Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Pentago板上的赢家_Performance_Matlab_Math - Fatal编程技术网

Performance Pentago板上的赢家

Performance Pentago板上的赢家,performance,matlab,math,Performance,Matlab,Math,对于那些不知道Pentago是什么的人来说,这对问题来说并不是那么重要,但只需说你有一个6x6的四象限板就足够了。每个玩家轮流放置一个棋子,然后旋转一个象限。当一名球员连续获得五分(在球员轮换阶段之前或之后)时,比赛获胜 我正在写一个算法来玩许多不同的随机Pentago游戏。然而,由于它是完全随机的,我看不出有什么好办法可以绕过检查,看看是否有人在回合的位置和旋转阶段之间获胜(否则,您可能会意外地旋转获胜的移动)。最后,我打算重写它,使其包含更多的策略,而不是完全随机的,但这是出于统计目的,所以

对于那些不知道Pentago是什么的人来说,这对问题来说并不是那么重要,但只需说你有一个6x6的四象限板就足够了。每个玩家轮流放置一个棋子,然后旋转一个象限。当一名球员连续获得五分(在球员轮换阶段之前或之后)时,比赛获胜

我正在写一个算法来玩许多不同的随机Pentago游戏。然而,由于它是完全随机的,我看不出有什么好办法可以绕过检查,看看是否有人在回合的位置和旋转阶段之间获胜(否则,您可能会意外地旋转获胜的移动)。最后,我打算重写它,使其包含更多的策略,而不是完全随机的,但这是出于统计目的,所以随机性很好(事实上在某些方面非常有用)

不管怎么说,目前我正在用Matlab编程,一个空板看起来像这样

eeeeee
eeeeee
eeeeee
eeeeee
eeeeee
eeeeee
随着游戏的进行,棋盘上会填满
w
,以及
b
。我检查获胜棋盘的方法实际上是通过对返回的“字符串”执行正则表达式检查,遍历每一列和每一行(以及每一条对角线),以查看是否有获胜棋盘

简言之,我的问题是:


是否有更有效的方法来确定Pentago棋盘的赢家?

使用6x6数字数组表示游戏棋盘,0表示空位置,1表示黑色,1表示白色。然后,通过以下方式初始化电路板:

>> board = zeros(6, 6) board = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 您现在可以通过调用
checkBoard
来检查电路板:

>> x = [-1 0 0 0 0 0; -1 0 0 0 0 0; -1 0 0 0 0 0; -1 0 0 0 0 0; -1 0 0 0 0 0; 0 0 0 0 0 0] x = -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 >> checkBoard(x) ans = White wins! >> x = [-1 0 0 0 0 0; -1 0 0 0 0 0; -1 0 0 0 0 0; -1 0 0 0 0 0; -1 0 0 0 0 0; 1 0 0 0 0 0] x = -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 1 0 0 0 0 0 >> checkBoard(x) ans = White wins! >> x = [1 1 1 1 1 0; 0 0 0 0 0 0; 0 0 0 0 0 0; 0 0 0 0 0 0; 0 0 0 0 0 0; 0 0 0 0 0 0] x = 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 >> checkBoard(x) ans = Black wins! >> x = [1 0 0 0 0 0; 0 1 0 0 0 0; 0 0 1 0 0 0; 0 0 0 1 0 0; 0 0 0 0 1 0; 0 0 0 0 0 0] x = 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 >> checkBoard(x) ans = Black wins! >>x=[-10000;-10000;-10000;-10000;-10000;-10000;-10000;-10000;-10000;0000] x= -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 >>棋盘(x) ans= 白人赢了! >>x=[-10000;-10000;-10000;-10000;-10000;-10000;-10000;-10000;10000;10000] x= -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 0 0 0 0 0 1 0 0 0 0 0 >>棋盘(x) ans= 白人赢了! >>x=[11 11 10;0 0 0 0;0 0 0 0;0 0 0 0 0;0 0 0 0 0 0;0 0 0 0 0 0;0 0 0 0 0 0 0] x= 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 >>棋盘(x) ans= 黑人赢了! >>x=[1 0 0 0;0 1 0 0 0;0 0 1 0 0;0 0 0 0 1 0;0 0 0 0 0 1 0;0 0 0 0 0 0 0 0 0] x= 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 >>棋盘(x) ans= 黑人赢了! 编辑:

我提出了两种解决方案:一种是基于卷积(使用函数)的解决方案,另一种是基于5个元素的所有可能字符串的强力索引(类似于)。这是:

卷积:

索引:

出于好奇,我想测量一下这些解决方案的速度和准确性。我创建了4个测试板:-1胜,无胜,1胜,双方都赢(平局)。然后,我为每个板运行每个解决方案10000次,并计时。结果如下:

               |   Calculated winner
---------------+-----------------------
convolution    |  -1     0     1     2
indexing       |  -1     0     1     2
b3 solution    |  -1     0     1    -1

               |   Running time for 10,000x (seconds)
