~ubuntu-branches/ubuntu/natty/gtkboard/natty

« back to all changes in this revision

Viewing changes to .pc/debian-changes-0.11pre0+cvs.2003.11.02-2/src/knights.c

  • Committer: Bazaar Package Importer
  • Author(s): Barak A. Pearlmutter
  • Date: 2011-02-28 11:25:02 UTC
  • mto: This revision was merged to the branch mainline in revision 10.
  • Revision ID: james.westby@ubuntu.com-20110228112502-e9aah248wxelm7ao
Tags: 0.11pre0+cvs.2003.11.02-2
autotools tweaks, most notably -lSDL to supplement -lSDL_mixer

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  This file is a part of gtkboard, a board games system.
 
2
    Copyright (C) 2003, Arvind Narayanan <arvindn@users.sourceforge.net>
 
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 of the License, or
 
7
    (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
 
17
 
 
18
*/
 
19
#include <stdio.h>
 
20
#include <stdlib.h>
 
21
#include <string.h>
 
22
#include <assert.h>
 
23
 
 
24
#include "game.h"
 
25
#include "gdk/gdkkeysyms.h"
 
26
#include "../pixmaps/chess.xpm"
 
27
#include "../pixmaps/misc.xpm"
 
28
 
 
29
#define KNIGHTS_CELL_SIZE 54
 
30
#define KNIGHTS_NUM_PIECES 3
 
31
 
 
32
#define KNIGHTS_BOARD_WID 7
 
33
#define KNIGHTS_BOARD_HEIT 7
 
34
 
 
35
#define KNIGHTS_EMPTY 0
 
36
#define KNIGHTS_CLOSED 1
 
37
#define KNIGHTS_WN 2
 
38
#define KNIGHTS_BN 3
 
39
 
 
40
char knights_colors[] = {200, 200, 130, 0, 140, 0};
 
41
 
 
42
int knights_initpos [KNIGHTS_BOARD_WID*KNIGHTS_BOARD_HEIT] = 
 
43
{
 
44
        3 , 0 , 0 , 0 , 0 , 0 , 0 ,
 
45
        0 , 0 , 0 , 0 , 0 , 0 , 0 ,
 
46
        0 , 0 , 0 , 0 , 0 , 0 , 0 ,
 
47
        0 , 0 , 0 , 0 , 0 , 0 , 0 ,
 
48
        0 , 0 , 0 , 0 , 0 , 0 , 0 ,
 
49
        0 , 0 , 0 , 0 , 0 , 0 , 0 ,
 
50
        0 , 0 , 0 , 0 , 0 , 0 , 2 ,
 
51
};
 
52
 
 
53
 
 
54
char ** knights_pixmaps [] = 
 
55
{
 
56
        grey_square_54_xpm,
 
57
        chess_wn_54_xpm,
 
58
        chess_bn_54_xpm,
 
59
};
 
60
 
 
61
typedef struct
 
62
{
 
63
        int num_pauses;
 
64
}Knights_state;
 
65
 
 
66
static int knights_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **);
 
67
static int knights_getmove_kb (Pos *, int, byte ** , int **);
 
68
void knights_init ();
 
69
static ResultType knights_who_won (Pos *, Player, char **);
 
70
static ResultType knights_eval (Pos *, Player, float *eval);
 
71
static ResultType knights_eval_real (Pos *, Player, float *eval, gboolean);
 
72
static byte * knights_movegen (Pos *);
 
73
static void *knights_newstate (Pos *, byte *);
 
74
 
 
75
Game Knights = { KNIGHTS_CELL_SIZE, KNIGHTS_BOARD_WID, KNIGHTS_BOARD_HEIT, 
 
76
        KNIGHTS_NUM_PIECES, 
 
77
        knights_colors, knights_initpos, knights_pixmaps, "Balanced Joust", "Nimlike games",
 
78
        knights_init};
 
79
 
 
80
void knights_init ()
 
