Javascript:卡在两个皇后的对角线验证上,以及它们是否可以互相攻击

问题描述

问题: 两个皇后在棋盘上不能互相攻击的位置总数是多少?

方法我的逻辑是创建两个皇后的变量,提供它们在棋盘上所在位置的坐标。从那里,将一个皇后(白皇后)移动到棋盘上的每个空缺位置,并在每个新位置循环中通过验证另一位皇后(黑皇后)是否可以通过首先确认他们是否在棋盘上来攻击它相同的列或行。然后对于从对角线向下和向右开始的对角线攻击,使用攻击坐标变量(vx 和 vy 值)在每次检查是否在对角线移动时向下和向右移动,如果黑后结束与白皇后在离开棋盘之前具有相同的坐标。变量 vx 和 vy 在每个验证路径后特意设置为 -1 以“脱离板”,因此它不会根据循环完成时停止的数字意外触发验证。

问题出在哪里:代码一直运行到 //validates 对角线向下/向右攻击部分的 else if 行(第 39 行+)。我在那里输入什么作为真实语句似乎并不重要,结果冻结了应用程序并迫使我使用 break 命令摆脱它。如果我注释掉对角攻击部分,程序(按原样)将运行并返回值 49。我试图得到 42 的答案。7 的差异是对角向下/向右攻击模式时黑皇后在左上角 (0,0) 位置。

一旦解决我知道数组会更容易,但在这一点上,我知道有一些变化可以解除这个问题,如果有人可以告诉我我缺少什么,那么其他三个对角攻击模式是复制/粘贴对角攻击部分,然后更改变量的 + 和 - 符号以更改攻击后的对角移动。每次白皇后在黑皇后的新坐标上遍历棋盘时,都会从那里添加黑皇后运动的 while 循环。

非常感谢您的帮助。非常感谢您的时间!

<!DOCTYPE html>
<html>
<body>

<h2>Answer To Two Queens Question</h2>    

<p id="demo"></p>

<script>
//total number of positions the two queens cannot attack each other
var n = 0;

//white queen
var x1 = 0;
var y1 = 0;

//black queen
var x2 = 0;
var y2 = 0;

//validation attack path
var vx = -1;
var vy = -1;

//moves white queen down one row after iterating through all available options
while (y1 <= 7) {

//moves white queen across an entire row
while (x1 <= 7) {
    //skips validation of attack patterns if queens are on the same square on the board (invalid scenario)
    if (x1==x2 && y1==y2){
        x1 = x1 + 1;
    //validates horizontal attack (left & right)
    } else if (x1 == x2) {
        x1 = x1 + 1;
    //validates vertical attack (up & down)
    } else if (y1 == y2){
        x1 = x1 + 1; 
    //validates diagonal down/right attack
    } else if (1 == 1) {
        //sets validation coordinates to be the same as the black queen
        vx = x2;
        vy = y2; 
        //iterates through diagonal down/right attack coordinates to see if it matches same coordinates of white queen
        while(vx <= 7 && vy <= 7){
            if (x2 + vx == x1 && y2 + vy == y1) {
                x1 = x1 + 1;
            } else {
                vx = vx + 1;
                vy = vy + 1;
            }
        }
        vx = -1;
        vy = -1;
    //if all validations fail,count towards total count where they cannot attack
    } else {
        n = n + 1;
        x1 = x1 + 1;
    }
}
y1 = y1 + 1;
x1 = 0;
}

document.getElementById("demo").innerHTML = "The number positions where two queens cannot attack each other is " + n;
</script>

</body>
</html>

解决方法

继续评论,此解决方案将“位置”视为 0 到 63 之间的整数,其中行和列可以使用“算术级数”逻辑从中派生。行可以由地板部分除以 8 得出。列可以由 8 上的模数得出。

这样只需要两个循环。使用双循环,以便将每个 Queen1 (Q1) 位置与 Q2 的位置进行比较。就像你的 alg 指定的那样,当 Q1 和 Q2 占据同一个正方形时,有一个条件可以排除。其余逻辑在代码注释中解释。

与您的算法的显着区别在于,此解决方案试图解决可以攻击的时间。当仓位不能建立时,返回值必须处理,通过推演。

免责声明:这可能不是解决方案,因为 OP 事先不知道正确的返回值。这只是一个代码尝试。

// What is the total number of positions that two queens can exist on a chess board where they cannot attack each other?
function answer() {

    var Q1;
    var Q2;
    var cnt = 0; // count of when they can attack each other
    
    for (Q1 = 0; Q1 < 64; Q1++) {
        //console.log(Q1);
        
        
        let Q1_y = Math.floor(Q1 / 8); // 0..7 ~ 0,8..15 ~ 1,and so on
        let Q1_x = Q1 % 8;
        
        // console.log(Q1_x + "," + Q1_y);
        
        for (Q2 = 0; Q2 < 64; Q2++) {
            
            let Q2_y = Math.floor(Q2 / 8); // 0..7 ~ 0,and so on
            let Q2_x = Q2 % 8;
            
            if (Q1 != Q2) {
                // rule out both on same square
            
                let canAttack = false;
                // Now determine if on same X
                if (Q1_x == Q2_x) {
                    canAttack = true;
                }
                
                // Now determine if on same Y
                if (Q1_y == Q2_y) {
                    canAttack = true;
                }
                
                // Now determine if on same diagnoal
                let diag = (Math.abs(Q1_x - Q2_x) / Math.abs(Q1_y - Q2_y)) == 1;
                
                if (diag) {
                    canAttack = true;
                }
                
                // Update count for this square combo
                
                if (canAttack) {
                    cnt++;
                }
                
            }
            
        }
    }
    
    // console.log (cnt);
    
    return ((64 * 64) - 64) - cnt; // 64*64 total space pairs,minus the 64 times they are on same square,minus the number of times they *can* attack
    
    
    
}

