OpenCores
URL https://opencores.org/ocsvn/connect-6/connect-6/trunk

Subversion Repositories connect-6

[/] [connect-6/] [trunk/] [CONNECTK/] [connectk-2.0/] [src/] [ai/] [sequences.c] - Blame information for rev 3

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 sumanta.ch
 
2
/*
3
 
4
connectk -- a program to play the connect-k family of games
5
Copyright (C) 2007 Jeff Deitch
6
 
7
This program is free software; you can redistribute it and/or
8
modify it under the terms of the GNU General Public License
9
as published by the Free Software Foundation; either version 2
10
of the License, or (at your option) any later version.
11
 
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
GNU General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
 
21
*/
22
 
23
#include "config.h"
24
#include <glib.h>
25
#include <string.h>
26
#include "../shared.h"
27
 
28
int utility_upper_bound;
29
 
30
/* arrays for holding the utility and threat values for each window */
31
int white_window_sequence_array[MAX_BOARD_SIZE][MAX_BOARD_SIZE][4];
32
int black_window_sequence_array[MAX_BOARD_SIZE][MAX_BOARD_SIZE][4];
33
int white_window_threat_array[MAX_BOARD_SIZE][MAX_BOARD_SIZE][4];
34
int black_window_threat_array[MAX_BOARD_SIZE][MAX_BOARD_SIZE][4];
35
 
36
/* arrays for holding the marks used for counting threats */
37
int whites_marks[MAX_BOARD_SIZE][MAX_BOARD_SIZE];
38
int blacks_marks[MAX_BOARD_SIZE][MAX_BOARD_SIZE];
39
 
40
/* the sum of all the windows' values for threats and utility */
41
int white_window_sequence_count;
42
int black_window_sequence_count;
43
int white_threat_count;
44
int black_threat_count;
45
 
46
/* the max sequence on a board */
47
int max_white_sequence;
48
int max_black_sequence;
49
 
50
/* Returns an integer to identify the window */
51
static int window_id(BCOORD x, BCOORD y, int i)
52
{
53
        return x * board_size * 4 + y * 4 + i + 1;
54
}
55
 
56
static void clear_all()
57
{
58
        /* clears all values in the matricies that hold the window scores and threat info */
59
        int x, y, d;
60
        for (x = 0; x < board_size; x++) {
61
                for (y = 0; y < board_size; y++) {
62
 
63
                        blacks_marks[x][y] = 0;
64
                        whites_marks[x][y] = 0;
65
 
66
                        for (d = 0; d < 4; d++) {
67
                                white_window_sequence_array[x][y][d] = 0;
68
                                black_window_sequence_array[x][y][d] = 0;
69
                                white_window_threat_array[x][y][d] = 0;
70
                                black_window_threat_array[x][y][d] = 0;
71
                        }
72
                }
73
        }
74
 
75
        white_window_sequence_count = 0;
76
        black_window_sequence_count = 0;
77
        white_threat_count = 0;
78
        black_threat_count = 0;
79
 
80
        max_black_sequence = 0;
81
        max_white_sequence = 0;
82
}
83
 
