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

Subversion Repositories connect-6

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

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 Michael Levin
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 <time.h>
25
#include <gtk/gtk.h>
26
#include <glib/gprintf.h>
27
#include "shared.h"
28
#include "connectk.h"
29
 
30
/*
31
 *      Options menu
32
 */
33
 
34
int opt_det_ai = 0,
35
    opt_print_u = 0,
36
    opt_debug_dfsc = 0,
37
    opt_debug_thread = 0,
38
    opt_debug_stage = 0,
39
    opt_pause_ai = 0,
40
    opt_mark_log = 1,
41
    opt_mark_norm = 1,
42
    opt_grayscale = 0;
43
 
44
typedef struct {
45
        char *desc;
46
        int *pint;
47
        int redraw;
48
} Option;
49
 
50
/* This array contains boolean integer options which will appear as check
51
   menu items in the Options menu, the format is:
52
        { "Option name", &integer, redraw_on_toggle }, */
53
static Option options[] = {
54
        { "Pause AI",                   &opt_pause_ai,          FALSE },
55
        { "Deterministic AI",           &opt_det_ai,            FALSE },
56
        { "Print board utility",        &opt_print_u,           FALSE },
57
        { "Debug search path",          &opt_debug_dfsc,        FALSE },
58
        { "Debug threat stage",         &opt_debug_stage,       FALSE },
59
        { "Debug threads",              &opt_debug_thread,      FALSE },
60
        { "Logarithmic marking",        &opt_mark_log,          TRUE  },
61
        { "Normalized marking",         &opt_mark_norm,         TRUE  },
62
        { "Grayscale rendering",        &opt_grayscale,         TRUE  },
63
};
64
 
65
#define OPTIONS (sizeof (options) / sizeof (options[0]))
66
 
67
static void option_menu_item_toggled(GtkCheckMenuItem *item,
68
                                     gpointer user_data)
69
{
70
        Option *option = (Option*)user_data;
71
 
72
        *option->pint = !(*option->pint);
73
        gtk_check_menu_item_set_active(item, *option->pint);
74
        if (option->redraw)
75
                draw_board();
76
}
77
 
78
static void add_options_to_menu_shell(GtkWidget *menu)
79
{
80
        GtkWidget *item;
81
        int i;
82
 
83
        for(i = 0; i < OPTIONS; i++) {
84
                item = gtk_check_menu_item_new_with_mnemonic(options[i].desc);
85
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item),
86
                                               *(options[i].pint));
87
                g_signal_connect(item, "toggled",
88
                                 G_CALLBACK(option_menu_item_toggled),
89
                                 options + i);
90
                gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
91
        }
92
}
93
 
94
/*
95
 *      Window widgets
96
 */
97
 
98
typedef struct {
99
        PIECE type;
100
        PLAYER player;
101
} PlayerMenuItem;
102
 
103
static GtkWidget *statusbar = NULL, *tree_view = NULL, *window = NULL;
104
static GtkListStore *list_store;
105
 
106
// Change window statusbar text
107
void window_status(const char *msg)
108
{
109
        static int context;
110
 
111
        if (!statusbar)
112
                return;
113
        if (context)
114
                gtk_statusbar_pop(GTK_STATUSBAR(statusbar), context);
115
        context = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar),
116
                                               "default");
117
        gtk_statusbar_push(GTK_STATUSBAR(statusbar), context, msg);
118
}
119
 
120
// Set the correct settings for a move state
121
void setup_move(void)
122
{
123
        if (!tournament) {
124
                draw_marks(NULL, TRUE);
125
 
126
                /* Stop a draw game */
127
                if (move_no >= board_size * board_size) {
128
                        window_status(va("Draw in %d moves", move_no));
129
                        draw_playable(FALSE);
130
                        return;
131
                }
132
 
133
                /* Stop a won game */
134
                if (board->won) {
135
                        draw_playable(FALSE);
136
                        draw_win();
137
                        window_status(va("%s wins in %d moves (%s -> %s)",
138
                                         piece_to_string(board->turn), move_no,
139
                                         bcoords_to_string(board->win_x1,
140
                                                           board->win_y1),
141
                                         bcoords_to_string(board->win_x2,
142
                                                           board->win_y2)));
143
                        return;
144
                }
145
 
146
                /* Status bar message */
147
                if (!move_no)
148
                        window_status(va("Game start: %s to play "
149
                                         "(%d move%s left)",
150
                                         piece_to_string(board->turn),
151
                                         board->moves_left,
152
                                         board->moves_left == 1 ? "" : "s"));
153
                else
154
                        window_status(va("Move %d: %s to play (%d move%s left)",
155
                                         move_no, piece_to_string(board->turn),
156
                                         board->moves_left,
157
                                         board->moves_left == 1 ? "" : "s"));
158
 
159
                draw_playable(players[board->turn].ai == PLAYER_HUMAN);
160
        }
161
 
162
        /* Let the AI thread run one move */
163
        start_ai();
164
}
165
 