81
{
 
82
        game_getmove = knights_getmove;
 
83
        game_getmove_kb = knights_getmove_kb;
 
84
        game_who_won = knights_who_won;
 
85
        game_eval = knights_eval;
 
86
        game_movegen = knights_movegen;
 
87
        game_stateful = TRUE;
 
88
        game_state_size = sizeof (Knights_state);
 
89
        game_newstate = knights_newstate;
 
90
        game_draw_cell_boundaries = TRUE;
 
91
        game_file_label = FILERANK_LABEL_TYPE_ALPHA;
 
92
        game_rank_label = FILERANK_LABEL_TYPE_NUM | FILERANK_LABEL_DESC;
 
93
        game_doc_about_status = STATUS_COMPLETE;
 
94
        game_doc_rules = "Two players take turns in moving their respective knights on a 7x7 chessboard. Squares that have been visited are considered \"eaten\" and cannot be revisited. When the knights are attacking each other, the player to move can pass by hitting Space. If both players pass in the same position, the game is a draw. The goal is to be the last player to make a move.";
 
95
        game_doc_strategy = "As the game progresses, there will eventually appear a single square, which, if eaten, will partition the board into two, such that a knight cannot move from one part to the other. The player who eats this square is often at an advantage because they can choose which part to move to.";
 
96
}
 
97
 
 
98
static int incx[] = { -2, -2, -1, -1, 1, 1, 2, 2};
 
99
static int incy[] = { -1, 1, -2, 2, -2, 2, -1, 1};
 
100
 
 
101
static void *knights_newstate (Pos *pos, byte *move)
 
102
{
 
103
        static Knights_state state;
 
104
        if (!pos->state)
 
105
        {
 
106
                state.num_pauses = 0;
 
107
                return &state;
 
108
        }
 
109
        if (move[0] == -1)
 
110
                state.num_pauses = ((Knights_state *)pos->state)->num_pauses + 1;
 
111
        else state.num_pauses = 0;
 
112
        return &state;
 
113
}
 
114
 
 
115
static void get_cur_pos (byte *board, Player player, int *x, int *y)
 
116
{
 
117
        int i=0, j=0;
 
118
        for (i=0; i<board_wid; i++)
 
119
        for (j=0; j<board_heit; j++)
 
120
        {
 
121
                if ((player == WHITE && board [j * board_wid + i] == KNIGHTS_WN)
 
122
                        || (player == BLACK && board [j * board_wid + i] == KNIGHTS_BN))
 
123
                {
 
124
                        *x = i;
 
125
                        *y = j;
 
126
                        return;
 
127
                }
 
128
        }
 
129
}
 
130
 
 
131
ResultType knights_who_won (Pos *pos, Player player, char **commp)
 
132
{
 
133
        int i=0, j=0, k;
 
134
        float eval;
 
135
        ResultType result = knights_eval_real (pos, player, &eval, TRUE);
 
136
        if (result == RESULT_NOTYET)
 
137
                ;
 
138
        else if (result == RESULT_TIE) *commp = "Draw";
 
139
        else if (result == RESULT_WHITE) *commp = "White won";
 
140
        else if (result == RESULT_BLACK) *commp = "Black won";
 
141
        return result;
 
142
}
 
143
 
 
144
 
 
145
int knights_getmove_kb (Pos *pos, int key, byte ** movp, int **rmovp)
 
146
{
 
147
        int i, j, wx = 0, wy = 0, bx = 0, by = 0;
 
148
        static byte move[1] = {-1};
 
149
        if (key != GDK_p)
 
150
                return 0;
 
151
        for (i=0; i<board_wid; i++)
 
152
        for (j=0; j<board_heit; j++)
 
153
        {
 
154
                if (pos->board[j * board_wid + i] == KNIGHTS_WN)
 
155
                        wx = i, wy = j;
 
156
                if (pos->board[j * board_wid + i] == KNIGHTS_BN)
 
157
                        bx = i, by = j;
 
158
        }
 
159
        if (abs ((wx - bx) * (wy - by)) != 2)
 
160
                return -1;              
 
161
        *movp = move;
 
162
        return 1;
 
163
}
 
164
 
 
165
int knights_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player player, 
 
166
                byte **movp, int **rmovp)
 
167
{
 
168
        int curx = -1, cury = -1;
 
169
        static byte move[128];
 
170
        byte *mp = move;
 
171
        if (type != GTKBOARD_BUTTON_RELEASE)
 
172
                return 0;
 
173
        if (pos->board[y * board_wid + x] == (player == WHITE ? KNIGHTS_WN : KNIGHTS_BN))
 
174
                return 0;
 
175
        if (pos->board[y * board_wid + x] != KNIGHTS_EMPTY)
 
176
                return -1;
 
177
        get_cur_pos (pos->board, player, &curx, &cury);
 
178
        if (abs ((curx - x) * (cury - y)) != 2)
 
179
                return -1;
 
180
        *mp++ = x;
 
181
        *mp++ = y;
 
182
        *mp++ = (player == WHITE ? KNIGHTS_WN : KNIGHTS_BN);
 
183
        *mp++ = curx;
 
184
        *mp++ = cury;
 
185
        *mp++ = KNIGHTS_CLOSED;
 
186
        *mp++ = -1;
 
187
        *movp = move;
 
188
        return 1;
 
189
}
 
