开发邮箱国际象棋引擎“GenerateAllMoves”未按预期工作

问题描述 投票:0回答:1

GenerateAllMoves 功能不起作用。

代码:

const BOARD_IDX = 120;

// black pieces
const W_P = 1;
const W_R = 2;
const W_B = 3;
const W_N = 4;
const W_Q = 5;
const W_K = 6;

// 블랙의 피스들
const B_P = -W_P;
const B_R = -W_R;
const B_B = -W_B;
const B_N = -W_N;
const B_Q = -W_Q;
const B_K = -W_K;

const RAND = 100; // padding
const EMPTY = 0; // blank

// remainder constant
const A8 = 21, B8 = 22, C8 = 23, D8 = 24, E8 = 25, F8 = 26, G8 = 27, H8 = 28,
    A7 = 31, B7 = 32, C7 = 33, D7 = 34, E7 = 35, F7 = 36, G7 = 37, H7 = 38,
    A2 = 81, B2 = 82, C2 = 83, D2 = 84, E2 = 85, F2 = 86, G2 = 87, H2 = 88,
    A1 = 91, B1 = 92, C1 = 93, D1 = 94, E1 = 95, F1 = 96, G1 = 97, H1 = 98;

const WHITE_PROMOTES = [A8, B8, C8, D8, E8, F8, G8, H8];
const BLACK_PROMOTES = [A1, B1, C1, D1, E1, F1, G1, H1];

const WHITE_NEAR_PROMOTES = [A7, B7, C7, D7, E7, F7, G7, H7];
const BLACK_NEAR_PROMOTES = [A2, B2, C2, D2, E2, F2, G2, H2];

const WHITE_PAWN = [A2, B2, C2, D2, E2, F2, G2, H2];
const BLACK_PAWN = [A7, B7, C7, D7, E7, F7, G7, H7];

// Default location on the board
const InitialPosition = [
    RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND,
    RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND,
    RAND, B_R, B_N, B_B, B_Q, B_K, B_B, B_N, B_R, RAND,
    RAND, B_P, B_P, B_P, B_P, B_P, B_P, B_P, B_P, RAND,
    RAND, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, RAND,
    RAND, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, RAND,
    RAND, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, RAND,
    RAND, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, RAND,
    RAND, W_P, W_P, W_P, W_P, W_P, W_P, W_P, W_P, RAND,
    RAND, W_R, W_N, W_B, W_Q, W_K, W_B, W_N, W_R, RAND,
    RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND,
    RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND, RAND
];

// board 
let board = InitialPosition;

// state
let game = {};

game.turn = 1;
game.enPassant = EMPTY;
game.castlings = [true, true, true, true];
game.kingLocations = [E1, E8];

game.undos = [];

// Move encoding
class Move {
    constructor(from, to, flags, isCapture) {
        this.move = (from & 0xFF) | ((to & 0xFF) << 8) | ((Math.abs(flags) & 0xFF) << 16) | (((isCapture ? 1 : 0) & 0xFF) << 32);
    }
    getFrom(){
        return this.move & 0xFF;
    }
    getTo(){
        return (this.move >> 8) & 0xFF;
    }
    getFlags(){
        return (this.move >> 12) & 0xFF;
    }
    isCapture(){
        return ((this.move >> 32) & 1) === 1;
    }
    isCastling(){
        let rook;
        return [(
            this.getFrom() === E8 && (
                (this.getTo() === G8 && (rook = new Move(H8, F8, 0, false))) ||
                (this.getTo() === C8 && (rook = new Move(A8, D8, 0, false)))
            ) ||
            this.getFrom() === E1 && (
                (this.getTo() === G1 && (rook = new Move(H1, F1, 0, false))) ||
                (this.getTo() === C1 && (rook = new Move(A1, D1, 0, false)))
            )
        ), rook];
    }
    is2Square(){
        return Math.abs(this.getTo() - this.getFrom()) === 20;
    }
}

// Undo encoding
class Undo {
    constructor(){}
    save(){
        this.board = board;
        this.enPassant = game.enPassant;
        this.castlings = game.castlings;
        this.kingLocations = game.kingLocations;
        game.undos.push(this);
    }
    undo(){
        let state = game.undos.pop();
        
        board = state.board;
        game.enPassant = state.enPassant;
        game.castlings = state.castlings;
        game.kingLocations = state.kingLocations;
    }
}