166
// Tree view cursor changed
167
static void cursor_changed(GtkTreeView *tree_view, gpointer user_data)
168
{
169
        GtkTreeSelection *selection;
170
        GtkTreeIter iter;
171
        GtkTreePath *path;
172
        gint *indices;
173
 
174
        selection = gtk_tree_view_get_selection(tree_view);
175
        gtk_tree_selection_get_selected(selection, NULL, &iter);
176
        path = gtk_tree_model_get_path(GTK_TREE_MODEL(list_store), &iter);
177
        indices = gtk_tree_path_get_indices(path);
178
        indices += gtk_tree_path_get_depth(path) - 1;
179
        if (*indices == move_no)
180
                return;
181
        go_to_move(*indices);
182
        gtk_tree_path_free(path);
183
        draw_board();
184
        stop_ai();
185
        setup_move();
186
}
187
 
188
// Clear moves in the history list
189
void tree_view_clear(unsigned int from)
190
{
191
        GtkTreeIter iter;
192
        GtkTreeSelection *selection;
193
        gboolean valid;
194
 
195
        if (!tree_view)
196
                return;
197
 
198
        g_signal_handlers_block_by_func(G_OBJECT(tree_view), cursor_changed,
199
                                        NULL);
200
 
201
        // Remove entries from list store
202
        valid = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store),
203
                                              &iter, NULL, from);
204
        while (valid)
205
                valid = gtk_list_store_remove(list_store, &iter);
206
 
207
        // Select start entry
208
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
209
        gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter);
210
        gtk_tree_selection_select_iter(selection, &iter);
211
 
212
        g_signal_handlers_unblock_by_func(G_OBJECT(tree_view), cursor_changed,
213
                                          NULL);
214
}
215
 
216
// Make a move for the current player
217
void make_move(BCOORD x, BCOORD y)
218
{
219
        GtkTreeIter iter;
220
        GtkTreePath *path;
221
        GtkTreeSelection *selection;
222
        PIECE last_turn;
223
 
224
        if (piece_at(board, x, y) != PIECE_NONE) {
225
                g_warning("%s attempted invalid move to %s",
226
                          piece_to_string(board->turn),
227
                          bcoords_to_string(x, y));
228
                return;
229
        }
230
 
231
        if (!tournament) {
232
                clear_last_moves();
233
 
234
                // Remove the later moves from the list
235
                if (move_no < move_last) {
236
                        clear_history(move_no + 1);
237
                        tree_view_clear(move_no + 1);
238
                }
239
 
240
                /* Add move to list */
241
                gtk_list_store_append(list_store, &iter);
242
                gtk_list_store_set(list_store, &iter, 0, va("%c%s",
243
                                   piece_to_char(board->turn),
244
                                   bcoords_to_string(x, y)), -1);
245
 
246
                // Scroll moves list down
247
                path = gtk_tree_model_get_path(GTK_TREE_MODEL(list_store),
248
                                               &iter);
249
                gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tree_view), path,
250
                                             NULL, FALSE, 0., 0.);
251
                gtk_tree_path_free(path);
252
 
253
                // Select last move
254
                selection =
255
                          gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
256
                g_signal_handlers_block_by_func(G_OBJECT(tree_view),
257
                                                cursor_changed, NULL);
258
                gtk_tree_selection_select_iter(selection, &iter);
259
                g_signal_handlers_unblock_by_func(G_OBJECT(tree_view),
260
                                                  cursor_changed, NULL);
261
        }
262
 
263
        // Place piece
264
        board->move_x = x;
265
        board->move_y = y;
266
        last_turn = board->turn;
267
        go_to_move(++move_no);
268
        place_piece(board, x, y);
269
        if (!tournament)
270
                draw_tile(x, y);
271
        board->won = check_win_full(board, x, y,
272
                                    &board->win_x1, &board->win_y1,
273
                                    &board->win_x2, &board->win_y2);
