-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathgame.c
138 lines (127 loc) · 3.93 KB
/
game.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "game.h"
#define LOOKUP(table, i, j, else_value) \
((i) < 0 || (j) < 0 || (i) > BOARD_SIZE || (j) > BOARD_SIZE \
? (else_value) \
: (table)[GET_INDEX(i, j)])
_Static_assert(BOARD_SIZE <= 26, "Board size must not be greater than 26");
_Static_assert(BOARD_SIZE > 0, "Board size must be greater than 0");
_Static_assert(GOAL <= BOARD_SIZE, "Goal must not be greater than board size");
_Static_assert(GOAL > 0, "Goal must be greater than 0");
_Static_assert(ALLOW_EXCEED == 0 || ALLOW_EXCEED == 1,
"ALLOW_EXCEED must be a boolean that is 0 or 1");
const line_t lines[4] = {
{1, 0, 0, 0, BOARD_SIZE - GOAL + 1, BOARD_SIZE}, // ROW
{0, 1, 0, 0, BOARD_SIZE, BOARD_SIZE - GOAL + 1}, // COL
{1, 1, 0, 0, BOARD_SIZE - GOAL + 1, BOARD_SIZE - GOAL + 1}, // PRIMARY
{1, -1, 0, GOAL - 1, BOARD_SIZE - GOAL + 1, BOARD_SIZE}, // SECONDARY
};
static char check_line_segment_win(const char *t, int i, int j, line_t line)
{
char last = t[GET_INDEX(i, j)];
if (last == ' ')
return ' ';
for (int k = 1; k < GOAL; k++) {
if (last != t[GET_INDEX(i + k * line.i_shift, j + k * line.j_shift)]) {
return ' ';
}
}
#if !ALLOW_EXCEED
if (last == LOOKUP(t, i - line.i_shift, j - line.j_shift, ' ') ||
last ==
LOOKUP(t, i + GOAL * line.i_shift, j + GOAL * line.j_shift, ' '))
return ' ';
#endif
return last;
}
char check_win(char *t)
{
for (int i_line = 0; i_line < 4; ++i_line) {
line_t line = lines[i_line];
for (int i = line.i_lower_bound; i < line.i_upper_bound; ++i) {
for (int j = line.j_lower_bound; j < line.j_upper_bound; ++j) {
char win = check_line_segment_win(t, i, j, line);
if (win != ' ')
return win;
}
}
}
for (int i = 0; i < N_GRIDS; i++)
if (t[i] == ' ')
return ' ';
return 'D';
}
double calculate_win_value(char win, char player)
{
if (win == player)
return 1.0;
if (win == (player ^ 'O' ^ 'X'))
return 0.0;
return 0.5;
}
int *available_moves(char *table)
{
int *moves = malloc(N_GRIDS * sizeof(int));
int m = 0;
for (int i = 0; i < N_GRIDS; i++)
if (table[i] == ' ')
moves[m++] = i;
if (m < N_GRIDS)
moves[m] = -1;
return moves;
}
void draw_board(const char *t)
{
for (int i = 0; i < BOARD_SIZE; i++) {
if (BOARD_SIZE < 10)
printf("%2d | ", i + 1);
else if (BOARD_SIZE >= 10 && BOARD_SIZE < 100)
printf("%3d | ", i + 1);
else
printf("%4d | ", i + 1);
for (int j = 0; j < BOARD_SIZE; j++) {
// make background color alter between high-intensity and standard
if ((i + j) & 1U)
printf("\x1b[47m");
else
printf("\x1b[107m");
switch (t[GET_INDEX(i, j)]) {
case 'O':
printf("\x1b[31m");
printf(" ○ ");
printf("\x1b[39m");
break;
case 'X':
printf("\x1b[34m");
printf(" × ");
printf("\x1b[39m");
break;
default:
printf(" ");
break;
}
printf("\x1b[49m");
}
printf("\n");
}
if (BOARD_SIZE >= 10)
printf("-");
if (BOARD_SIZE >= 100)
printf("-");
printf("---+-");
for (int i = 0; i < BOARD_SIZE; i++)
printf("---");
printf("\n");
if (BOARD_SIZE >= 10)
printf(" ");
if (BOARD_SIZE >= 100)
printf(" ");
printf(" ");
for (int i = 0; i < BOARD_SIZE; i++)
printf(" %2c", 'A' + i);
printf("\n");
}