190
 
 
191
 
 
192
byte * knights_movegen (Pos *pos)
 
193
{
 
194
        int i, j, k;
 
195
        byte movbuf [64];
 
196
        byte *movlist, *movp = movbuf;
 
197
        Player player = pos->player;
 
198
        get_cur_pos (pos->board, player, &i, &j);
 
199
        for (k=0; k<8; k++)
 
200
        {
 
201
                int x = i + incx[k], y = j + incy[k];
 
202
                int val;
 
203
                if (!ISINBOARD (x, y)) continue;
 
204
                if ((val = pos->board[y * board_wid + x]) == KNIGHTS_EMPTY)
 
205
                {
 
206
                        *movp++ = i;
 
207
                        *movp++ = j;
 
208
                        *movp++ = KNIGHTS_CLOSED;
 
209
                        *movp++ = x;
 
210
                        *movp++ = y;
 
211
                        *movp++ = (player == WHITE ? KNIGHTS_WN : KNIGHTS_BN);
 
212
                        *movp++ = -1;
 
213
                }
 
214
                else if (val == KNIGHTS_WN || val == KNIGHTS_BN)
 
215
                {
 
216
                        *movp++ = -1;
 
217
                }
 
218
        }
 
219
        *movp++ = -2;
 
220
        movlist = (byte *) (malloc (movp - movbuf));
 
221
        memcpy (movlist, movbuf, (movp - movbuf));
 
222
        return movlist;
 
223
}
 
224
 
 
225
static gboolean eval_disconnected (byte *theboard)
 
226
{
 
227
        byte board[KNIGHTS_BOARD_WID * KNIGHTS_BOARD_HEIT];
 
228
        int stack[KNIGHTS_BOARD_WID * KNIGHTS_BOARD_HEIT];
 
229
        int stack_top = 0;
 
230
        int i, curx, cury, x, y;
 
231
 
 
232
        for (i=0; i<board_wid * board_heit; i++)
 
233
                board[i] = theboard[i];
 
234
 
 
235
        get_cur_pos (board, WHITE, &curx, &cury);
 
236
        
 
237
        stack[stack_top++] = cury * board_wid + curx;
 
238
        while (stack_top > 0)
 
239
        {
 
240
                stack_top--;
 
241
                curx = stack[stack_top] % board_wid;
 
242
                cury = stack[stack_top] / board_wid;
 
243
                for (i=0; i<8; i++)
 
244
                {
 
245
                        x = curx + incx[i];
 
246
                        y = cury + incy[i];
 
247
                        if (!ISINBOARD (x, y)) continue;
 
248
                        if (board[y * board_wid + x] == KNIGHTS_BN)
 
249
                                return FALSE;
 
250
                        if (board[y * board_wid + x] != KNIGHTS_EMPTY)
 
251
                                continue;
 
252
                        board[y * board_wid + x] = KNIGHTS_CLOSED;
 
253
                        stack[stack_top++] = y * board_wid + x;
 
254
                }
 
255
        }
 
256
        return TRUE;
 
257
}
 
258
 
 
259
// exhaustive DFS to solve the position exactly
 
260
static int eval_max_path_len (byte *theboard, Player player)
 
261
{
 
262
        byte board[KNIGHTS_BOARD_WID * KNIGHTS_BOARD_HEIT];
 
263
        int stack [KNIGHTS_BOARD_WID * KNIGHTS_BOARD_HEIT];
 
264
        int current [KNIGHTS_BOARD_WID * KNIGHTS_BOARD_HEIT];
 
265
        int stack_top = 0;
 
266
        int i, curx, cury, x, y;
 
267
        int max_len = 0;
 
268
 
 
269
        for (i=0; i<board_wid * board_heit; i++)
 
270
                board[i] = theboard[i];
 
271
 
 
272
        get_cur_pos (board, player, &curx, &cury);
 
273
        
 
274
        current[stack_top] = 0;
 
275
        stack[stack_top] = cury * board_wid + curx;
 
276
 
 
277
        while (stack_top >= 0)
 
278
        {
 
279
                if (stack_top > max_len)
 
280
                        max_len = stack_top;
 
281
                i = current[stack_top]++;
 
282
                if (i == 8)
 
283
                {
 
284
                        stack_top--;
 
285
                        continue;
 
286
                }
 
287
                curx = stack[stack_top] % board_wid;
 
288
                cury = stack[stack_top] / board_wid;
 
289
                x = curx + incx[i];
 
290
                y = cury + incy[i];
 
291
                if (!ISINBOARD (x, y)) continue;
 
292
                if (board[y * board_wid + x] != KNIGHTS_EMPTY)
 
293
                        continue;
 
294
                board[y * board_wid + x] = KNIGHTS_CLOSED;
 
295
                stack_top++;
 
296
                current[stack_top] = 0;
 
297
                stack[stack_top] = y * board_wid + x;
 
298
        }
 
299
        return max_len;
 
300
}
 