// tool
function pieceMapper(piece){
    const pieceMapping = {
        'P': W_P, 'R': W_R, 'N': W_N, 'B': W_B, 'Q': W_Q, 'K': W_K,
        'p': B_P, 'r': B_R, 'n': B_N, 'b': B_B, 'q': B_Q, 'k': B_K 
    };
    return pieceMapping[piece];
}

function pieceReverseMapper(piece){
    const reverseMapping = {
        [W_P]: 'P', [W_R]: 'R', [W_N]: 'N', [W_B]: 'B', [W_Q]: 'Q', [W_K]: 'K',
        [B_P]: 'p', [B_R]: 'r', [B_N]: 'n', [B_B]: 'b', [B_Q]: 'q', [B_K]: 'k'
    };
    return reverseMapping[piece] || '';
}

function pieceColor(piece){
    return Math.abs(piece) === piece;
}

function squareMapper(idx){
    const range = [];
    for(let i = 21; i <= 91; i += 10){
        range.push(i);
    }

    const mapping = {
        1: 'a',
        2: 'b',
        3: 'c',
        4: 'd',
        5: 'e',
        6: 'f',
        7: 'g',
        8: 'h',
    };

    let pair = '';
    for(let i = 0; i < range.length; i++){
        if(idx >= range[i] && idx <= range[i] + 7){
            pair = mapping[i + 1] + (idx - range[i] + 1);
            break;
        }
    }

    return pair;
}

function squareReverseMapper(sq){
    return 8 * (sq[0].charCodeAt(0) - 97) + (parseInt(sq[1], 10) - 1);
}

function loadKingLocations(){
    for(let i = 0; i < 64; i++){
        if(board[21+i] === W_K) game.kingLocations[0] = i;
        else if(board[21+i] === B_K) game.kingLocations[1] = i;
    }
}

// all possible movements

