我有一个游戏。屏幕上将随机显示5种符号。如果屏幕上有3个或更多相同的符号,则玩家可以赢得一些钱。
例如,如果我有符号A
,B
,C
,D
,E
和F
。
F
可以替代任何其他类型的符号(通配符)。
因此,当屏幕上显示AAABC
或AFABB
时,就意味着我赢得了3-A
次胜利。
如果屏幕上显示AAFBB
,则表示我赢得了3-A
和3-B
两种胜利。
现在我有一个关于屏幕上显示内容的数组;我需要找到足够快的方式来检测游戏结果。
我现在有这个方法:
我为每个符号提供了一个代码:A -> 1
,B -> 2
,C -> 3
,D -> 4
,E -> 5
,F -> 0xF
。
就像我有一个数组:{A,B,C,D,E}
我将它们转换为屏幕代码:0x12345。
然后我列出了获奖面具:
0x11111
0x22222
0x33333
0x44444
0x55555
0x11110
0x01111
0x22220
...
0x00111
0x01110
0x11100
我使用屏幕代码,对每个掩码代码执行&
,例如0x111f1 & 0x11111 == 0x11111
,然后我知道我有5-A
胜利。
是否还有其他任何技巧可以做到这一点?
答案 0 :(得分:5)
正如ilent2所说,您当前使用的方法实际上不起作用,因为您使用的符号表示不是按位可分的(例如,A = 1
,B = 2
和{ {1}}因C = 3
}而中断。
解决这个问题的直接方法是每个位置使用5位,并使用:
A | B = C
然而,通过将每个符号表示为在4位字段中设置的两位,有一种聪明的方法,因为有6种(A = 0x01 (0b00001)
B = 0x02 (0b00010)
C = 0x04 (0b00100)
D = 0x08 (0b01000)
E = 0x10 (0b10000)
F = 0x1F (0b11111)
)种可能的组合:
= 4 x 3 ÷ 2
这样,任何两个符号的按位AND或OR都不是另一个有效符号。
就检测匹配而言,您已经使用的方法是在正确的轨道上。利用位移来检测多个位置的匹配,而不是为每个组合分别设置模式。
答案 1 :(得分:2)
这是我相当快的代码。
它输入一个包含5个字符的数组(例如:"AAFBB"
),并跟踪它找到的连续字母数。只要连续计数为3或更大,它就会增加该字母的Win
计数器。
它最终返回一个包含5个整数的数组,表示每个整数的胜利。
因此,对于输入"AAFBB"
,输出为{1, 1, 0, 0, 0}
,表示A和B都“赢了”一次。
(调用者负责释放返回的数组)
int* checkWins(char input[5])
{
int Counts[5]= {0};
int* Wins = (int*)calloc(5, sizeof(int));
char prevSymbol=input[0];
for(int i=0; i<5; ++i)
{
if (input[i] == 'F')
{
// WildCard! Increment ALL counters
for(int j=0; j<5; ++j)
{
Counts[j]++;
if (Counts[j] >= 3)
{
Wins[j]++;
}
}
prevSymbol = input[i];
continue;
}
if (input[i] == prevSymbol || prevSymbol == 'F')
{
Counts[ input[i]-'A']++;
if (Counts[ input[i]-'A'] >= 3)
{
Wins[ input[i]-'A']++;
}
}
else
{
Counts[prevSymbol-'A']=0;
}
prevSymbol = input[i];
}
return Wins;
}
int main(void)
{
int* wins = checkWins("AAFBB");
// Check wins[0]... wins[4] for winners.
// wins[0] and wins[1] should both be 1
// Indicating AAA and BBB according to the rules.
free(wins );
}
答案 2 :(得分:1)
可以通过符号串单次确定结果。这段代码可以做到:
#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()
的工作。实际上这些变化并不大(但是如果因为名称变更和结构变化而对文件进行区分,它们看起来会很大。
答案 3 :(得分:0)
我假设你将符号放在一个整数数组中,其中0到6的每个整数对应于你的符号,其中1 = A和F = 6.然后你只需循环给定的输入和每个符号检查以下x看你是否看到3的三元组。外循环将运行6次,内循环将运行6 - 最多i次。这将打印出重复项(打印输出AAAABE赢得4A赢和3A赢)但你可以解决这个问题。
for (int i = 0; i < 6; i++)
{
int candidate = symbols[i];
int j = i;
while (candidate == symbols[j] || symbols[i] == 6 && j < 6)
{
j++;
}
if (j - i >= 3)
{
// win of type candidate with length of j - i
}
}
答案 4 :(得分:0)
您可以按如下方式分配值:A = 10,B = 100,C = 1000,D = 10000,E = 100000,F = 1.我认为enum
可以帮助您。
然后你只需要输出输出字符串的值就可以说sum
。因此fNumber = sum % 10
是您F
的号码,aNumber = sum % 10
等等。然后只需检查aNumber + fNumber >= 3
。
答案 5 :(得分:0)
我觉得你建议的面具没什么问题。此外,您根本不需要检测游戏结果:
理论上,每五个字母的胜利都有1/7776的概率发生;每三个字母的胜利,一个105/7776的机会。如果您将随机生成器设置为输出介于1和7776之间的数字,并将每个掩码与这些数字中的一个(或三个字母获胜的情况下的范围)相关联,则程序将“事先知道”是否存在赢或不,以及哪种。
如果没有胜利,则显示随机的无赢洗牌。