Skip to content

Commit

Permalink
#319: add null move functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
ppeloton committed Mar 18, 2024
1 parent 21d8d08 commit 6ee8c59
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 10 deletions.
9 changes: 9 additions & 0 deletions __tests__/nullmove.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Chess } from '../src/chess'

test('null move', () => {
const fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
const next = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1'
const chess = new Chess(fen)
chess.move('--')
expect(chess.fen()).toBe(next)
})
60 changes: 50 additions & 10 deletions src/chess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const FLAGS: Record<string, string> = {
PROMOTION: 'p',
KSIDE_CASTLE: 'k',
QSIDE_CASTLE: 'q',
NULL_MOVE: 'nm',
}

// prettier-ignore
Expand All @@ -123,6 +124,7 @@ const BITS: Record<string, number> = {
PROMOTION: 16,
KSIDE_CASTLE: 32,
QSIDE_CASTLE: 64,
NULL_MOVE: 128,
}

/*
Expand Down Expand Up @@ -265,6 +267,8 @@ const SECOND_RANK = { b: RANK_7, w: RANK_2 }

const TERMINATION_MARKERS = ['1-0', '0-1', '1/2-1/2', '*']

const SAN_NULLMOVE = '--'

// Extracts the zero-based rank of an 0x88 square.
function rank(square: number): number {
return square >> 4
Expand Down Expand Up @@ -1405,6 +1409,18 @@ export class Chess {
const them = swapColor(us)
this._push(move)

if (move.flags & BITS.NULL_MOVE){
if (us === BLACK) {
this._moveNumber++
}

this._turn = them

this._epSquare = EMPTY

return
}

this._board[move.to] = this._board[move.from]
delete this._board[move.from]

Expand Down Expand Up @@ -1524,6 +1540,10 @@ export class Chess {
const us = this._turn
const them = swapColor(us)

if (move.flags & (BITS.NULL_MOVE)) {
return move
}

this._board[move.from] = this._board[move.to]
this._board[move.from].type = move.piece // to undo any promotions
delete this._board[move.to]
Expand Down Expand Up @@ -1961,6 +1981,8 @@ export class Chess {
output = 'O-O'
} else if (move.flags & BITS.QSIDE_CASTLE) {
output = 'O-O-O'
} else if (move.flags & BITS.NULL_MOVE){
output = SAN_NULLMOVE
} else {
if (move.piece !== PAWN) {
const disambiguator = getDisambiguator(move, moves)
Expand All @@ -1981,15 +2003,17 @@ export class Chess {
}
}

this._makeMove(move)
if (this.isCheck()) {
if (this.isCheckmate()) {
output += '#'
} else {
output += '+'
if (!(move.flags & BITS.NULL_MOVE)){
this._makeMove(move)
if (this.isCheck()) {
if (this.isCheckmate()) {
output += '#'
} else {
output += '+'
}
}
this._undoMove()
}
this._undoMove()

return output
}
Expand All @@ -1999,6 +2023,18 @@ export class Chess {
// strip off any move decorations: e.g Nf3+?! becomes Nf3
const cleanMove = strippedSan(move)

//first implementation of null with a dummy move (black king moves from a8 to a8), maybe this can be implemented better
if (cleanMove == SAN_NULLMOVE){
let res: InternalMove = {
color: this._turn,
from: 0,
to: 0,
piece: "k",
flags: BITS.NULL_MOVE,
};
return res
}

let pieceType = inferPieceType(cleanMove)
let moves = this._moves({ legal: true, piece: pieceType })

Expand Down Expand Up @@ -2202,9 +2238,13 @@ export class Chess {
}

// generate the FEN for the 'after' key
this._makeMove(uglyMove)
move.after = this.fen()
this._undoMove()
if (!(uglyMove.flags & BITS.NULL_MOVE)){
this._makeMove(uglyMove)
move.after = this.fen()
this._undoMove()
} else {
move.after = this.fen()
}

if (captured) {
move.captured = captured
Expand Down

0 comments on commit 6ee8c59

Please sign in to comment.