function GenerateWhitePieceMoves(idx){
    let moves = [];
    switch(board[idx]){
        case W_P: { // Pawn
            if(WHITE_NEAR_PROMOTES.includes(idx)){
                let promoteSq;
                let isCapture = true;
                if(
                    (
                        board[idx - 10] === EMPTY && 
                        (promoteSq = idx - 10) &&
                        (isCapture = false)
                    ) || (
                        board[idx - 9] !== RAND && board[idx - 9] !== EMPTY && 
                        !pieceColor(board[idx - 9]) &&  
                        (promoteSq = idx - 9)
                    ) || (
                        board[idx - 11] !== RAND && board[idx - 11] !== EMPTY &&
                        !pieceColor(board[idx - 11]) &&
                        (promoteSq = idx - 11)
                    )
                ){
                    moves.push(new Move(idx, promoteSq, W_Q, isCapture));
                    moves.push(new Move(idx, promoteSq, W_N, isCapture));
                    moves.push(new Move(idx, promoteSq, W_R, isCapture));
                    moves.push(new Move(idx, promoteSq, W_B, isCapture));
                }
            } else {
                if(board[idx - 10] === EMPTY){
                    moves.push(new Move(idx, idx - 10, 0, false));
                    if(WHITE_PAWN.includes(idx)){
                        if(board[idx - 20] === EMPTY){
                            moves.push(new Move(idx, idx - 20, 0, false));
                        }
                    }
                    let captureSq;
                    if(
                        (
                            board[idx - 9] !== RAND && (
                                (board[idx - 9] !== EMPTY && !pieceColor(board[idx - 9])) || 
                            (
                                game.enPassant !== EMPTY && (idx - 9) === game.enPassant
                            )) && 
                            (captureSq = idx - 9)
                        ) || (
                            board[idx - 11] !== RAND && (
                                (board[idx - 11] !== EMPTY && !pieceColor(board[idx - 11])) || 
                            (
                                game.enPassant !== EMPTY && (idx - 11) === game.enPassant
                            )) && 
                            (captureSq = idx - 11)
                        )
                    ){
                        moves.push(new Move(idx, captureSq, 0, true));
                    }
                }
            }
            break;
        }
        case W_R: { // Rook
            let sq = board[idx];
            [+1, -1, +0.1, -0.1].forEach(element => {
                rook: for(let i = 10; i < 80; i+=10){
                    sq = board[idx + (i*element)];
                    if(sq === RAND) break rook;
                    if(sq !== EMPTY){
                        if(!pieceColor(sq)){
                            moves.push(new Move(idx, idx + i, 0, true));
                        }
                        break rook;
                    }
                    moves.push(new Move(idx, idx + i, 0, false));
                }
            });
            break;
        }
        case W_B: { // Bishop
            let sq = board[idx];
            [+9, +11, -11, -9].forEach(element => {
                bishop: for(let i = 1; i < 8; i++){
                    sq = board[idx + (i*element)];
                    if(sq === RAND) break bishop;
                    if(sq !== EMPTY){
                        if(!pieceColor(sq)){
                            moves.push(new Move(idx, idx + i, 0, true));
                        }
                        break bishop;
                    }
                    moves.push(new Move(idx, idx + i, 0, false));
                }
            });
            break;
        }
        case W_N: { // Knight
            const knightMoves = [
                -21, -19, -12, -8,
                8, 12, 19, 21
            ];

            for(let i = 0; i < knightMoves.length; i++){
                let sq = board[idx + knightMoves[i]];

                if(sq === RAND) continue;
                if(sq === EMPTY || !pieceColor(sq)){
                    moves.push(new Move(idx, idx + knightMoves[i], 0, sq !== EMPTY));
                }
            }
            break;
        }
        case W_Q: { // Queen
            let sq = board[idx];
            [+1, -1, +0.1, -0.1, +0.9, +0.11, -0.11, -0.9].forEach(element => {
                queen: for(let i = 10; i < 80; i+=10){
                    sq = board[idx + (i*element)];
                    if(sq === RAND) break queen;
                    if(sq !== EMPTY){
                        if(!pieceColor(sq)){
                            moves.push(new Move(idx, idx + i, 0, true));
                        }
                        break queen;
                    }
                    moves.push(new Move(idx, idx + i, 0, false));
                }
            });
            break;
        }
        case W_K: { // King
            const kingMoves = [+10, -10, +1, -1, +9, +11, -11, -9];

            for(let i = 0; i < kingMoves.length; i++){
                let sq = board[idx + kingMoves[i]];

                if(sq === RAND) continue;
                if(sq === EMPTY || !pieceColor(sq)){
                    moves.push(new Move(idx, idx + kingMoves[i], 0, sq !== EMPTY));
                }
            }
            break;
        }
    }
    return moves;
}