---------------+---------------------------------------
convolution    |  0.4863    0.5305    0.5248    0.4787
indexing       |  0.1706    0.1770    0.1755    0.1889
b3 solution    |  0.6607    1.3958    1.4223    0.7507

请注意,b3的解决方案无法检测抽签。尽管基于卷积的解决方案的代码最短,也最容易实现(我不必手动创建索引列表),但我上面给出的索引解决方案最终是最快的。

此解决方案使用蛮力式方法将董事会与可能获胜的条件进行比较:

function winner = pentago_winner(board)

if connectFive(-1)
    winner = -1;
elseif connectFive(1)
    winner = 1;
else
    winner = 0;
end

    function result = connectFive(player)
        result = find([all(~(board(1:5,:) - ones(5,6) * player)) ...                            % Check top 5 rows
            all(~(board(2:6,:) - ones(5,6) * player)) ...                                       % Check bottom 5 rows
            all(~(board(:,1:5)' - ones(5,6) * player)) ...                                      % Check left 5 columns
            all(~(board(:,2:6)' - ones(5,6) * player)) ...                                      % Check right 5 columns
            all(~([diag(board, 1) diag(board, -1)] - ones(5, 2) * player)) ...                  % Check minor diagonals
            all(~([diag(fliplr(board), 1) diag(fliplr(board), -1)] - ones(5, 2) * player)) ...  % Check minor anti-diagonals
            all(~(board(1:7:29)' - ones(5, 1) * player)) ...                                    % Check first 5 elements of major diagonal
            all(~(board(6:5:29)' - ones(5, 1) * player)) ...                                    % Check last 5 elements of major diagonal
            all(~(board(5:5:25)' - ones(5, 1) * player)) ...                                    % Check first 5 elements of major anti-diagonal
            all(~(board(12:5:32)' - ones(5, 1) * player))], 1) * player;                        % Check last 5 elements of major anti-diagonal
    end

end

编辑:使用Gnovices更新新算法(总共3个对吗?您使用的是filter(),现在使用的是conv2())

新数字:

                     Apus     B3    B3   Gnovice 
                             Old   New   Orig  Conv Index
Player One Wins:        97   197    91    97    97    97 
Player Two Wins:       102   181   114   102   118   118 
Both Players Win:       16     0     0    16     0     0 
Neither Player Win:    785   622   795   785   785   785 
Execution Time:      0.081 0.037 0.144 0.317 0.068 0.036
这太有趣了,无法抗拒。如果没有B3和Gnovice的代码,我的代码将充满错误。据我所知,Gnovice的代码似乎有100%的准确性。B3提交了两个功能,第一个错误地授予了一个获奖者,如果连续有4个,一个空格,还有一个。B3的第二个条目未能在从右上到左下的对角线上检测到赢家。B3也没有考虑到两名球员都有获胜位置的情况。(据我所知,象限旋转可能导致两名玩家同时获胜?)

这是1000块随机板的列表

                     Apus     B3    B3   Gnovice
Player One Wins:       106   207   104   106 
Player Two Wins:       103   180   105   103 
Both Players Win:        6     0     0     6 
Neither Player Win:    785   613   791   785 
Execution Time:      0.082 0.037 0.146 0.322 
Gnovice是第一个达到100%准确率的产品,但它的执行时间最高。B3可能会修改他的代码来修复错误,然后获得最快的代码。我可能会得到一个生活,而不是赛车连接4码对彼此

这是我的密码:

function winner = testboard_apus(board)
answersheet1 = true(6,6);
answersheet1(6,:) = false(1,6);
answersheet2 = true(6,6);
answersheet2(1,:) = false(1,6);
winner = 0;
for player = 1:2
    if      any(sum((board==player) & answersheet1)==5)  ||...
            any(sum((board==player) & answersheet2)==5)  ||...
            any(sum((board'==player) & answersheet1)==5) ||...
            any(sum((board'==player) & answersheet2)==5) ||...
            all(diag(board(1:5,1:5))==player) ||...
            all(diag(board(2:6,2:6))==player) ||...
            all(diag(board(1:5,2:6))==player) ||...
            all(diag(board(2:6,1:5))==player) ||...
            all(diag(board(1:5,5:-1:1))==player) ||...
            all(diag(board(2:6,6:-1:2))==player) ||...
            all(diag(board(1:5,6:-1:2))==player) ||...
            all(diag(board(2:6,5:-1:1))==player)

        winner = winner + player;
    end
end
end
这是司机代码

function testboard_wrapper

total = zeros(4,1);
agree = false(1000,1);
winner = zeros(1000,4);
for i = 1:1000
    board = floor(rand(6)*3);

    t(1) = tic;
    winner(i,1) = testboard_apus(board);
    total(1) = total(1)+toc(t(1));

    board2 = board;
    board2(board2==2) = -1;

    t(2) = tic;
    winner(i,2) = testboard_b3(board2);
    total(2) = total(2)+toc(t(2));

    t(3) = tic;
    winner(i,3) = testboard_b3_2nd(board2);
    total(3) = total(3)+toc(t(3));

    t(4) = tic;
    winner(i,4) = testboard_gnovice(board2);
    total(4) = total(4)+toc(t(4));

    agree(i) = all(winner(i,:)==0) || all(winner(i,:)==1) || all(winner(i,:)==2) ||all(winner(i,:)==3);

end

fprintf('                     Apus     B3    B3   Gnovice\n')
fprintf('Player One Wins:     %5i %5i %5i %5i \n',sum(winner==1))
fprintf('Player Two Wins:     %5i %5i %5i %5i \n',sum(winner==2))
fprintf('Both Players Win:    %5i %5i %5i %5i \n',sum(winner==3))
fprintf('Neither Player Win:  %5i %5i %5i %5i \n',sum(winner==0))
fprintf('Execution Time:      %1.3f %1.3f %1.3f %1.3f \n',total)
end
仅供参考B3这里是一个您的代码未能检测到的示例板

 0     0     0     0     0     2
 1     0     1     0     2     0
 1     2     1     2     1     0
 1     1     2     2     1     0
 0     2     2     0     0     2
 1     1     0     0     1     1
以及

 0     2     2     2     0     2
 1     2     1     2     1     1
 0     0     2     0     0     2
 2     0     1     2     0     0
 2     0     1     0     2     0
 1     0     1     1     1     2

使用预先计算的查找表,可以检测一个播放器在大约18条指令中是否有5条指令。以下例程将一名玩家的所有石头作为输入打包成64位整数:

inline quadrant_t quadrant(uint64_t state, int q) {
  assert(0<=q && q<4);
  return (state>>16*q)&0xffff;
}

// Determine if one side has 5 in a row
inline bool won(side_t side) {
  /* To test whether a position is a win for a given player, we note that
   * there are 3*4*2+4+4 = 32 different ways of getting 5 in a row on the
   * board. Thus, a 64-bit int can store a 2 bit field for each possible
   * method. We then precompute a lookup table mapping each quadrant state
   * to the number of win-possibilities it contributes to. 28 of the ways
   * of winning occur between two boards, and 4 occur between 4, so a sum
   * and a few bit twiddling checks are sufficient to test whether 5 in a
   * row exists. See helper for the precomputation code. */
  uint64_t c = win_contributions[0][quadrant(side,0)]
             + win_contributions[1][quadrant(side,1)]
             + win_contributions[2][quadrant(side,2)]
             + win_contributions[3][quadrant(side,3)];
  return c&(c>>1)&0x55 // The first four ways of winning require contributions from three quadrants
      || c&(0xaaaaaaaaaaaaaaaa<<8); // The remaining 28 ways require contributions from only two
}
内联象限(uint64\t状态,int q){
断言(016*q)&0xffff;
}
//确定一侧是否连续有5个
内联布尔元(侧边){
/*为了测试一个位置是否是一个给定球员的胜利,我们注意到
*有3*4*2+4+4=32种不同的方法可以在屏幕上获得一行5
*因此,64位int可以为每个可能的值存储一个2位字段
*方法。然后,我们预计算一个映射每个象限状态的查找表
*对获胜可能性的贡献。28种方式
*赢的概率发生在两个棋盘之间,赢的概率发生在4个棋盘之间,所以是一个总和
*还有一些无聊的c
 0     0     0     0     0     2
 1     0     1     0     2     0
 1     2     1     2     1     0
 1     1     2     2     1     0
 0     2     2     0     0     2
 1     1     0     0     1     1
 0     2     2     2     0     2
 1     2     1     2     1     1
 0     0     2     0     0     2
 2     0     1     2     0     0
 2     0     1     0     2     0
 1     0     1     1     1     2
inline quadrant_t quadrant(uint64_t state, int q) {
  assert(0<=q && q<4);
  return (state>>16*q)&0xffff;
}

// Determine if one side has 5 in a row
inline bool won(side_t side) {
  /* To test whether a position is a win for a given player, we note that
   * there are 3*4*2+4+4 = 32 different ways of getting 5 in a row on the
   * board. Thus, a 64-bit int can store a 2 bit field for each possible
   * method. We then precompute a lookup table mapping each quadrant state
   * to the number of win-possibilities it contributes to. 28 of the ways
   * of winning occur between two boards, and 4 occur between 4, so a sum
   * and a few bit twiddling checks are sufficient to test whether 5 in a
   * row exists. See helper for the precomputation code. */
  uint64_t c = win_contributions[0][quadrant(side,0)]
             + win_contributions[1][quadrant(side,1)]
             + win_contributions[2][quadrant(side,2)]
             + win_contributions[3][quadrant(side,3)];
  return c&(c>>1)&0x55 // The first four ways of winning require contributions from three quadrants
      || c&(0xaaaaaaaaaaaaaaaa<<8); // The remaining 28 ways require contributions from only two
}