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