function GenerateBlackPieceMoves(idx){
    let moves = [];
    switch(board[idx]){
        case B_P: { // Pawn
            if(BLACK_NEAR_PROMOTES.includes(idx)){
                let promiteSq;
                let isCapture = true;
                if(
                    (
                        board[idx + 10] === EMPTY && 
                        (promiteSq = idx + 10) &&
                        (isCapture = false)
                    ) || (
                        board[idx + 9] !== RAND && board[idx + 9] !== EMPTY && 
                        pieceColor(board[idx + 9]) &&  
                        (promiteSq = idx + 9)
                    ) || (
                        board[idx + 11] !== RAND && board[idx + 11] !== EMPTY &&
                        pieceColor(board[idx + 11]) &&
                        (promiteSq = idx + 11)
                    )
                ){
                    moves.push(new Move(idx, promiteSq, B_Q, isCapture));
                    moves.push(new Move(idx, promiteSq, B_N, isCapture));
                    moves.push(new Move(idx, promiteSq, B_R, isCapture));
                    moves.push(new Move(idx, promiteSq, B_B, isCapture));
                }
            } else {
                if(board[idx + 10] === EMPTY){
                    moves.push(new Move(idx, idx + 10, 0, false));
                    if(BLACK_PAWN.includes(idx)){
                        if(board[idx + 20] === EMPTY){
                            moves.push(new Move(idx, idx + 20, 0, false));
                        }
                    }
                    let captureSq;
                    if(
                        (
                            board[idx + 9] !== RAND && (
                                (board[idx + 9] !== EMPTY && pieceColor(board[idx + 9])) || 
                            (
                                game.enPassant !== EMPTY && (idx + 9) === game.enPassant
                            )) && 
                            (captureSq = idx + 9)
                        ) || (
                            board[idx + 11] !== RAND && (
                                (board[idx + 11] !== EMPTY && pieceColor(board[idx + 9])) || 
                            (
                                game.enPassant !== EMPTY && (idx + 11) === game.enPassant
                            )) && 
                            (captureSq = idx + 11)
                        )
                    ){
                        moves.push(new Move(idx, captureSq, 0, true));
                    }
                }
            }
            break;
        }
        case B_R: { // Rook
            let sq = board[idx];
            [+1, -1, +0.1, -0.1].forEach(element => {
                rook: for(let i = 10; i < 80; i+=10){
                    sq = board[idx + (i*element)];
                    if(sq === RAND) break rook;
                    if(sq !== EMPTY){
                        if(pieceColor(sq)){
                            moves.push(new Move(idx, idx + i, 0, true));
                        }
                        break rook;
                    }
                    moves.push(new Move(idx, idx + i, 0, false));
                }
            });
            break;
        }
        case B_B: { // Bishop
            let sq = board[idx];
            [+9, +11, -11, -9].forEach(element => {
                bishop: for(let i = 1; i < 8; i++){
                    sq = board[idx + (i*element)];
                    if(sq === RAND) break bishop;
                    if(sq !== EMPTY){
                        if(pieceColor(sq)){
                            moves.push(new Move(idx, idx + i, 0, true));
                        }
                        break bishop;
                    }
                    moves.push(new Move(idx, idx + i, 0, false));
                }
            });
            break;
        }
        case B_N: { // Knight 
            const knightMoves = [
                -21, -19, -12, -8,
                8, 12, 19, 21
            ];

            for(let i = 0; i < knightMoves.length; i++){
                let sq = board[idx + knightMoves[i]];

                if(sq === RAND) continue;
                if(sq === EMPTY || pieceColor(sq)){
                    moves.push(new Move(idx, idx + knightMoves[i], 0, sq !== EMPTY));
                }
            }
            break;
        }
        case B_Q: { // Queen
            let sq = board[idx];
            [+1, -1, +0.1, -0.1, +0.9, +0.11, -0.11, -0.9].forEach(element => {
                queen: for(let i = 10; i < 80; i+=10){
                    sq = board[idx + (i*element)];
                    if(sq === RAND) break queen;
                    if(sq !== EMPTY){
                        if(pieceColor(sq)){
                            moves.push(new Move(idx, idx + i, 0, true));
                        }
                        break queen;
                    }
                    moves.push(new Move(idx, idx + i, 0, false));
                }
            });
            break;
        }
        case B_K: { // King
            const kingMoves = [+10, -10, +1, -1, +9, +11, -11, -9];

            for(let i = 0; i < kingMoves.length; i++){
                let sq = board[idx + kingMoves[i]];

                if(sq === RAND) continue;
                if(sq === EMPTY || pieceColor(sq)){
                    moves.push(new Move(idx, idx + kingMoves[i], 0, sq !== EMPTY));
                }
            }
            break;
        }
    }
    return moves;
}

// Is an attack possible
function isWhiteAttacked(sq){
    const blackPieces = [B_P, B_R, B_B, B_N, B_Q, B_K];
    const piece = board[sq];

    for(let pieceType of blackPieces){
        board[sq] = pieceType;

        const moves = GenerateBlackPieceMoves(sq);
        for(let move of moves){
            if(board[move.getTo()] !== RAND && !pieceColor(board[move.getTo()])){
                board[sq] = piece;
                return true;
            }
        }
    }

    board[sq] = piece;
    return false;
}

function isBlackAttacked(sq){
    const whitePieces = [W_P, W_R, W_B, W_N, W_Q, W_K];
    const piece = board[sq];

    for(let pieceType of whitePieces){
        board[sq] = pieceType;

        const moves = GenerateWhitePieceMoves(sq);
        for(let move of moves){
            if(board[move.getTo()] !== RAND && pieceColor(board[move.getTo()])){
                board[sq] = piece;
                return true;
            }
        }
    }

    board[sq] = piece;
    return false;
}