84
/* A utility function of a particular window for a given player */
85
static void window_sequence(const Board *b, BCOORD x, BCOORD y, int i, PIECE player)
86
{
87
        int sequence, count_sequence, count_threat, dx, dy, ddx, ddy, j, len;
88
        int ddxs[] = {1, 0, 1,  1};
89
        int ddys[] = {0, 1, 1, -1};
90
        int to_mark[MAX_CONNECT_K];
91
 
92
        ddx = ddxs[i];
93
        ddy = ddys[i];
94
 
95
        len = 0;
96
        count_sequence = 0;
97
        count_threat = 0;
98
        sequence = 0;
99
 
100
        if (player == PIECE_WHITE) {
101
                // We are recalculating this window's threat level.
102
                // Start be taking this window's previous threat out of the sum
103
                // and reset it to 0.
104
                white_threat_count -= white_window_threat_array[x][y][i];
105
                white_window_threat_array[x][y][i] = 0;
106
 
107
                // Do the same for the sequence count.
108
                white_window_sequence_count -= white_window_sequence_array[x][y][i];
109
                white_window_sequence_array[x][y][i] = 0;
110
 
111
                // step through the window.
112
                for (dx = 0, dy = 0; dx < connect_k && dy < (int)connect_k; dx += ddx, dy += ddy) {
113
                        if (x + dx < 0 || y + dy < 0 || x + dx >= board_size || y + dy >= board_size) {
114
                                break;
115
                        }
116
                        // If this window was the one that marked this spot, unmark it so we can recheck.
117
                        if (whites_marks[x + dx][y + dy] == window_id(x, y, i)) {
118
                                whites_marks[x + dx][y + dy] = 0;
119
                        }
120
 
121
                        if (piece_at(b, x + dx, y + dy) == PIECE_NONE) {
122
                                count_sequence++;
123
                                if (whites_marks[x + dx][y + dy] == 0) {
124
                                        count_threat++;
125
                                        to_mark[len++] = x + dx;
126
                                        to_mark[len++] = y + dy;
127
                                }
128
                        } else if (piece_at(b, x + dx, y + dy) == player) {
129
                                count_sequence++;
130
                                count_threat++;
131
                                sequence++;
132
                        }
133
                }
134
 
135
                if (count_threat == connect_k) {
136
                        /* if this is a threat, update the threat array */
137
                        if (sequence >= (connect_k - place_p)) {
138
                                for (j = 0; j < len; j+=2) {
139
                                        whites_marks[to_mark[j]][to_mark[j+1]] = window_id(x, y, i);
140
                                }
141
                                white_window_threat_array[x][y][i] = 1;
142
                                white_threat_count += 1;
143
                        }
144
                }
145
 
146
                if (count_sequence == connect_k) {
147
 
148
                        /* if this is the max sequence of the board, update the max_sequence value */
149
                        if (sequence > max_white_sequence) {
150
                                max_white_sequence = sequence;
151
                        }
152
 
153
                        /* if the sequence is greater than connect_k - place_p, set it equal to connect_k - place_p.
154
                        This prevents it from giving a sequence of 5 a higher score than a sequence of 4 in the default game.  */
155
                        if (sequence > (connect_k - place_p)) {
156
                                sequence = (connect_k - place_p);
157
                        }
158
 
159
                        /* update the utility array values */
160
                        white_window_sequence_array[x][y][i] = sequence * sequence;
161
                        white_window_sequence_count += white_window_sequence_array[x][y][i];
162
                }
163
 
164
                /* Do it all again if we are black.  There must be a better way to do this */
165
        } else if (player == PIECE_BLACK) {
166
                // We are recalculating this window's threat level.
167
                // Start be taking this window's previous threat out of the sum
168
                // and reset it to 0.
169
                black_threat_count -= black_window_threat_array[x][y][i];
170
                black_window_threat_array[x][y][i] = 0;
171
 
172
                // Do the same for the sequence count.
173
                black_window_sequence_count -= black_window_sequence_array[x][y][i];
174
                black_window_sequence_array[x][y][i] = 0;
175
 
176
                // step through the window.
177
                for (dx = 0, dy = 0; dx < connect_k && dy < (int)connect_k; dx += ddx, dy += ddy) {
178
                        if (x + dx < 0 || y + dy < 0 || x + dx >= board_size || y + dy >= board_size) {
179
                                break;
180
                        }
181
                        // If this window was the one that marked this spot, unmark it so we can recheck.
182
                        if (blacks_marks[x + dx][y + dy] == window_id(x, y, i)) {
183
                                blacks_marks[x + dx][y + dy] = 0;
184
                        }
185
 
186
                        if (piece_at(b, x + dx, y + dy) == PIECE_NONE) {
187
                                count_sequence++;
188
                                if (blacks_marks[x + dx][y + dy] == 0) {
189
                                        count_threat++;
190
                                        to_mark[len++] = x + dx;
191
                                        to_mark[len++] = y + dy;
192
                                }
193
                        } else if (piece_at(b, x + dx, y + dy) == player) {
194
                                count_sequence++;
195
                                count_threat++;
196
                                sequence++;
197
                        }
198
                }
199
 
200
                if (count_threat == connect_k) {
201
                        /* if this is a threat, update the threat array */
202
                        if (sequence >= (connect_k - place_p)) {
203
                                for (j = 0; j < len; j+=2) {
204
                                        blacks_marks[to_mark[j]][to_mark[j+1]] = window_id(x, y, i);
205
                                }
206
                                black_window_threat_array[x][y][i] = 1;
207
                                black_threat_count += 1;
208
                        }
209
                }
210
 
211
                if (count_sequence == connect_k) {
212
 
213
                        /* if this is the max sequence of the board, update the max_sequence value */
214
                        if (sequence > max_black_sequence) {
215
                                max_black_sequence = sequence;
216
                        }
217
 
218
                        /* if the sequence is greater than connect_k - place_p, set it equal to connect_k - place_p.
219
                        This prevents it from giving a sequence of 5 a higher score than a sequence of 4 in the default game.  */
220
                        if (sequence > (connect_k - place_p)) {
221
                                sequence = (connect_k - place_p);
222
                        }
223
 
224
                        /* update the utility array values */
225
                        black_window_sequence_array[x][y][i] = sequence * sequence;
226
                        black_window_sequence_count += black_window_sequence_array[x][y][i];
227
                }
228
        } else {
229
                g_debug("error in window_sequence(), unknown board turn.");
230
        }
231
}
232
 