274
        if (!board->won) {
275
                board->moves_left--;
276
                if (board->moves_left <= 0) {
277
                        board->turn = other_player(last_turn);
278
                        board->moves_left = place_p;
279
                }
280
        }
281
 
282
        /* Tournament win conditions */
283
        if (tournament) {
284
                if (move_no >= board_size * board_size) {
285
                        tourney_result(PIECE_NONE, move_last);
286
                        return;
287
                }
288
                if (board->won) {
289
                        tourney_result(board->turn, move_last);
290
                        return;
291
                }
292
        } else
293
                draw_last_moves();
294
 
295
        setup_move();
296
}
297
 
298
// Main window closed
299
static void window_destroy(GtkWidget *widget, gpointer data)
300
{
301
        gtk_main_quit();
302
}
303
 
304
// Create a menu bar the old-fashioned way
305
static GtkWidget *window_menu_bar_init(GtkAccelGroup *accel)
306
{
307
        GtkWidget *bar, *item, *submenu;
308
 
309
        bar = gtk_menu_bar_new();
310
 
311
        /* Init player dialogs */
312
        player_dialog_init(player_dialog, PIECE_BLACK);
313
        player_dialog_init(player_dialog + 1, PIECE_WHITE);
314
        player_dialog_init(player_dialog + 2, PIECE_NONE);
315
 
316
        // Game menu
317
        item = gtk_menu_item_new_with_mnemonic("_Game");
318
        gtk_menu_shell_append(GTK_MENU_SHELL(bar), item);
319
        submenu = gtk_menu_new();
320
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
321
        item = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, accel);
322
        g_signal_connect(G_OBJECT(item), "activate",
323
                         G_CALLBACK(open_new_game_dialog), NULL);
324
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
325
        item = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, accel);
326
        g_signal_connect(G_OBJECT(item), "activate",
327
                         G_CALLBACK(open_file_dialog), NULL);
328
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
329
        item = gtk_separator_menu_item_new();
330
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
331
        item = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE_AS, accel);
332
        g_signal_connect(G_OBJECT(item), "activate",
333
                         G_CALLBACK(save_file_dialog), NULL);
334
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
335
#ifndef NO_CAIRO_SVG
336
        item = gtk_separator_menu_item_new();
337
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
338
        item = gtk_menu_item_new_with_mnemonic("Screenshot");
339
        g_signal_connect(G_OBJECT(item), "activate",
340
                         G_CALLBACK(screenshot_dialog), NULL);
341
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
342
#endif
343
        item = gtk_separator_menu_item_new();
344
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
345
 
346
        // Game -> Quit
347
        item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel);
348
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
349
        g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(window_destroy),
350
                         NULL);
351
 
352
        /* Setup menu */
353
        item = gtk_menu_item_new_with_mnemonic("_Setup");
354
        gtk_menu_shell_append(GTK_MENU_SHELL(bar), item);
355
        submenu = gtk_menu_new();
356
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
357
        item = gtk_menu_item_new_with_mnemonic("_Black Player");
358
        g_signal_connect(G_OBJECT(item), "activate",
359
                         G_CALLBACK(open_player_dialog), player_dialog);
360
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
361
        item = gtk_menu_item_new_with_mnemonic("_White Player");
362
        g_signal_connect(G_OBJECT(item), "activate",
363
                         G_CALLBACK(open_player_dialog), player_dialog + 1);
364
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
365
        item = gtk_menu_item_new_with_mnemonic("_Mark Player");
366
        g_signal_connect(G_OBJECT(item), "activate",
367
                         G_CALLBACK(open_player_dialog), player_dialog + 2);
368
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
369
        item = gtk_separator_menu_item_new();
370
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
371
        item = gtk_menu_item_new_with_mnemonic("_Tournament");
372
        g_signal_connect(G_OBJECT(item), "activate",
373
                         G_CALLBACK(open_tourney_dialog), NULL);
374
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
375
        item = gtk_separator_menu_item_new();
376
        gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
377
        add_options_to_menu_shell(submenu);
378
 
379
        /* Tests menu */
380
        item = gtk_menu_item_new_with_mnemonic("_Tests");
381
        gtk_menu_shell_append(GTK_MENU_SHELL(bar), item);
382
        submenu = gtk_menu_new();
383
        add_tests_to_menu_shell(submenu);
384
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
385
 
386
        return bar;
387
}
388
 