// All of White's moves (including how many his opponent can check)
function GenerateWhiteMoves(){
    let moves = [];
    if(
        game.castlings[0] && 
        board[G8] === EMPTY && 
        board[F8] === EMPTY && 
        !isBlackAttacked(E1) && 
        !isBlackAttacked(G1) && 
        !isBlackAttacked(F1)
    ){
        moves.push(new Move(E1, G1, 0, false));
    }
    if(
        game.castlings[1] && 
        board[D1] === EMPTY && 
        board[C1] === EMPTY && 
        board[B1] === EMPTY &&  
        !isBlackAttacked(E1) && 
        !isBlackAttacked(D1) && 
        !isBlackAttacked(C1) && 
        !isBlackAttacked(B1)
    ){
        moves.push(new Move(E1, C1, 0, false));
    }
    for(let i = 0; i < 99; i++){
        if(board[21+i] === RAND || board[21+i] === EMPTY) continue;
        if(pieceColor(board[21+i])){
            let pieceMoves = GenerateWhitePieceMoves(21+i);
            moves.push(...pieceMoves);
        }
    }
    return moves;
}

// All of Black's moves (including how many his opponent can check)
function GenerateBlackMoves(){
    let moves = [];
    if(
        game.castlings[2] && 
        board[G8] === EMPTY && 
        board[F8] === EMPTY &&  
        !isWhiteAttacked(E8) && 
        !isWhiteAttacked(G8) && 
        !isWhiteAttacked(F8)
    ){
        moves.push(new Move(E8, G8, 0, false));
    }
    if(
        game.castlings[3] && 
        board[D8] === EMPTY && 
        board[C8] === EMPTY && 
        board[B8] === EMPTY &&  
        !isWhiteAttacked(E8) && 
        !isWhiteAttacked(D8) && 
        !isWhiteAttacked(C8) && 
        !isWhiteAttacked(B8)
    ){
        moves.push(new Move(E8, C8, 0, false));
    }
    for(let i = 0; i < 99; i++){
        if(board[21+i] === RAND || board[21+i] === EMPTY) continue;
        if(!pieceColor(board[21+i])){
            let pieceMoves = GenerateBlackPieceMoves(21+i);
            moves.push(...pieceMoves);
        }
    }
    return moves;
}

// Create all movements according to the turn
function GenerateAllMoves(){
    return game.turn ? GenerateWhiteMoves() : GenerateBlackMoves()
}

// create movement
function MakeWhiteMove(move){
    let from = move.getFrom();
    let to = move.getTo();
    let castling = move.isCastling();
    let flag = move.getFlags();
    console.log(squareMapper(from), squareMapper(to));

    if(board[from] === W_K && castling[0]){
        board[to] = W_K;
        board[from] = EMPTY;
        board[castling[1].getTo()] = W_R;
        board[castling[1].getFrom()] = EMPTY;
    } else if(flag !== EMPTY){
        board[to] = flag;
        board[from] = EMPTY;
    } else {
        board[to] = board[from];
        board[from] = EMPTY;
        if(board[to] === W_P && move.is2Square()){
            game.enPassant = to - 10;
        }
    }

    new Undo().save();
}

function MakeBlackMove(move){
    let from = move.getFrom();
    let to = move.getTo();
    let castling = move.isCastling();
    let flag = move.getFlags();

    if(castling[0]){
        board[to] = B_K;
        board[from] = EMPTY;
        board[castling[1].getTo()] = B_R;
        board[castling[1].getFrom()] = EMPTY;
    } else if(flag !== EMPTY){
        board[to] = flag;
        board[from] = EMPTY;
    } else {
        board[to] = board[from];
        board[from] = EMPTY;
        if(board[to] === B_P && move.is2Square()){
            game.enPassant = to + 10;
        }
    }

    new Undo().save();
}