233
int board_utility(const Board *b, PIECE player)
234
/* This returns the utility value of the board
235
It looks for a few things, first if the currently player is on their way to winning
236
(have enough moves left in given turn to win) it returns a high utility
237
second if there is a threat on this board from the other player, it gives a very low utility.
238
Third, if the board is going to force a win for the player, it gives a high utility.
239
If none of these are true, it adds up the utilities of all the windows and subtracts
240
the sum of the utilities of the other player times the defensive constant */
241
{
242
 
243
        int utility = 0;
244
        utility_upper_bound = 2 * board_size * board_size * connect_k * connect_k;
245
 
246
        if (b->turn == PIECE_WHITE) {
247
                if ((connect_k - max_white_sequence) <= (b->moves_left)) {
248
                        utility = utility_upper_bound;
249
                } else if (black_threat_count) {
250
                        utility = -utility_upper_bound - black_threat_count;
251
                } else if (white_threat_count > place_p) {
252
                        utility = utility_upper_bound - 1;
253
                } else {
254
                        utility = white_window_sequence_count - black_window_sequence_count;
255
                }
256
        } else if (b->turn == PIECE_BLACK) {
257
                if ((connect_k - max_black_sequence) <= (b->moves_left)) {
258
                        utility = utility_upper_bound;
259
                } else if (white_threat_count) {
260
                        utility = -utility_upper_bound - white_threat_count;
261
                } else if (black_threat_count > place_p) {
262
                        utility = utility_upper_bound - 1;
263
                } else {
264
                        utility = black_window_sequence_count - white_window_sequence_count;
265
                }
266
        } else {
267
                g_debug("error in board_utility(), unknown board turn.");
268
        }
269
 
270
        if (b->turn != player)
271
                utility = -utility;
272
 
273
        return utility;
274
}
275
 
276
int board_update(const Board *b, PIECE player)
277
{
278
        /* scans the entire board and returns its utility */
279
        BCOORD x, y;
280
        int i;
281
 
282
        clear_all();
283
 
284
        for (y = 0; y < board_size; y++) {
285
                for (x = 0; x < board_size; x++) {
286
                        for (i = 0; i < 4; i++) {
287
                                window_sequence(b, x, y, i, PIECE_WHITE);
288
                                window_sequence(b, x, y, i, PIECE_BLACK);
289
                        }
290
                }
291
        }
292
 
293
        return board_utility(b, player);
294
}
295
 
296
int incremental_update(const Board *b, BCOORD x, BCOORD y, PIECE player)
297
/* only scans the windows that have been impacted by a new piece and returns the board's utility */
298
{
299
        int dx, dy, ddx, ddy, i, counter;
300
        int ddxs[] = {1, 0, 1,  1};
301
        int ddys[] = {0, 1, 1, -1};
302
 
303
        max_black_sequence = 0;
304
        max_white_sequence = 0;
305
 
306
        for (i = 0; i < 4; i++) {
307
 
308
                ddx = ddxs[i];
309
                ddy = ddys[i];
310
 
311
                for (counter = 0, dx = ddx * -connect_k, dy = ddy * -connect_k;
312
                     counter < connect_k + 2;
313
                     counter ++, dx += ddx, dy += ddy) {
314
                        if (x + dx < 0 || y + dy < 0 || x + dx >= board_size || y + dy >= board_size) {
315
                                continue;
316
                        }
317
 
318
                        window_sequence(b, x + dx, y + dy, i, PIECE_WHITE);
319
                        window_sequence(b, x + dx, y + dy, i, PIECE_BLACK);
320
                }
321
        }
322
 
323
        return board_utility(b, player);
324
}
325
 
326
AIMoves *move_utilities(const Board *b)
327
{
328
        /* creates a list of possible moves based on the sequences utility function */
329
        AIMoves *moves = aimoves_new();
330
        AIMove move;
331
 
332
        moves->utility = board_update(b, b->turn);
333
 
334
        /* create a new board */
335
        Board *new_board;
336
        new_board = board_new();
337
 
338
        for (move.y = 0; move.y < board_size; move.y++) {
339
 
340
                /* bails out if ai_stop is true */
341
                if (ai_stop)
342
                        return moves;
343
 
344
                for (move.x = 0; move.x < board_size; move.x++) {
345
 
346
                        if (piece_at(b, move.x, move.y) != PIECE_NONE)
347
                                continue;
348
 
349
                        /* copy the board into the new board */
350
                        board_copy(b, new_board);
351
                        /* Add the piece to the board */
352
                        place_piece(new_board, move.x, move.y);
353
                        new_board->moves_left--;
354
                        /* find the utility for this new board */
355
                        move.weight = incremental_update(new_board, move.x, move.y, new_board->turn);
356
 
357
                        aimoves_add(moves, &move);
358
 
359
                        /* undo what we did, so things are correct next time around */
360
                        place_piece_type(new_board, move.x, move.y, PIECE_NONE);
361
                        new_board->moves_left++;
362
                        incremental_update(new_board, move.x, move.y, new_board->turn);
363
                }
364
        }
365
 
366
        if ((b->turn == PIECE_WHITE && black_threat_count) || (b->turn == PIECE_BLACK && white_threat_count)) {
367
                aimoves_sort(moves);
368
                aimoves_crop(moves, 1);
369
        }
370
 
371
        board_free(new_board);
372
 
373
        return moves;
374
}
375
 
376
AIMoves *ai_sequences(const Board *b)
377
{
378
        AIMoves *moves = move_utilities(b);
379
 
380
        return moves;
381
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.