389
// Create a tree view to store the move history
390
static GtkWidget *tree_view_init(void)
391
{
392
        GtkWidget *scrolled;
393
        GtkTreeViewColumn *column;
394
        GtkTreeSelection *selection;
395
        GtkTreeIter iter;
396
 
397
        if (tree_view)
398
                return tree_view;
399
 
400
        // Tree view to list move history
401
        list_store = gtk_list_store_new(1, G_TYPE_STRING);
402
        tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store));
403
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
404
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
405
        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_view), TRUE);
406
        column = gtk_tree_view_column_new_with_attributes("History",
407
                                                   gtk_cell_renderer_text_new(),
408
                                                          "text", 0, NULL);
409
        gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
410
        g_signal_connect(G_OBJECT(tree_view), "cursor-changed",
411
                         G_CALLBACK(cursor_changed), NULL);
412
 
413
        // Add empty board entry to history list
414
        gtk_list_store_append(list_store, &iter);
415
        gtk_list_store_set(list_store, &iter, 0, "(start)", -1);
416
 
417
        // Scrolled container for tree view
418
        scrolled = gtk_scrolled_window_new(NULL, NULL);
419
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
420
                                       GTK_POLICY_NEVER,
421
                                       GTK_POLICY_AUTOMATIC);
422
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
423
                                            GTK_SHADOW_IN);
424
        gtk_container_add(GTK_CONTAINER(scrolled), tree_view);
425
        return scrolled;
426
}
427
 
428
// Create and show main window
429
static void window_init(void)
430
{
431
        GtkWidget *hbox, *vbox;
432
        GtkAccelGroup *accel;
433
 
434
        if (window)
435
                return;
436
 
437
        // Keyboard accelerator group
438
        accel = gtk_accel_group_new();
439
 
440
        // Menu, hbox, and status bar are packed vertically
441
        vbox = gtk_vbox_new(FALSE, 0);
442
        gtk_box_pack_start(GTK_BOX(vbox), window_menu_bar_init(accel), FALSE,
443
                           FALSE, 0);
444
        statusbar = gtk_statusbar_new();
445
        gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
446
 
447
        // Board and history are packed horizontally
448
        hbox = gtk_hbox_new(FALSE, 0);
449
        gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
450
        gtk_box_pack_start(GTK_BOX(hbox), draw_init(), TRUE, TRUE, 0);
451
        gtk_box_pack_start(GTK_BOX(hbox), tree_view_init(), FALSE, FALSE, 0);
452
 
453
        // Create and show the window
454
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
455
        g_signal_connect(G_OBJECT(window), "destroy",
456
                         G_CALLBACK(window_destroy), NULL);
457
        gtk_window_set_title(GTK_WINDOW(window), "connectk");
458
        gtk_window_resize(GTK_WINDOW(window), 686, 656);
459
        gtk_window_add_accel_group(GTK_WINDOW(window), accel);
460
        gtk_container_add(GTK_CONTAINER(window), vbox);
461
        gtk_widget_show_all(window);
462
 
463
        // Create new game dialog
464
        new_game_dialog_init();
465
 
466
        /* Initialize tournament dialog */
467
        tourney_dialog_init();
468
}
469
 
470
/*
471
 *      Utility and main
472
 */
473
 
474
char *nvav(int *plen, const char *fmt, va_list va)
475
{
476
        static char buffer[2][16000];
477
        static int which;
478
        int len;
479
 
480
        which = !which;
481
        len = g_vsnprintf(buffer[which], sizeof(buffer[which]), fmt, va);
482
        if (plen)
483
                *plen = len;
484
        return buffer[which];
485
}
486
 
487
char *nva(int *plen, const char *fmt, ...)
488
{
489
        va_list va;
490
        char *string;
491
 
492
        va_start(va, fmt);
493
        string = nvav(plen, fmt, va);
494
        va_end(va);
495
        return string;
496
}
497
 
498
char *va(const char *fmt, ...)
499
{
500
        va_list va;
501
        char *string;
502
 
503
        va_start(va, fmt);
504
        string = nvav(NULL, fmt, va);
505
        va_end(va);
506
        return string;
507
}
508
 
509
int main(int argc, char *argv[])
510
{
511
        start_ai_thread();
512
        new_game(19);
513
 
514
        /* Set the Glib random seed */
515
        g_random_set_seed(time(NULL));
516
 
517
        /* Initialize and run the GTK interface */
518
        gtk_init(&argc, &argv);
519
        window_init();
520
        gtk_main();
521
 
522
        return 0;
523
}

powered by: WebSVN 2.1.0

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