comparison board.c @ 0:a9a7ad180c3b version-1

Initial revision
author Guido Berhoerster <guido+rantaiwarna@berhoerster.name>
date Sat, 15 Mar 2014 18:41:03 +0100
parents
children aec74ae4d6e5
comparison
equal deleted inserted replaced
-1:000000000000 0:a9a7ad180c3b
1 /*
2 * Copyright (C) 2014 Guido Berhoerster <guido+rantaiwarna@berhoerster.name>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #define _XOPEN_SOURCE 600
25
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <curses.h> /* for OK, ERR */
29
30 #include "board.h"
31 #include "compat.h"
32 #include "util.h"
33
34 struct stack_element {
35 struct stack_element *next;
36 int x;
37 int y;
38 };
39
40 struct board_ctx *
41 board_create(int height, int width, short colors)
42 {
43 struct board_ctx *board;
44
45 board = rantaiwarna_malloc(sizeof (struct board_ctx));
46 board->elements = rantaiwarna_calloc((size_t)(width * height),
47 sizeof (short));
48 board->seed = (uint32_t)getpid();
49 board->height = height;
50 board->width = width;
51 board->colors = colors;
52 board->status = GAME_OVER;
53 board->score = 0;
54 if (board_generate(board) == ERR) {
55 board_free(board);
56 return (NULL);
57 }
58
59 return (board);
60 }
61
62 void
63 board_free(struct board_ctx *board)
64 {
65 free(board->elements);
66 free(board);
67 }
68
69 int
70 board_check_status(struct board_ctx *board)
71 {
72 int status = GAME_OVER | GAME_OVER_CLEARED;
73 int y;
74 int x;
75
76 for (y = board->height - 1; y >= 0; y--) {
77 for (x = 0; x < board->width; x++) {
78 if (board->elements[y * board->width + x] != 0) {
79 status &= ~GAME_OVER_CLEARED;
80 if (((y - 1 >= 0) &&
81 (board->elements[y * board->width + x] ==
82 board->elements[(y - 1) * board->width +
83 x])) ||
84 ((x + 1 < board->width) &&
85 (board->elements[y * board->width + x] ==
86 (board->elements[y * board->width + x +
87 1])))) {
88 status &= ~GAME_OVER;
89 goto out;
90 }
91 }
92 }
93 }
94
95 out:
96 board->status = status;
97 return (status);
98 }
99
100 int
101 board_generate(struct board_ctx *board)
102 {
103 int i;
104 int j;
105
106 /* make up to 1000 attempts to create a board that is playable */
107 for (i = 0; i < 1000; i++) {
108 for (j = 0; j < board->width * board->height; j++) {
109 board->elements[j] =
110 (short)(rantaiwarna_rand(&board->seed) %
111 board->colors) + 1;
112 }
113 if (board_check_status(board) & GAME_OVER) {
114 return (ERR);
115 }
116 }
117
118 board->score = 0;
119
120 return (OK);
121 }
122
123 int
124 board_compact(struct board_ctx *board)
125 {
126 int changes = 0;
127 int x;
128 int y;
129 int top;
130 int left;
131
132 /* close vertical gaps iby moving elements down */
133 for (x = 0; x < board->width; x++) {
134 for (y = top = board->height - 1; y >= 0; y--) {
135 if (board->elements[y * board->width + x] != 0) {
136 board->elements[top * board->width + x] =
137 board->elements[y * board->width + x];
138 top--;
139 changes++;
140 }
141 }
142 for (y = top; y >= 0; y--) {
143 board->elements[y * board->width + x] = 0;
144 }
145 }
146
147 /* close column gaps by moving columns to the left */
148 for (x = left = 0; x < board->width; x++) {
149 if (board->elements[(board->height - 1) * board->width + x] !=
150 0) {
151 if (x > left) {
152 for (y = 0; y < board->height; y++) {
153 board->elements[y * board->width +
154 left] = board->elements[y *
155 board->width + x];
156 }
157 changes++;
158 }
159 left++;
160 }
161 }
162 for (x = left; x < board->width; x++) {
163 for (y = 0; y < board->height; y++) {
164 board->elements[y * board->width + x] = 0;
165 }
166 }
167
168 return (changes);
169 }
170
171 int
172 board_remove_elements(struct board_ctx *board, int start_y, int start_x)
173 {
174 int removed = 0;
175 int color;
176 int x;
177 int y;
178 int west;
179 int east;
180 int n = 0;
181 int i;
182 int save_x;
183 int save_y;
184 struct stack_element *stack_start;
185 struct stack_element *stack_tmp;
186 struct stack_element *stack_new;
187
188 color = board->elements[start_y * board->width + start_x];
189 if (color == 0) {
190 return (0);
191 }
192
193 stack_new = rantaiwarna_malloc(sizeof (struct stack_element));
194 stack_new->next = NULL;
195 stack_new->y = start_y;
196 stack_new->x = start_x;
197 stack_start = stack_new;
198
199 while (stack_start != NULL) {
200 x = stack_start->x;
201 y = stack_start->y;
202 stack_tmp = stack_start;
203 stack_start = stack_start->next;
204 free(stack_tmp);
205
206 if (board->elements[y * board->width + x] != color) {
207 continue;
208 }
209
210 for (west = x; (west - 1 >= 0) &&
211 (board->elements[y * board->width + west - 1] == color);
212 west--);
213 for (east = x; (east + 1 < board->width) &&
214 (board->elements[y * board->width + east + 1] == color);
215 east++);
216 for (i = west; i <= east; i++) {
217 /*
218 * only really start removing elements if there are
219 * more than two adjacent elements of the same color
220 */
221 n++;
222 if (n < 2) {
223 save_x = i;
224 save_y = y;
225 } else {
226 if (n == 2) {
227 board->elements[save_y * board->width +
228 save_x] = 0;
229 removed++;
230 }
231 board->elements[y * board->width + i] = 0;
232 removed++;
233 }
234
235 if ((y - 1 >= 0) &&
236 (board->elements[(y - 1) * board->width + i] ==
237 color)) {
238 stack_new = rantaiwarna_malloc(
239 sizeof (struct stack_element));
240 stack_new->next = stack_start;
241 stack_new->y = y - 1;
242 stack_new->x = i;
243 stack_start = stack_new;
244 }
245 if ((y + 1 < board->height) &&
246 (board->elements[(y + 1) * board->width + i] ==
247 color)) {
248 stack_new = rantaiwarna_malloc(
249 sizeof (struct stack_element));
250 stack_new->next = stack_start;
251 stack_new->y = y + 1;
252 stack_new->x = i;
253 stack_start = stack_new;
254 }
255 }
256 }
257 if (removed > 0) {
258 board_compact(board);
259 board->score += (removed - 1) * (removed - 1);
260 board_check_status(board);
261 if (board->status & GAME_OVER) {
262 if (board->status & GAME_OVER_CLEARED) {
263 board->score += 1000;
264 }
265 }
266 }
267
268 return (removed);
269 }