// FEN
function fenToMailbox(fen){
    const [position, turn, castling, enPassant] = fen.split(' ');
  
    // Initializing mailbox array
    const mailboxBoard = new Array(BOARD_IDX).fill(EMPTY);
    const boardRanks = position.split('/');
  
    let index = 21;
    boardRanks.forEach(rank => {
        for(let i = 0; i < rank.length; i++){
            const symbol = rank[i];
            if(isNaN(+symbol)){ // If the symbol is not a number
                mailboxBoard[index] = pieceMapper(symbol);
                index++;
            } else {
                index += parseInt(symbol, 10);
            }
        }
        index += 2;
    });
  
    // Filling the padding space
    for(let i = 0; i < 10; i++){
        // top
        mailboxBoard[i] = RAND;
        mailboxBoard[10 + i] = RAND;

        // bottom
        mailboxBoard[100 + i] = RAND;
        mailboxBoard[110 + i] = RAND;
    }
    for(let i = 0; i < 100; i = i + 10){
        // left
        mailboxBoard[20+i] = RAND;

        // right
        mailboxBoard[29+i] = RAND;
    }
    
    game.turn = turn === "w" ? 1 : 0;
    game.enPassant = enPassant === '-' ? EMPTY : squareReverseMapper(enPassant);
    loadKingLocations();

    return mailboxBoard;
}
  
function mailboxToFen(mailboxBoard){
    let fen = '';
    let emptySquares = 0;
  
    for(let i = 21; i < 99; i++){
        const piece = mailboxBoard[i];
    
        if(piece === RAND){
            continue; // Ignore border cells
        }

        if(piece === EMPTY){
            emptySquares++;
        } else {
            if(emptySquares > 0){
                fen += emptySquares;
                emptySquares = 0;
            }
            fen += pieceReverseMapper(piece);
        }

        if(i % 10 === 8){ // end of rank
            if(emptySquares > 0){
                fen += emptySquares;
                emptySquares = 0;
            }
            if(i < 98){
                fen += '/';
            }
            i += 2; // Skip border cells
        }
    }
  
    fen += " "+(game.turn ? "w" : "b");

    // todo: Additional FEN information (castling, en passant, etc.) should be added here.
    // For now we simply transform the positions of the pieces.

    return fen;
}

const fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
const mailboxBoard = fenToMailbox(fen);
board = mailboxBoard;


let loop = 100000;
let startTime = performance.now()
for(let i = 1; i <= loop; i++){
    GenerateAllMoves();
}
let endTime = performance.now()
console.log((endTime - startTime)/loop);

GenerateAllMoves().forEach(move => {
    console.log(squareMapper(move.getFrom()), squareMapper(move.getTo()));
})

我运行了这段代码,但结果很奇怪。

当前结果:

g1 f1
g1 e1
g2 f2
g2 e2
g3 f3
g3 e3
g4 f4
g4 e4
g5 f5
g5 e5
g6 f6
g6 e6
g7 f7
g7 e7
g8 f8
g8 e8
h2 f1
h2 f3
h5
h5
h7 f6
h7 f8

预期结果:

a2a3
a2 a4
b2 b3
b2 b4
c2 c3
c2 c4
d2 d3
d2 d4
e2 e3
e2 e4
f2 f3
f2 f4
g2 g3
g2 g4
小时2小时3
小时2小时4
b1 a3
b1 c3
g1 f3
g1 h3

我是初学者,我不可能修复这个错误。请帮助我..

javascript arrays chess
1个回答
0
投票

一个问题是你的

squareMapping
功能

据我了解您的代码,具有相同单位位置的所有索引(=最后一位数字,例如

21
31
41
,...)应该位于同一列中(即所有
A
21
31
...)但是用你的代码

pair = mapping[i + 1] + ...

您实际上使其取决于十年位置(=第一个数字,例如

21
22
23
)。因为
i
在范围内计数,即如果您的
idx == 81
位于
81
91
之间,您的
i
将是
6
,因此您将拾取字母
g
而不是
a

而且你也错误地计算了你的行,因为当你这样做时

pair = ... + (idx - range[i] + 1)

您实际上是让行依赖于列。据我了解您的代码,

idx
例如
81
83
应该位于同一行(即第2行),但根据您的计算,
81
将位于第
81 - 81 + 1 == 1
行(这是错误的)自己的)并且
83
将位于
83 - 81 + 1 == 3
行,这也是错误的...

所以计算平方映射的正确方法应该如下

//the column only depends on the last digit, 1 = a, 2 = b, 3 = c ...
let column = mapping[idx % 10];  
//the row only depends on the first digit, 9x = 1, 8x = 2, 7x= 3, ... 
let row = 10 - Math.floor(idx / 10);
pair = `${column}${row}`;

如果你这样做,你的算法会打印出正确的动作(至少对于前几块,没有检查全部)

© www.soinside.com 2019 - 2024. All rights reserved.