Current section
Files
Jump to
Current section
Files
src/game_server.gleam
import gleam/otp/actor
import gleam/erlang/process.{type Subject}
import move.{type Move}
import game.{type Game, InProgress}
import fen
import color.{Black, White}
import castle_rights.{No, Yes}
import gleam/option.{None, Some}
import bitboard
import board
pub type Message {
AllLegalMoves(reply_with: Subject(List(Move)))
ApplyMove(reply_with: Subject(Game), move: Move)
ApplyMoveUCI(reply_with: Subject(Game), move: String)
UndoMove(reply_with: Subject(Game))
GetFen(reply_with: Subject(String))
Shutdown
PrintBoard(reply_with: Subject(Nil))
}
pub fn print_board(game_actor: Subject(Message)) {
process.call(game_actor, PrintBoard, 1000)
}
pub fn apply_move(game_actor: Subject(Message), move: Move) {
process.call(game_actor, ApplyMove(_, move), 1000)
}
pub fn apply_move_uci(game_actor: Subject(Message), move_uci: String) {
process.call(game_actor, ApplyMoveUCI(_, move_uci), 1000)
}
pub fn undo_move(game_actor: Subject(Message)) {
process.call(game_actor, UndoMove, 1000)
}
pub fn all_legal_moves(game_actor: Subject(Message)) {
process.call(game_actor, AllLegalMoves, 1000)
}
pub fn get_fen(game_actor: Subject(Message)) {
process.call(game_actor, GetFen, 1000)
}
fn handle_message(message: Message, game: Game) -> actor.Next(Message, Game) {
case message {
AllLegalMoves(client) -> handle_all_legal_moves(game, client)
ApplyMove(client, move) -> handle_apply_move(game, client, move)
ApplyMoveUCI(client, move) -> handle_apply_move_uci(game, client, move)
UndoMove(client) -> handle_undo_move(game, client)
GetFen(client) -> handle_get_fen(game, client)
Shutdown -> actor.Stop(process.Normal)
PrintBoard(client) -> handle_print_board(game, client)
}
}
fn handle_all_legal_moves(
game: Game,
client: Subject(List(Move)),
) -> actor.Next(Message, Game) {
process.send(client, game.all_legal_moves(game))
actor.continue(game)
}
fn handle_undo_move(game: Game, client: Subject(Game)) {
let new_game_state = game.undo_move(game)
process.send(client, new_game_state)
actor.continue(new_game_state)
}
fn handle_apply_move_uci(game: Game, client: Subject(Game), move: String) {
let new_game_state = game.apply_move_uci(game, move)
process.send(client, new_game_state)
actor.continue(new_game_state)
}
fn handle_apply_move(game: Game, client: Subject(Game), move: Move) {
let new_game_state = game.apply_move(game, move)
process.send(client, new_game_state)
actor.continue(new_game_state)
}
fn handle_get_fen(game: Game, client: Subject(String)) {
process.send(client, game.to_fen(game))
actor.continue(game)
}
fn handle_print_board(
game: Game,
client: Subject(Nil),
) -> actor.Next(Message, Game) {
game.print_board(game)
process.send(client, Nil)
actor.continue(game)
}
pub fn from_fen(fen_string: String) {
let fen = fen.from_string(fen_string)
let status = InProgress
let ply = case fen.turn {
White -> {
{ fen.fullmove - 1 } * 2
}
Black -> {
{ fen.fullmove - 1 } * 2 + 1
}
}
let white_kingside_castle = case fen.castling.white_kingside {
True -> Yes
False -> No(1)
}
let white_queenside_castle = case fen.castling.white_queenside {
True -> Yes
False -> No(1)
}
let black_kingside_castle = case fen.castling.black_kingside {
True -> Yes
False -> No(2)
}
let black_queenside_castle = case fen.castling.black_queenside {
True -> Yes
False -> No(2)
}
let game =
game.Game(
board: fen.board,
turn: fen.turn,
history: [],
status: Some(status),
fifty_move_rule: fen.halfmove,
ply: ply,
white_kingside_castle: white_kingside_castle,
white_queenside_castle: white_queenside_castle,
black_kingside_castle: black_kingside_castle,
black_queenside_castle: black_queenside_castle,
en_passant: fen.en_passant,
)
let assert Ok(actor) = actor.start(game, handle_message)
actor
}
pub fn new_game() {
let white_king_bitboard =
bitboard.Bitboard(
bitboard: 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001000,
)
let white_queen_bitboard =
bitboard.Bitboard(
bitboard: 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00010000,
)
let white_rook_bitboard =
bitboard.Bitboard(
bitboard: 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_10000001,
)
let white_bishop_bitboard =
bitboard.Bitboard(
bitboard: 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00100100,
)
let white_knight_bitboard =
bitboard.Bitboard(
bitboard: 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_01000010,
)
let white_pawns_bitboard =
bitboard.Bitboard(
bitboard: 0b00000000_00000000_00000000_00000000_00000000_00000000_11111111_00000000,
)
let black_king_bitboard =
bitboard.Bitboard(
bitboard: 0b00001000_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
)
let black_queen_bitboard =
bitboard.Bitboard(
bitboard: 0b00010000_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
)
let black_rook_bitboard =
bitboard.Bitboard(
bitboard: 0b10000001_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
)
let black_bishop_bitboard =
bitboard.Bitboard(
bitboard: 0b00100100_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
)
let black_knight_bitboard =
bitboard.Bitboard(
bitboard: 0b01000010_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
)
let black_pawns_bitboard =
bitboard.Bitboard(
bitboard: 0b00000000_11111111_00000000_00000000_00000000_00000000_00000000_00000000,
)
let board =
board.BoardBB(
black_king_bitboard: black_king_bitboard,
black_queen_bitboard: black_queen_bitboard,
black_rook_bitboard: black_rook_bitboard,
black_bishop_bitboard: black_bishop_bitboard,
black_knight_bitboard: black_knight_bitboard,
black_pawns_bitboard: black_pawns_bitboard,
white_king_bitboard: white_king_bitboard,
white_queen_bitboard: white_queen_bitboard,
white_rook_bitboard: white_rook_bitboard,
white_bishop_bitboard: white_bishop_bitboard,
white_knight_bitboard: white_knight_bitboard,
white_pawns_bitboard: white_pawns_bitboard,
)
let turn = White
let history = []
let status = InProgress
let ply = 0
let assert Ok(actor) =
actor.start(
game.Game(
board: board,
turn: turn,
history: history,
status: Some(status),
fifty_move_rule: 0,
ply: ply,
white_kingside_castle: Yes,
white_queenside_castle: Yes,
black_kingside_castle: Yes,
black_queenside_castle: Yes,
en_passant: None,
),
handle_message,
)
actor
}