console.log (answer());

,

为了好玩,这里是另一个问题..

在这种情况下,使用位板进行国际象棋编程的标准方法用于表示棋子的可能移动。也就是说,Uint64 数字用作位掩码来表示车、象或后的可能移动。由于棋盘上有 64 个方格,因此需要 64 个 Uint64 位掩码来表示棋子在每个方格上的可能移动。

为了帮助形象化这一点,下面的脚本打印出方格“d3”(它是棋子数组中 64 个方格中的第 19 个方格)的车、象和皇后位板。

一旦位板建成,确定两个皇后是否互相攻击的工作就变得微不足道了,因为这只是将第一个皇后的移动位板与代表第二个皇后所在方格的位板进行逻辑与运算,如果结果是 0,那么他们就没有互相攻击。

顺便说一句,这种方法可以得到 2576 种不互相攻击的皇后组合...

// Establish array with each bitboard representing the square on the board
// that the bitboard index represents.
let squares = new BigUint64Array( 64 ).map( ( v,i ) => 1n << BigInt( i ) );

// Generate possible moves for Rooks and Bishops for each square
// that they can occupy.
let rookMoves = new BigUint64Array( 64 );
let bishopMoves = new BigUint64Array( 64 );

for ( pieceRank = 0; pieceRank < 8; pieceRank++ ) {
  for ( pieceFile = 0; pieceFile < 8; pieceFile++ ) {
    let squareIndex = pieceRank * 8 + pieceFile;
    let rookMap = 0n;
    let bishopMap = 0n;
    for ( let r = 0; r < 8; r++ ) {
      for ( let f = 0; f < 8; f++ ) {
        let rf = r * 8 + f;
        if ( ( r === pieceRank || f === pieceFile ) && rf !== squareIndex ) {
          rookMap |= squares[ rf ];
        }
        if ( ( Math.abs( r - pieceRank ) === Math.abs( f - pieceFile ) ) && rf !== squareIndex ) {
          bishopMap |= squares[ rf ];
        }
      }
    }
    rookMoves[ squareIndex ] = rookMap;
    bishopMoves[ squareIndex ] = bishopMap;
  }
}  
 
// Generate the possible moves for Queens for each square that
// they can occupy.  This is done my looping through the Rook
// moves and simply ORing with the bishop moves.
let queenMoves = rookMoves.map( ( v,i ) => v | bishopMoves[ i ] );

// Helper function to print out the bitmap as a board,where 'X' 
// represents a bit that is set to 1 and '-' a bit that is set to '0'.
function printBitMap( bitBoard ) {
  let bm = '';
  for ( rank = 7; 0 <= rank; rank-- ) {
    for ( file = 0; file < 8; file++ ) {
      bm += bitBoard & squares[ rank * 8 + file ] ? ' X ' : ' - ';
    }
    bm += '\n';
  }
  return bm + '\n';
}

// Let's print the bitmaps for the rook,bishop,and queen at square d3,// which is rank 2 ( range 0 - 7 ) file 3,or 2 * 8 + 3 which is square
// index 19.
console.log( 'Rook,Bishop,and Queen moves from square d3:' );
console.log( printBitMap( rookMoves[ 19 ] ) );
console.log( printBitMap( bishopMoves[ 19 ] ) );
console.log( printBitMap( queenMoves[ 19 ] ) );

// Now that the bitmaps are set up,the effort is simple... Loop through
// all combinations of two queens on the board...
let nonIntersectCount = 0;
for ( let Q1square = 0; Q1square < 64; Q1square++ ) {
  for ( let Q2square = 0; Q2square < 64; Q2square++ ) {
    // ...and if the queens are not on the same square and the intersection of
    // the possible moves for Q1 with the Q2 square is 0 bits,then we have
    // a situation where the queens are not attacking each other... 
    if ( Q1square !== Q2square && ( queenMoves[ Q1square ] & squares[ Q2square ] ) === 0n ) {
      nonIntersectCount++;
    }
  }
}

console.log( 'For every combination of 2 queens on a board,the number of combinations where they do not attack each other is:' );
console.log( nonIntersectCount );

另请注意,截至 2021 年 1 月,BigUint64Array 具有广泛的浏览器支持,但 Safari 除外。既然如此,如果 Safari 支持对手头的问题至关重要,那么人们可能需要考虑使用 Uint32Array 重新设计此解决方案...