Mastermind解决方案实施问题

时间:2014-12-18 00:17:40

标签: c++ algorithm memory-management

我用C ++编写了一个mastermind解算器,用az字母表示,字符串的长度由用户插入 - 不应该绑定,因为我们可以保存一个这么大的字符串在记忆中。所有这一切,不使用矢量等STD容器。此外,根据之前给出的反馈,没有猜测错误的猜测。

我写了一个令人沮丧的Knuth算法版本: 对于我们在猜测后得到的每个反馈,我们消除了所有其他可能性,如果它们是实际代码,它们将不会产生这种反馈。与Knuth's不同,我之后没有使用minmax,我只是根据反馈从可能的猜测组中消除那些可能不正确的组合。

我用两种方式实现了这个:

  1. 持有一个大小为26 ^ Length的布尔表,表示猜测X是否仍然可能。然后在每个getPossibleGuess()调用中,我们将返回对应于第一个有效单元格的字符串(单元格编号0是aaa ... a,单元格2是aaaa ... ab等)。 当收到反馈时,我们在表格上进行迭代并将单元格设置为“假”。如果它们代表的字符串如果是实际代码则不会给出相同的反馈。
  2. 问题:数组大小。 26 ^长度可以变得相当大,甚至像20这样的短长度也给我们一个甚至没有签名的长长度可以处理的数字。因此,我们无法满足未绑定长度的要求。

    第二次实施:

    1. 持有作为当前字符串的类成员。在给出反馈时,存储该反馈。当被问及可能的猜测时,将当前字符串(aaa ... a增加到aaa..ab,aaa ... az到aaaa ... aba等)增加并检查它是否符合以前存储的所有反馈。如果是这样,请将其退回。如果没有,请递增并继续搜索。
    2. 问题:这可以处理我们想要的字符串,但它非常非常慢。非常

      如果有人能指出我如何解决这些问题,我将非常感激。

      谢谢!

2 个答案:

答案 0 :(得分:0)

正如我在评论中提到的,我建议您使用unsigned longs数组来跟踪可能性。只要unsigned int超过26位,sizeof(int)也可以在许多平台上使用。

数组中的每个unsigned long表示可以在相应位置播放的可能字母集。

检查long

的位
00000000000000000000000000010101
      ZYXWVUTSRQPONMLKJIHGFEDCBA

在此示例中,该值设置为21,对应于“A”,“C”和“E”已被裁定为无法播放且所有其他字母仍处于争用状态。

您可以使用常量来跟踪每个字母的“位值”。 (如果sizeof(enum value)小于26位,则枚举将不起作用)。

const unsigned long A = 1 << 0;  // ==1  or 00000000000000001
const unsigned long B = 1 << 1;  // ==2  or 00000000000000010
const unsigned long C = 1 << 2;  // ==4  or 00000000000000100
const unsigned long D = 1 << 3;  // ==8  or 00000000000001000
const unsigned long E = 1 << 4;  // ==16 or 00000000000010000
// etc ...

然后为每个可以放置字母的位置创建一个带有一个无符号长整数的数组:

unsigned long possibilities [20] = {}; 

然后要排除一个字母,你可以按位OR |使用无符号long的常量字母值在数组中的正确位置。例如,要排除位置4处的字母“D”,您可以调用:

possibilities[3] |= D; // rules out d by flipping the 'D' bit to 1.

要在游戏结束时重置,只需将可能性数组中的所有值重置为0。

要确定字母是否仍可播放,以下代码使用按位AND &将起作用:

if( (possibilities[3] & D) == D )
{
    // D's bit is set to 1 therefore D has been ruled out
}
else
{
    // D's bit is set to 0 therefore D is still a possibility
}

请注意,使用标准容器(例如std::bitsetstd::vector

)也可以更优雅地完成此操作

您可以将所有这些封装在一个不错的class中,这样就可以完全屏蔽任何客户端代码。

答案 1 :(得分:0)

1)Knuth的算法仅适用于小型拼图集,例如: 6种颜色,4个位置,总共6个 4 = 1296个可能的答案。大型拼图套装不适合记忆,使用minmax进行分析需要很长时间。

2)计数算法将永远需要,例如,26 20 = 2 94 。忘记验证给定的解决方案是否与反馈一致,只需要一个计算为2 94 的简单循环就会花费太长时间。

3)所以你需要一种完全不同的方法。最好的方法是计算机实现的简单方法(尽管对于人类玩家来说很无聊和乏味)。

首先猜测所有a s,反馈会告诉您答案中有多少a个。重复bz。现在你知道你需要的每封信中有多少。

接下来,您需要确定字母a的正确位置。因此,猜猜有一个a和其他所有b。该猜测的反馈将是3种不同可能性中的1种。假设已知b s的数量为B,则反馈将为

    1 white and B-1 black, if the 'a' is where a 'b' should be.
    1 white and B   black, if the 'a' is where a 'c' thru 'z' should be.
    0 white and B+1 black, if the 'a' is in one of the correct locations.

在每个位置猜测一个a后,您将确切知道所有ab的确切位置。从那时起,您始终可以在正确的位置使用ab进行猜测。在未知位置,添加一个c,其余d s ...