5

我有一个游戏。屏幕上会随机显示 6 种符号中的 5 个符号。如果屏幕上相邻的相同符号有 3 个或更多,则玩家赢得一些钱。

例如,如果我有符号ABCDE、 和F

F可以替代任何其他类型的符号(通配符)。

所以当AAABCAFABB出现在屏幕上时,就意味着我赢了3-A。如果AAFBB出现在屏幕上,则表示我赢了 a3-A3-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赢了。

有没有人有任何其他技巧来做到这一点?

4

6 回答 6

5

正如 ilent2 所指出的,您当前使用的方法实际上不起作用,因为您使用的符号表示不是按位可分离的(例如,A = 1,B = 2C = 3break 因为A | B = C)。

解决此问题的直接方法是每个位置使用 5 位,并使用:

A = 0x01 (0b00001)
B = 0x02 (0b00010)
C = 0x04 (0b00100)
D = 0x08 (0b01000)
E = 0x10 (0b10000)
F = 0x1F (0b11111)

但是,有一种巧妙的方法可以将每个符号表示为在四位字段中设置的两位,因为有 6 ( = 4 x 3 ÷ 2) 种可能的组合:

A = 0x3 (0b0011)
B = 0x5 (0b0101)
C = 0x9 (0b1001)
D = 0x6 (0b0110)
E = 0xA (0b1010)
    0xC (0b1100) - unused, but available for one more symbol
F = 0xF (0b1111)

这样,任何两个符号的按位与或或永远不会是另一个有效符号。

就检测匹配而言,您已经使用的方法是正确的。利用位移来检测多个位置的匹配,而不是为每个组合使用单独的模式。

于 2013-09-15T01:17:28.673 回答
2

这是我相当快的代码。

它将一个包含 5 个字符的数组(例如:"AAFBB")作为输入,并跟踪它找到的连续字母的数量。只要连续计数为 3 或更大,它就会Win为该字母增加一个计数器。

它最终返回一个由 5 个整数组成的数组,表示每个整数的胜利。因此对于 input "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 );
}
于 2013-09-15T01:38:51.133 回答
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()。实际上,这些变化并不大(但是如果您因为名称更改和结构更改而对文件进行差异化,它们看起来会很大。

于 2013-09-15T04:48:16.000 回答
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
        }
    }
于 2013-09-15T01:17:32.070 回答
0

您可以按如下方式分配值:A = 10,B = 100,C = 1000,D = 10000,E = 100000,F = 1。我认为enum可以帮助您。然后,您只需将输出字符串的值添加到sum. 你fNumber = sum % 10的数量也是如此FaNumber = sum % 10 依此类推。然后只需检查是否aNumber + fNumber >= 3.

于 2013-09-15T01:28:08.240 回答
0

我认为您建议的口罩没有任何问题。此外,您根本不需要检测游戏结果:

理论上,每五个字母的胜利都有 1/7776 的概率发生;每三个字母获胜,就有 105/7776 的机会。如果您将随机生成器设置为输出 1 到 7776 之间的数字,并将每个掩码与其中一个数字(或在三字母获胜的情况下的范围)相关联,程序将“提前”知道是否存在胜利与否,以及哪种。

如果没有获胜,则显示随机无获胜洗牌。

于 2013-09-16T03:39:38.943 回答