-
Notifications
You must be signed in to change notification settings - Fork 0
/
behavior.c
154 lines (136 loc) · 3.96 KB
/
behavior.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "board.h"
#include "search.h"
bool fallbackmode = false;
static char increment(bool, int *, int, int);
static int singlepass(int *);
static bool intermediatepass(void);
static void finalpass(void);
int computerplayer(int *score)
{
// Match until no more can be made
while (singlepass(score) > 0);
// Find space that does not give SOS oppourtinities
if (intermediatepass())
finalpass();
return false;
}
// Scans the board once and makes moves that gain points
// Increments score
// Returns number of points gained
static int singlepass(int *score)
{
int gain = 0;
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (board[i][j] != ' ')
continue;
// Possible points gained
int sgain = search(S_SCORE_MASK, S_SCORE_MASK_LENGTH, j, i), ogain = search(O_SCORE_MASK, O_SCORE_MASK_LENGTH, j, i);
// Skip if no points can be gained
if (sgain == 0 && ogain == 0)
continue;
if (sgain > 0 && ogain > 0)
{
// Both sgain and ogain are greater than 0
// Priorotize choice that results in the most possible SOS setups
int schain = search(S_CHAIN_MASK, S_CHAIN_MASK_LENGTH, j, i), ochain = search(O_CHAIN_MASK, O_CHAIN_MASK_LENGTH, j, i);
board[i][j] = increment(sgain + schain > ogain + ochain, &gain, sgain, ogain);
}
else
{
// One or the other is equal to 0
board[i][j] = increment(sgain > ogain, &gain, sgain, ogain);
}
}
}
*score += gain;
return gain;
}
static char increment(bool expr, int *gain, int sgain, int ogain)
{
*gain += expr ? sgain : ogain;
return expr ? 'S' : 'O';
}
// Looks two steps ahead to not give opponent an advantage
// Returns true if no valid space is found
static bool intermediatepass()
{
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (board[i][j] != ' ')
continue;
int schain = search(S_CHAIN_MASK, S_CHAIN_MASK_LENGTH, j, i), ochain = search(O_CHAIN_MASK, O_CHAIN_MASK_LENGTH, j, i);
// No setups can be made
if (schain == 0 && ochain == 0)
{
board[i][j] = (fallbackmode = !fallbackmode) ? 'S' : 'O';
return false;
}
// Both letters create setups
if (schain > 0 && ochain > 0)
continue;
// Only one letter can create setups
board[i][j] = schain > ochain ? 'O': 'S';
return false;
}
}
return true;
}
// Scans for an empty space
static void finalpass()
{
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (board[i][j] == ' ')
{
board[i][j] = (fallbackmode = !fallbackmode) ? 'S' : 'O';
return;
}
}
}
}
// Ask for manual player input
int player(int *score)
{
char c;
do
{
printf("Select 's' or 'o': ");
c = getchar() == '\n' ? getchar() : c;
c = toupper(c);
} while (!(c == 'S' || c == 'O'));
int x, y;
do
{
do
{
printf("Input X coordinate (1 - %d): ", WIDTH);
scanf("%d", &x);
x--;
} while (x < 0 || x >= WIDTH);
do
{
printf("Input Y coordinate (1 - %d): ", HEIGHT);
scanf("%d", &y);
y--;
} while (y < 0 || y >= HEIGHT);
} while (isoccupied(x, y));
printf("\n");
int inc;
if ((board[y][x] = c) == 'S')
inc = search(S_SCORE_MASK, S_SCORE_MASK_LENGTH, x, y);
else
inc = search(O_SCORE_MASK, O_SCORE_MASK_LENGTH, x, y);
*score += inc;
return inc;
}