1 /* The Ace of Penguins - mastermind.c
2 Copyright (C) 1998, 2001 DJ Delorie
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <stdlib.h>
19 #include <time.h>
20 #include <math.h>
21 #include "cards.h"
22
23 static Picture *splash, *youwin, *youlose;
24
25 static Picture *colors[6], *bighole, *cover;
26 static Picture *black, *white, *smallhole;
27
28 /* The "palette" */
29 static int px, py, pdy;
30 /* The guesses */
31 static int gx, gy, gdx, gdy;
32 /* The ranks */
33 static int rx, ry, rdx, rdy;
34 /* The solution */
35 static int sx, sy, sdx;
36
37 /* Sizes of the images */
38 #define BSZ 16
39 #define SSZ 10
40 #define WGAP 30
41
42 #define MOVES 10
43
44 static Picture *guesses[MOVES][4];
45 static Picture *ranks[MOVES][4];
46 static Picture *solution[4];
47
48 extern int table_width, table_height;
49
50 static int active_row, solution_shown;
51
52 static int
redraw_row(int row)53 redraw_row(int row)
54 {
55 int x;
56 for (x=0; x<4; x++)
57 {
58 if (guesses[row][x])
59 put_picture(guesses[row][x], gx+x*gdx, gy+row*gdy, 0, 0, BSZ, BSZ);
60 if (ranks[row][x])
61 put_picture(ranks[row][x], rx+x*rdx, ry+row*rdy, 0, 0, SSZ, SSZ);
62 }
63 }
64
65 static void
set_active_row(int row)66 set_active_row(int row)
67 {
68 int x;
69 active_row = row;
70 for (x=0; x<4; x++)
71 guesses[active_row][x] = bighole;
72 redraw_row(active_row);
73 py = (gy+active_row*gdy)-(BSZ+1)*5/2;
74 if (py < CARD_MARGIN)
75 py = CARD_MARGIN;
76 if (py > table_height-CARD_MARGIN-6*BSZ-5)
77 py = table_height-CARD_MARGIN-6*BSZ-5;
78 invalidate(0, 0, px+BSZ, table_height);
79 }
80
81 static void
start_again()82 start_again()
83 {
84 int x, y;
85 for (x=0; x<4; x++)
86 {
87 for (y=0; y<MOVES; y++)
88 {
89 guesses[y][x] = 0;
90 ranks[y][x] = 0;
91 }
92 solution[x] = colors[rand()%6];
93 }
94 set_active_row(0);
95 solution_shown = 0;
96 }
97
98 static void
init()99 init()
100 {
101 start_again();
102 set_centered_pic(splash);
103 }
104
105 static void
show_solution()106 show_solution()
107 {
108 solution_shown = 1;
109 invalidate(0, 0, table_width, table_height);
110 }
111
112 static void
redraw()113 redraw()
114 {
115 int x, y;
116 for (y=0; y<MOVES; y++)
117 redraw_row(y);
118 for (x=0; x<4; x++)
119 if (solution_shown)
120 put_picture(solution[x], sx+x*sdx, sy, 0, 0, BSZ, BSZ);
121 else
122 put_picture(cover, sx+x*sdx, sy, 0, 0, BSZ, BSZ);
123 if (! solution_shown)
124 for (y=0; y<6; y++)
125 put_picture(colors[y], px, py+y*pdy, 0, 0, BSZ, BSZ);
126 }
127
128 static void
show_rank(int row)129 show_rank(int row)
130 {
131 int x, y;
132 int b=0, w=0, ri=0;
133 int gs[4], ss[4];
134 for (x=0; x<4; x++)
135 gs[x] = ss[x] = 0;
136 for (x=0; x<4; x++)
137 if (guesses[active_row][x] == solution[x])
138 {
139 ranks[active_row][ri++] = black;
140 b++;
141 gs[x] = ss[x] = 1;
142 }
143 for (x=0; x<4; x++)
144 if (! gs[x])
145 for (y=0; y<4; y++)
146 if (! ss[y])
147 if (guesses[active_row][x] == solution[y])
148 {
149 ranks[active_row][ri++] = white;
150 w++;
151 gs[x] = 1;
152 ss[y] = 1;
153 break;
154 }
155 while (ri<4)
156 ranks[active_row][ri++] = smallhole;
157 if (b == 4)
158 show_solution();
159 redraw_row(active_row);
160 }
161
162 static void
check_row()163 check_row()
164 {
165 int x;
166 for (x=0; x<4; x++)
167 if (!guesses[active_row][x] || guesses[active_row][x] == bighole)
168 return;
169 show_rank(active_row);
170 if (!solution_shown)
171 {
172 if (active_row == (MOVES-1))
173 {
174 show_solution();
175 set_centered_pic(youlose);
176 }
177 else
178 set_active_row(active_row+1);
179 }
180 }
181
182 static void
key_color(int c)183 key_color(int c)
184 {
185 int x;
186 for (x=0; x<4; x++)
187 if (guesses[active_row][x] == bighole)
188 {
189 guesses[active_row][x] = colors[c];
190 redraw_row(active_row);
191 return;
192 }
193 }
194
195 extern char mastermind_help[];
196
197 static void
key(int k,int x,int y)198 key(int k, int x, int y)
199 {
200 int i;
201 Picture *p = get_centered_pic();
202 set_centered_pic(0);
203 if (p == splash)
204 return;
205 if (p == youwin || p == youlose || solution_shown)
206 {
207 start_again();
208 invalidate(0, 0, table_width, table_height);
209 return;
210 }
211 if (k == 3 || k == 27 || k == 'q')
212 exit(0);
213 if (k == KEY_F(2))
214 {
215 start_again();
216 invalidate(0, 0, table_width, table_height);
217 return;
218 }
219 if (k == KEY_F(1) || k == 'h')
220 {
221 set_centered_pic(0);
222 help("mastermind.html", mastermind_help);
223 return;
224 }
225 if (k == 'r') key_color(0);
226 if (k == 'o') key_color(1);
227 if (k == 'y') key_color(2);
228 if (k == 'g') key_color(3);
229 if (k == 'b') key_color(4);
230 if (k == 'p') key_color(5);
231 if (k == '\r' || k == '\n')
232 check_row();
233 }
234
235 static Picture *color_dragged=0;
236 static int drag_dx, drag_dy, drag_ox, drag_oy;
237
238 static void
click(int x,int y,int b)239 click(int x, int y, int b)
240 {
241 Picture *p = get_centered_pic();
242 set_centered_pic(0);
243 if (p == splash)
244 return;
245 if (p == youwin || p == youlose || solution_shown)
246 {
247 start_again();
248 invalidate(0, 0, table_width, table_height);
249 return;
250 }
251 drag_ox = x;
252 drag_oy = y;
253 if (x >= px && x < px+BSZ && y >= py && y < py+6*pdy)
254 {
255 color_dragged = colors[(y-py)/pdy];
256 drag_dx = x - px;
257 drag_dy = y - (((int)((y-py)/pdy))*pdy+py);
258 return;
259 }
260 if (x >= gx && x < gx+4*gdx && y < gy+BSZ && y > gy+(MOVES-1)*gdy)
261 {
262 int ty;
263 ty = ((gy+BSZ)-y)/(-gdy);
264 color_dragged = guesses[ty][(x-gx)/gdx];
265 if (color_dragged == bighole)
266 color_dragged = 0;
267 drag_dx = x - (((int)((x-gx)/gdx))*gdx+gx);
268 ty = gy+ty*gdy;
269 drag_dy = y - ty;
270 return;
271 }
272 color_dragged = 0;
273 if (x > rx-WGAP/2)
274 check_row();
275 }
276
277 static void
drag(int x,int y,int b)278 drag(int x, int y, int b)
279 {
280 if (color_dragged == 0) return;
281 invalidate_exposure(drag_ox-drag_dx, drag_oy-drag_dy, BSZ, BSZ,
282 x-drag_dx, y-drag_oy, BSZ, BSZ);
283 put_picture(color_dragged, x-drag_dx, y-drag_dy, 0, 0, BSZ, BSZ);
284 drag_ox = x;
285 drag_oy = y;
286 }
287
288 static void
drop(int x,int y,int b)289 drop(int x, int y, int b)
290 {
291 if (color_dragged == 0) return;
292 invalidate(drag_ox-drag_dx, drag_oy-drag_dy, BSZ, BSZ);
293 x = x-drag_dx + BSZ/2;
294 y = y-drag_dy + BSZ/2;
295
296 if (x >= gx && x < gx+4*gdx
297 && y >= gy+active_row*gdy && y < gy+active_row*gdy+BSZ)
298 {
299 int i = (x-gx)/gdx;
300 guesses[active_row][i] = color_dragged;
301 redraw_row(active_row);
302 }
303 color_dragged = 0;
304 }
305
306 static FunctionMapping fmap[] = {
307 { "click", (void *)click },
308 { "drag", (void *)drag },
309 { "drop", (void *)drop },
310 { "init", (void *)init },
311 { "key", (void *)key },
312 { "redraw", (void *)redraw },
313 { 0, 0 }
314 };
315
316 int
main(int argc,char ** argv)317 main(int argc, char **argv)
318 {
319 register_imagelib(appimglib_imagelib);
320 init_ace(argc, argv, fmap);
321
322 splash = get_picture("mastermind");
323 youwin = get_picture("youwin");
324 youlose = get_picture("youlose");
325
326 colors[0] = get_picture("mastermind-r");
327 colors[1] = get_picture("mastermind-o");
328 colors[2] = get_picture("mastermind-y");
329 colors[3] = get_picture("mastermind-g");
330 colors[4] = get_picture("mastermind-b");
331 colors[5] = get_picture("mastermind-p");
332 bighole = get_picture("mastermind-eb");
333 cover = get_picture("mastermind-c");
334
335 black = get_picture("mastermind-k");
336 white = get_picture("mastermind-w");
337 smallhole = get_picture("mastermind-e");
338
339 px = WGAP;
340 py = CARD_MARGIN;
341 pdy = BSZ + 1;
342
343 sx = 2*WGAP+BSZ;
344 sy = CARD_MARGIN;
345 sdx = BSZ + 3;
346
347 gdx = BSZ + 3;
348 gdy = -(BSZ + 3);
349 gx = sx;
350 gy = 2*CARD_MARGIN+BSZ - (MOVES-1)*gdy;
351
352 rx = gx + 3*gdx + BSZ + WGAP;
353 ry = gy + (BSZ-SSZ)/2;
354 rdx = SSZ+3;
355 rdy = gdy;
356
357 table_width = rx + 3*rdx + SSZ + WGAP;
358 table_height = gy + BSZ + CARD_MARGIN;
359
360 init_table(table_width, table_height);
361 table_loop();
362 }
363