mirror of
https://github.com/SleepingInsomniac/lx_chess_cr
synced 2025-01-19 10:26:42 +01:00
Generate all pseudolegal moves
This commit is contained in:
parent
af020fb3c6
commit
e496f6c51a
5 changed files with 198 additions and 41 deletions
|
@ -3,66 +3,204 @@ require "../../src/lx_chess/board"
|
|||
require "../../src/lx_chess/piece"
|
||||
require "../../src/lx_chess/move_set"
|
||||
require "../../src/lx_chess/game"
|
||||
require "../../src/lx_chess/term_board"
|
||||
|
||||
def debug_board(game : LxChess::Game, moves : Array(Int16))
|
||||
puts
|
||||
gb = LxChess::TermBoard.new(game.board)
|
||||
gb.highlight(moves)
|
||||
gb.draw
|
||||
puts
|
||||
end
|
||||
|
||||
describe LxChess::Game do
|
||||
describe "#moves" do
|
||||
it "correctly generates white pawn moves from the initial rank" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e2"] = LxChess::Piece.from_fen('P')
|
||||
moves = game.moves("e2")
|
||||
moves.map { |m| game.board.cord(m) }.should eq(["e3", "e4"])
|
||||
if move_set = game.moves("e2")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[e3 e4])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly generates black pawn moves from the initial rank" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e7"] = LxChess::Piece.from_fen('p')
|
||||
moves = game.moves("e7")
|
||||
moves.map { |m| game.board.cord(m) }.should eq(["e6", "e5"])
|
||||
if move_set = game.moves("e7")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[e6 e5])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly generates single white pawn moves" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e3"] = LxChess::Piece.from_fen('P')
|
||||
moves = game.moves("e3")
|
||||
moves.map { |m| game.board.cord(m) }.should eq(["e4"])
|
||||
if move_set = game.moves("e3")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[e4])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly generates black white pawn moves" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e6"] = LxChess::Piece.from_fen('p')
|
||||
moves = game.moves("e6")
|
||||
moves.map { |m| game.board.cord(m) }.should eq(["e5"])
|
||||
if move_set = game.moves("e6")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[e5])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly generates knight moves" do
|
||||
game = LxChess::Game.new
|
||||
game.board["c3"] = LxChess::Piece.from_fen('N')
|
||||
moves = game.moves("c3")
|
||||
moves.map { |m| game.board.cord(m) }.should eq(["a4", "b5", "d5", "e4", "e2", "d1", "b1", "a2"])
|
||||
if move_set = game.moves("c3")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[a4 b5 d5 e4 e2 d1 b1 a2])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "does not generate knight moves that cross the left border edge" do
|
||||
game = LxChess::Game.new
|
||||
game.board["a1"] = LxChess::Piece.from_fen('N')
|
||||
if move_set = game.moves("a1")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[b3 c2])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "does not generate knight moves that cross the right border edge" do
|
||||
game = LxChess::Game.new
|
||||
game.board["h1"] = LxChess::Piece.from_fen('N')
|
||||
if move_set = game.moves("h1")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[f2 g3])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly generates rook moves" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e4"] = LxChess::Piece.from_fen('R')
|
||||
moves = game.moves("e4")
|
||||
moves.map { |m| game.board.cord(m) }.should eq([
|
||||
"d4", "c4", "b4", "a4",
|
||||
"e5", "e6", "e7", "e8",
|
||||
"f4", "g4", "h4",
|
||||
"e3", "e2", "e1",
|
||||
])
|
||||
if move_set = game.moves("e4")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[
|
||||
d4 c4 b4 a4
|
||||
e5 e6 e7 e8
|
||||
f4 g4 h4
|
||||
e3 e2 e1
|
||||
])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly generates bishop moves" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e4"] = LxChess::Piece.from_fen('B')
|
||||
moves = game.moves("e4")
|
||||
moves.map { |m| game.board.cord(m) }.should eq([
|
||||
"d5", "c6", "b7", "a8",
|
||||
"f5", "g6", "h7",
|
||||
"f3", "g2", "h1",
|
||||
"d3", "c2", "b1",
|
||||
])
|
||||
if move_set = game.moves("e4")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[
|
||||
d5 c6 b7 a8
|
||||
f5 g6 h7
|
||||
f3 g2 h1
|
||||
d3 c2 b1
|
||||
])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly generates king moves" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e4"] = LxChess::Piece.from_fen('K')
|
||||
if move_set = game.moves("e4")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[
|
||||
d4 d5 e5 f5 f4 f3 e3 d3
|
||||
])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "does not generate king moves crossing the right border" do
|
||||
game = LxChess::Game.new
|
||||
game.board["h4"] = LxChess::Piece.from_fen('K')
|
||||
if move_set = game.moves("h4")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[
|
||||
g4 g5 h5 h3 g3
|
||||
])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly generates queen moves" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e4"] = LxChess::Piece.from_fen('Q')
|
||||
if move_set = game.moves("e4")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[
|
||||
d5 c6 b7 a8
|
||||
f5 g6 h7
|
||||
f3 g2 h1
|
||||
d3 c2 b1
|
||||
d4 c4 b4 a4
|
||||
e5 e6 e7 e8
|
||||
f4 g4 h4
|
||||
e3 e2 e1
|
||||
])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "blocks moves when a piece is in the way" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e4"] = LxChess::Piece.from_fen('B')
|
||||
game.board["f5"] = LxChess::Piece.from_fen('P')
|
||||
if move_set = game.moves("e4")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[
|
||||
d5 c6 b7 a8
|
||||
f3 g2 h1
|
||||
d3 c2 b1
|
||||
])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
|
||||
it "adds captures before blocking further moves" do
|
||||
game = LxChess::Game.new
|
||||
game.board["e4"] = LxChess::Piece.from_fen('B')
|
||||
game.board["f5"] = LxChess::Piece.from_fen('p')
|
||||
if move_set = game.moves("e4")
|
||||
debug_board(game, move_set.moves)
|
||||
move_set.moves.map { |m| game.board.cord(m) }.should eq(%w[
|
||||
d5 c6 b7 a8
|
||||
f5
|
||||
f3 g2 h1
|
||||
d3 c2 b1
|
||||
])
|
||||
else
|
||||
raise "no moves"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -44,7 +44,9 @@ loop do
|
|||
if input
|
||||
notation = LxChess::Notation.new(input)
|
||||
input = input.to_i16 if input =~ /^\d+$/
|
||||
puts game.moves(input).map { |m| game.board.cord(m) }
|
||||
if move_set = game.moves(input)
|
||||
puts move_set.moves.map { |m| game.board.cord(m) }
|
||||
end
|
||||
# from, to = game.parse_san(notation)
|
||||
# if from && to
|
||||
# puts "#{notation.to_s}: #{game.board.cord(from)} => #{game.board.cord(to)}"
|
||||
|
|
|
@ -76,9 +76,7 @@ module LxChess
|
|||
{x: -1, y: -1}, # down left
|
||||
])
|
||||
end
|
||||
set.moves
|
||||
else
|
||||
[] of Int16
|
||||
set
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,13 +11,17 @@ module LxChess
|
|||
@moves = [] of Int16
|
||||
end
|
||||
|
||||
def add_vector(x : Int16, y : Int16, limit : Int16)
|
||||
add_vector(y * @board.width + x, limit)
|
||||
def origin
|
||||
@piece.index.as(Int16)
|
||||
end
|
||||
|
||||
def add_vector(offset : Int16, limit : Int16)
|
||||
def add_vector(x : Int16, y : Int16, limit : Int16)
|
||||
dist_edge = @board.dist_left(origin) if x.negative?
|
||||
dist_edge = @board.dist_right(origin) if x.positive?
|
||||
limit = dist_edge if dist_edge && dist_edge < limit
|
||||
|
||||
offset = y * @board.width + x
|
||||
step = offset
|
||||
location = @piece.index.as(Int16)
|
||||
limit.times do
|
||||
info = add_offset(offset)
|
||||
offset += step
|
||||
|
@ -27,25 +31,22 @@ module LxChess
|
|||
|
||||
def add_offsets(offsets : Array(NamedTuple(x: Int32, y: Int32)))
|
||||
offsets.each do |cord|
|
||||
# Check if the offset crosses the border
|
||||
next if cord[:x].negative? && origin + cord[:x] < @board.border_left(origin)
|
||||
next if cord[:x].positive? && origin + cord[:x] > @board.border_right(origin)
|
||||
offset = cord[:y] * @board.width + cord[:x]
|
||||
add_offset(offset.to_i16)
|
||||
end
|
||||
end
|
||||
|
||||
def add_offsets(offsets : Array(Int16))
|
||||
offsets.each do |offset|
|
||||
add_offset(offset)
|
||||
end
|
||||
end
|
||||
|
||||
def add_offset(x : Int16, y : Int16)
|
||||
add_offset(y * @board.width + x)
|
||||
end
|
||||
|
||||
# TODO: Stop at the board edges
|
||||
# Does not check for crossing border edges
|
||||
def add_offset(offset : Int16)
|
||||
added = false; stop = false
|
||||
location = @piece.index.as(Int16) + offset
|
||||
location = origin + offset
|
||||
if location < 0 || location >= @board.squares.size
|
||||
# Beyond top or bottom
|
||||
stop = true
|
||||
|
|
|
@ -8,6 +8,7 @@ module LxChess
|
|||
|
||||
def initialize(@board : Board)
|
||||
@flipped = false
|
||||
@highlights = {} of Int16 => Tuple(Symbol, Symbol)
|
||||
|
||||
@bg_dark = :green
|
||||
@bg_light = :light_green
|
||||
|
@ -42,6 +43,16 @@ module LxChess
|
|||
@flipped ? (width - 1).downto(0) : 0.upto(width - 1)
|
||||
end
|
||||
|
||||
def highlight(indicies : Array(Int16), color = {:light_yellow, :yellow})
|
||||
indicies.each do |index|
|
||||
@highlights[index] = color
|
||||
end
|
||||
end
|
||||
|
||||
def clear
|
||||
@highlights = {} of Int16 => Tuple(Symbol, Symbol)
|
||||
end
|
||||
|
||||
def draw(io = STDOUT)
|
||||
ranks.each do |y|
|
||||
io << (y + 1) << ": "
|
||||
|
@ -50,7 +61,14 @@ module LxChess
|
|||
index = @board.index(x, y)
|
||||
piece = @board[index]
|
||||
|
||||
background = (index + y) % 2 == 0 ? @bg_dark : @bg_light
|
||||
tint = (index + y) % 2 == 0 ? :light : :dark
|
||||
|
||||
background =
|
||||
if @highlights[index]?
|
||||
@highlights[index][tint == :light ? 0 : 1]
|
||||
else
|
||||
tint == :light ? @bg_light : @bg_dark
|
||||
end
|
||||
|
||||
if piece
|
||||
foreground = piece.white? ? @fg_light : @fg_dark
|
||||
|
|
Loading…
Reference in a new issue