forked from sysprog21/lab0-c
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame.c
139 lines (128 loc) · 3.98 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
139
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fixpoint.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';
}
long calculate_win_value(char win, char player)
{
if (win == player)
return FIXED_1;
if (win == (player ^ 'O' ^ 'X'))
return 0;
return 1UL << (SCALE_FACTOR - 1);
}
int *available_moves(const 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");
}