可以通过符号串一次确定结果。这段代码做到了:
#include <assert.h>
#include <stdio.h>
/* You can have 0, 1 or 2 wins */
typedef struct WinInfo
{
unsigned char streak;
unsigned char letter;
unsigned char start;
} WinInfo;
typedef struct Win
{
int wins;
WinInfo windata[2];
} Win;
static void add_win(Win *win, int streak, int start, char letter)
{
assert(win->wins >= 0 && win->wins <= 1);
win->windata[win->wins].streak = streak;
win->windata[win->wins].letter = letter;
win->windata[win->wins].start = start;
win->wins++;
}
static void print_win(Win *win, const char symbol[5])
{
assert(win->wins >= 0 && win->wins <= 2);
if (win->wins == 0)
printf("No win for [%.5s]\n", symbol);
else
{
for (int i = 0; i < win->wins; i++)
{
printf("Win %d: %d-%c starting at %d in [%.5s]\n",
i, win->windata[i].streak, win->windata[i].letter,
win->windata[i].start, symbol);
}
}
}
static Win check_win(const char symbol[5])
{
int streak = 0;
int start = -1;
char letter = 0;
Win result = { 0 };
for (int i = 1; i < 5; i++)
{
if (symbol[i] == 'F' || symbol[i-1] == 'F' || symbol[i] == symbol[i-1])
{
/* Current and prior symbols are the same, or at least one is 'F' */
if (start == -1)
{
streak = 2;
start = i-1;
letter = symbol[i];
if (letter == 'F')
letter = symbol[i-1];
}
else if (symbol[i] != 'F' && letter != 'F' && symbol[i] != letter)
{
/* End of a streak -- for example: AFB, FAFB, AAB, FFAB, AFFB */
if (streak >= 3)
add_win(&result, streak, start, letter);
/* Reset start ... */
if (symbol[i-1] != 'F')
{
streak = 0;
start = -1;
}
else
{
/* Step back to first 'F' not preceded by another 'F' */
int j = i;
while (symbol[j-1] == 'F')
j--;
start = j;
streak = i - j + 1;
letter = symbol[i];
}
}
else
{
if (letter == 'F')
letter = symbol[i];
streak++;
}
}
else
{
/* Mismatch between current and prior symbol */
if (streak >= 3)
add_win(&result, streak, start, letter);
streak = 0;
start = -1;
}
}
if (streak >= 3)
add_win(&result, streak, start, letter);
return result;
}
#include <time.h>
#include <stdlib.h>
int main(void)
{
const struct test
{
char *symbols;
Win win;
} tests[] =
{
/* W2WB - wall-to-wall braces */
{ "AAAAA", { 1, { { 5, 'A', 0 }, { 0, 0, 0 } } } },
{ "AAAAB", { 1, { { 4, 'A', 0 }, { 0, 0, 0 } } } },
{ "AAABB", { 1, { { 3, 'A', 0 }, { 0, 0, 0 } } } },
{ "AAABC", { 1, { { 3, 'A', 0 }, { 0, 0, 0 } } } },
{ "AABBC", { 0, { { 0, 0, 0 }, { 0, 0, 0 } } } },
{ "AAFBB", { 2, { { 3, 'A', 0 }, { 3, 'B', 2 } } } },
{ "AAFBC", { 1, { { 3, 'A', 0 }, { 0, 0, 0 } } } },
{ "AAFFB", { 2, { { 4, 'A', 0 }, { 3, 'B', 2 } } } },
{ "ABCDE", { 0, { { 0, 0, 0 }, { 0, 0, 0 } } } },
{ "ABCDF", { 0, { { 0, 0, 0 }, { 0, 0, 0 } } } },
{ "ABCFE", { 0, { { 0, 0, 0 }, { 0, 0, 0 } } } },
{ "AFABB", { 1, { { 3, 'A', 0 }, { 0, 0, 0 } } } },
{ "AFFFB", { 2, { { 4, 'A', 0 }, { 4, 'B', 1 } } } },
{ "AFAFA", { 1, { { 5, 'A', 0 }, { 0, 0, 0 } } } },
{ "AFAFB", { 1, { { 4, 'A', 0 }, { 0, 0, 0 } } } },
{ "AFFFF", { 1, { { 5, 'A', 0 }, { 0, 0, 0 } } } },
{ "BAAAA", { 1, { { 4, 'A', 1 }, { 0, 0, 0 } } } },
{ "BAAAC", { 1, { { 3, 'A', 1 }, { 0, 0, 0 } } } },
{ "BCAAA", { 1, { { 3, 'A', 2 }, { 0, 0, 0 } } } },
{ "FAABB", { 1, { { 3, 'A', 0 }, { 0, 0, 0 } } } },
{ "FFAAB", { 1, { { 4, 'A', 0 }, { 0, 0, 0 } } } },
{ "FFABB", { 1, { { 3, 'A', 0 }, { 0, 0, 0 } } } },
{ "FFFAB", { 1, { { 4, 'A', 0 }, { 0, 0, 0 } } } },
{ "FFFBB", { 1, { { 5, 'B', 0 }, { 0, 0, 0 } } } },
{ "FFFFA", { 1, { { 5, 'A', 0 }, { 0, 0, 0 } } } },
{ "FFFFF", { 1, { { 5, 'F', 0 }, { 0, 0, 0 } } } },
};
enum { NUM_TESTS = sizeof(tests)/sizeof(tests[0]) };
int pass = 0;
for (size_t i = 0; i < NUM_TESTS; i++)
{
Win result = check_win(tests[i].symbols);
print_win(&result, tests[i].symbols);
if (result.wins == tests[i].win.wins)
{
int fail = 0;
for (int n = 0; n < result.wins; n++)
{
/* Update to record/verify start too */
if (result.windata[n].streak != tests[i].win.windata[n].streak ||
result.windata[n].letter != tests[i].win.windata[n].letter ||
result.windata[n].start != tests[i].win.windata[n].start)
{
printf("!! FAIL !! (wanted %d-%c @%d, actual %d-%c @%d)\n",
tests[i].win.windata[n].streak, tests[i].win.windata[n].letter,
tests[i].win.windata[n].start, result.windata[n].streak,
result.windata[n].letter, result.windata[n].start);
fail++;
}
}
if (fail == 0)
pass++;
}
else
printf("!! FAIL !! (%s: wanted %d, actual %d)\n",
tests[i].symbols, tests[i].win.wins, result.wins);
}
if (pass == NUM_TESTS)
printf("== PASS ==\n");
else
printf("!! FAIL !! (%d pass, %d fail)\n", pass, NUM_TESTS-pass);
printf("\nRandom play:\n");
srand(time(0));
for (int i = 0; i < 10; i++)
{
char symbols[5];
for (int j = 0; j < 5; j++)
{
symbols[j] = rand() % 6 + 'A';
}
Win result = check_win(symbols);
print_win(&result, symbols);
}
return (pass != NUM_TESTS); /* 0 success, 1 failure */
}
它有一个严格的测试阶段,以确保它在特别选择的测试用例上产生正确的结果。它还有一个“随机游戏”部分,可以随机尝试游戏。
示例输出:
Win 0: 5-A starting at 0 in [AAAAA]
Win 0: 4-A starting at 0 in [AAAAB]
Win 0: 3-A starting at 0 in [AAABB]
Win 0: 3-A starting at 0 in [AAABC]
No win for [AABBC]
Win 0: 3-A starting at 0 in [AAFBB]
Win 1: 3-B starting at 2 in [AAFBB]
Win 0: 3-A starting at 0 in [AAFBC]
Win 0: 4-A starting at 0 in [AAFFB]
Win 1: 3-B starting at 2 in [AAFFB]
No win for [ABCDE]
No win for [ABCDF]
No win for [ABCFE]
Win 0: 3-A starting at 0 in [AFABB]
Win 0: 4-A starting at 0 in [AFFFB]
Win 1: 4-B starting at 1 in [AFFFB]
Win 0: 5-A starting at 0 in [AFAFA]
Win 0: 4-A starting at 0 in [AFAFB]
Win 0: 5-A starting at 0 in [AFFFF]
Win 0: 4-A starting at 1 in [BAAAA]
Win 0: 3-A starting at 1 in [BAAAC]
Win 0: 3-A starting at 2 in [BCAAA]
Win 0: 3-A starting at 0 in [FAABB]
Win 0: 4-A starting at 0 in [FFAAB]
Win 0: 3-A starting at 0 in [FFABB]
Win 0: 4-A starting at 0 in [FFFAB]
Win 0: 5-B starting at 0 in [FFFBB]
Win 0: 5-A starting at 0 in [FFFFA]
Win 0: 5-F starting at 0 in [FFFFF]
== PASS ==
Random play:
Win 0: 3-B starting at 1 in [DBBBA]
No win for [DEECC]
No win for [ACAED]
Win 0: 4-D starting at 0 in [DFFFA]
Win 1: 4-A starting at 1 in [DFFFA]
No win for [FADFA]
No win for [CAEAF]
Win 0: 3-C starting at 2 in [AECFF]
No win for [EDAED]
No win for [EDEAC]
Win 0: 3-C starting at 1 in [EFCCA]
此版本的代码丢失了导致注释中提到的问题的静态变量。它还将报告结构与结果的打印分开。该check_win()
函数不打印任何内容;这就是现在的工作print_win()
。实际上,这些变化并不大(但是如果您因为名称更改和结构更改而对文件进行差异化,它们看起来会很大。