Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
zmx0142857
GitHub Repository: zmx0142857/mini-games
Path: blob/master/c/add2n/add2n.c
363 views
1
#include <stdio.h>
2
#include <stdbool.h>
3
#include <stdlib.h>
4
#include <time.h>
5
#include <string.h>
6
7
/* 000 Not decided
8
* 100 A wins by rr
9
* 101 A wins by rl
10
* 110 A wins by lr
11
* 111 A wins by ll
12
* 1000 B wins
13
*/
14
#define ARR 4
15
#define ARL 5
16
#define ALR 6
17
#define ALL 7
18
#define A_WINS 4
19
#define B_WINS 8
20
int N = 10;
21
char **table;
22
#define TBL table[al*(al+1)/2+ar-1][bl*(bl+1)/2+br-1]
23
int al, ar, bl, br;
24
int cnt = 0;
25
int collision = 0;
26
#define BUF_SIZE 64
27
char buf[BUF_SIZE];
28
29
#define status(AL,AR,BL,BR) al==AL && ar==AR && bl==BL && br==BR
30
31
void print()
32
{
33
char ch;
34
printf("A/B");
35
for (al = 1; al < N; ++al)
36
for (ar = 0; ar <= al; ++ar)
37
printf(" %d/%d", al, ar);
38
putchar('\n');
39
for (al = 1; al < N; ++al)
40
for (ar = 0; ar <= al; ++ar) {
41
printf("%d/%d ", al, ar);
42
for (bl = 1; bl < N; ++bl)
43
for (br = 0; br <= bl; ++br) {
44
ch = TBL;
45
if (ch == 0)
46
printf(" ");
47
else if (ch == B_WINS)
48
printf("B ");
49
else {
50
putchar('A');
51
putchar(ch & 2 ? 'l' : 'r');
52
putchar(ch & 1 ? 'l' : 'r');
53
putchar(' ');
54
}
55
}
56
putchar('\n');
57
}
58
}
59
60
char check(int al, int ar, int bl, int br)
61
{
62
if (al >= N) al = 0;
63
if (ar >= N) ar = 0;
64
if (bl >= N) bl = 0;
65
if (br >= N) br = 0;
66
int tmp;
67
if (al < ar) { tmp = al; al = ar; ar = tmp; }
68
if (bl < br) { tmp = bl; bl = br; br = tmp; }
69
tmp = TBL;
70
return tmp;
71
}
72
73
// 四面有一 B 就获胜, 四面皆 A 则失败
74
// #define try
75
#define try(BL,BR)\
76
win = check(bl, br, BL, BR);\
77
if (win == B_WINS) {\
78
TBL = A_WINS | add | by;\
79
return true;\
80
} else if (win & A_WINS) {\
81
++fail;\
82
}
83
84
bool fill(int al, int ar, int bl, int br) {
85
if (TBL) {
86
//printf("%d %d %d %d already decided\n", al, ar, bl, br);
87
++collision;
88
return false;
89
}
90
char win = 0, fail = 0, add, by;
91
if (al) {
92
add = 2;
93
if (bl) {
94
by = 1;
95
try(al+bl, ar);
96
} else fail += 1;
97
if (br) {
98
by = 0;
99
try(al+br, ar);
100
} else fail += 1;
101
} else fail += 2;
102
if (ar) {
103
add = 0;
104
if (bl) {
105
by = 1;
106
try(al, ar+bl);
107
} else fail += 1;
108
if (br) {
109
by = 0;
110
try(al, ar+br);
111
} else fail += 1;
112
} else fail += 2;
113
if (fail == 4) {
114
TBL = B_WINS;
115
return true;
116
}
117
return false; // 暂时不能判断
118
}
119
120
void init()
121
{
122
int SIZE = N*(N+1)/2-1;
123
table = (char**)malloc(SIZE*sizeof(char*));
124
for (int i = 0; i < SIZE; ++i) {
125
table[i] = (char*)malloc(SIZE);
126
memset(table[i], 0, SIZE);
127
}
128
129
ar = 0;
130
for (al = 1; al < N; ++al)
131
for (bl = N-al; bl < N; ++bl)
132
for (br = 0; br <= bl; ++br)
133
TBL = ALL;
134
cnt = (N*N-1)*N/3; // sum_(k=1)^(N-1) k(k+1)
135
}
136
137
void build_table()
138
{
139
// init
140
init();
141
//puts("----init----");
142
//print();
143
144
// first round
145
int bound = (N-1)*(N*(N+1)/2-1);
146
bound = bound * 2 - (N-1)*(N-1);
147
int prevcnt = 0;
148
int loop = 0;
149
while (cnt < bound && cnt > prevcnt) {
150
++loop;
151
prevcnt = cnt;
152
br = 0;
153
for (bl = N-1; bl > 0; --bl)
154
for (al = N-1; al > 0; --al)
155
for (ar = al; ar >= 0; --ar)
156
if (fill(al, ar, bl, br)) ++cnt;
157
158
ar = 0;
159
for (al = N-1; al > 0; --al)
160
for (bl = N-1; bl > 0; --bl)
161
for (br = bl; br >= 0; --br)
162
if (fill(al, ar, bl, br)) ++cnt;
163
}
164
//puts("\n----first round----");
165
//print();
166
//printf("collision: %d, loop: %d\n", collision, loop);
167
//printf("bound: %d, cnt: %d, prevcnt: %d\n", bound, cnt, prevcnt);
168
if (cnt < bound) return;
169
170
bound = N*(N+1)/2-1; bound *= bound;
171
loop = 0;
172
while (cnt < bound && cnt > prevcnt) {
173
++loop;
174
prevcnt = cnt;
175
for (int i = N-1; i > 0; --i)
176
for (int j = i; j > 0; --j) {
177
bl = i; br = j; al = i;
178
for (ar = j; ar > 0; --ar)
179
if (fill(al, ar, bl, br)) ++cnt;
180
for (al = i-1; al > 0; --al)
181
for (ar = al; ar > 0; --ar)
182
if (fill(al, ar, bl, br)) ++cnt;
183
184
al = i; ar = j; bl = i;
185
for (br = j; br > 0; --br)
186
if (fill(al, ar, bl, br)) ++cnt;
187
for (bl = i-1; bl > 0; --bl)
188
for (br = bl; br > 0; --br)
189
if (fill(al, ar, bl, br)) ++cnt;
190
}
191
}
192
//puts("\n----second round----");
193
//print();
194
//printf("collision: %d, loop: %d\n", collision, loop);
195
//printf("bound: %d, cnt: %d, prevcnt: %d\n", bound, cnt, prevcnt);
196
if (cnt < bound) return;
197
}
198
199
void discard_line()
200
{
201
while (buf[strlen(buf)-1] != '\n')
202
fgets(buf, BUF_SIZE, stdin);
203
}
204
205
void play()
206
{
207
srand(time(NULL));
208
209
bool your_turn = true;
210
printf("[ADD TO %d]\n"
211
"2 players take turns to add a number from the other's hand.\n"
212
"the one who get both numbers >= %d wins.\n"
213
"you cannot operate on a number that is already >= %d.\n"
214
"you have 4 choices: ll/lr/rl/rr\n"
215
"will you go first? [y/n] ", N, N, N);
216
217
al = ar = bl = br = 1;
218
while (true) {
219
fgets(buf, 1+2, stdin); // one is for '\n', the other for '\0'
220
if (strcmp(buf, "n\n") == 0 || strcmp(buf, "N\n") == 0)
221
your_turn = false;
222
else if (strcmp(buf, "y\n") == 0 || strcmp(buf, "Y\n") == 0)
223
printf("computer: %d %d\n", bl, br);
224
else {
225
puts("invalid input");
226
printf("will you go first? [y/n] ");
227
discard_line();
228
continue;
229
}
230
break;
231
}
232
233
printf("you: %d %d\n", al, ar);
234
int flag = 0;
235
while (!flag) {
236
if (your_turn) {
237
printf("> ");
238
discard_line();
239
if (!fgets(buf, 2+2, stdin)) {
240
break;
241
}
242
int *a, *b;
243
if (buf[2] == '\n' && (
244
(buf[0] == 'l' && al < N && (a = &al))
245
|| (buf[0] == 'r' && ar < N && (a = &ar))
246
)) {
247
if ((buf[1] == 'l' && bl < N && (b = &bl))
248
|| (buf[1] == 'r' && br < N && (b = &br))
249
) {
250
*a += *b;
251
} else {
252
puts("invalid input");
253
continue;
254
}
255
} else {
256
puts("invalid input");
257
continue;
258
}
259
printf("you: ");
260
if (al >= N) { int tmp = al; al = ar; ar = tmp; }
261
if (al < N) printf(" %d", al);
262
else printf(" (%d)", al);
263
if (ar < N) printf(" %d", ar);
264
else printf(" (%d)", ar);
265
putchar('\n');
266
if (al >= N && ar >= N)
267
flag = 1;
268
} else {
269
int solution = check(bl, br, al, ar);
270
if (solution == B_WINS) {
271
int choice = rand() % 4;
272
while (true) {
273
if (choice == 0 && bl < N && al < N) {
274
bl += al;
275
break;
276
} else if (choice == 1 && bl < N && ar < N) {
277
bl += ar;
278
break;
279
} else if (choice == 2 && br < N && al < N) {
280
br += al;
281
break;
282
} else if (choice == 3 && br < N && ar < N) {
283
br += ar;
284
break;
285
}
286
choice = (choice+1) % 4;
287
}
288
} else {
289
int *a1, *a2, *b1, *b2;
290
if (ar >= N || al >= ar) {
291
a1 = &al;
292
a2 = &ar;
293
} else {
294
a1 = &ar;
295
a2 = &al;
296
}
297
if (br >= N || bl >= br) {
298
b1 = &bl;
299
b2 = &br;
300
} else {
301
b1 = &br;
302
b2 = &bl;
303
}
304
switch (solution) {
305
case ALL: *b1 += *a1; break;
306
case ALR: *b1 += *a2; break;
307
case ARL: *b2 += *a1; break;
308
case ARR: *b2 += *a2; break;
309
}
310
}
311
printf("computer:");
312
if (bl >= N) { int tmp = bl; bl = br; br = tmp; }
313
if (bl < N) printf(" %d", bl);
314
else printf(" (%d)", bl);
315
if (br < N) printf(" %d", br);
316
else printf(" (%d)", br);
317
putchar('\n');
318
if (bl >= N && br >= N)
319
flag = 2;
320
}
321
your_turn = !your_turn;
322
}
323
if (flag == 1)
324
puts("you win!");
325
else if (flag == 2)
326
puts("computer wins! you suck!");
327
else
328
puts("bye");
329
}
330
331
int main(int argc, char **argv)
332
{
333
if (argc > 1) {
334
N = atoi(argv[1]);
335
if (N < 5 || N > 20) {
336
puts("5 <= N <= 20 is required.");
337
return 1;
338
}
339
}
340
build_table();
341
play();
342
return 0;
343
}
344
345