301
 
 
302
// We may want to continue the game even when a result is apparent. The
 
303
// parameter strict is for this. who_won() sets it to TRUE and eval() to FALSE.
 
304
static ResultType knights_eval_real (Pos *pos, Player player, float *eval, gboolean strict)
 
305
{
 
306
        int i, j, k;
 
307
        int wcnt = 0, bcnt = 0;
 
308
        static int disconn_cnt [2 * KNIGHTS_BOARD_WID * KNIGHTS_BOARD_HEIT] = {0};
 
309
        static int total_cnt [2 * KNIGHTS_BOARD_WID * KNIGHTS_BOARD_HEIT] = {0};
 
310
 
 
311
        if (pos->state && ((Knights_state *)pos->state)->num_pauses >= 2)
 
312
        {
 
313
                *eval = 0;
 
314
                return RESULT_TIE;
 
315
        }
 
316
        
 
317
        if (!strict && eval_disconnected (pos->board))
 
318
        {
 
319
                int wlen = 0, blen = 0;
 
320
                disconn_cnt [pos->num_moves]++;
 
321
                total_cnt[pos->num_moves]++;
 
322
                wlen = eval_max_path_len (pos->board, WHITE);
 
323
                blen = eval_max_path_len (pos->board, BLACK);
 
324
                *eval = 2 * (wlen - blen) + (player == WHITE ? -1 : 1);
 
325
                if (wlen > blen) return RESULT_WHITE;
 
326
                else if (wlen < blen) return RESULT_BLACK;
 
327
                else return player == WHITE ? RESULT_BLACK : RESULT_WHITE;
 
328
        }
 
329
 
 
330
        total_cnt[pos->num_moves]++;
 
331
//      if (total_cnt[pos->num_moves] % 10000 == 0) printf ("Ply: %d;\t total: %d;\t disc: %d\n", pos->num_moves, total_cnt[pos->num_moves], disconn_cnt[pos->num_moves]);
 
332
 
 
333
        get_cur_pos (pos->board, WHITE, &i, &j);
 
334
        for (k=0; k<8; k++)
 
335
        {
 
336
                int x = i + incx[k], y = j + incy[k];
 
337
                if (!ISINBOARD (x, y)) continue;
 
338
                if (pos->board[y * board_wid + x] == KNIGHTS_EMPTY)
 
339
                        wcnt++;
 
340
        }
 
341
 
 
342
        get_cur_pos (pos->board, BLACK, &i, &j);
 
343
        for (k=0; k<8; k++)
 
344
        {
 
345
                int x = i + incx[k], y = j + incy[k];
 
346
                if (!ISINBOARD (x, y)) continue;
 
347
                if (pos->board[y * board_wid + x] == KNIGHTS_EMPTY)
 
348
                        bcnt++;
 
349
        }
 
350
        *eval = wcnt - bcnt;
 
351
        if (player == WHITE && wcnt == 0)
 
352
        {
 
353
                if (bcnt == 0) *eval -= 1;
 
354
                *eval *= GAME_EVAL_INFTY;
 
355
                return RESULT_BLACK;
 
356
        }
 
357
        if (player == BLACK && bcnt == 0)
 
358
        {
 
359
                if (wcnt == 0) *eval += 1;
 
360
                *eval *= GAME_EVAL_INFTY;
 
361
                return RESULT_WHITE;
 
362
        }
 
363
        return RESULT_NOTYET;
 
364
}
 
365
 
 
366
ResultType knights_eval (Pos *pos, Player player, float *eval)
 
367
{
 
368
        return knights_eval_real (pos, player, eval, FALSE);
 
369
}