192 lines
5.0 KiB
Julia
192 lines
5.0 KiB
Julia
# Chess-like Game Example - MCTS for Game Playing
|
|
|
|
This example demonstrates MCTS for a simplified chess-like game where the goal is to capture the opponent's pieces.
|
|
|
|
```julia
|
|
using LLMMCTS
|
|
|
|
# Simple game state
|
|
# board: Dict mapping positions to pieces
|
|
# turn: :white or :black
|
|
struct GameState
|
|
board::Dict{String, String} # position => piece
|
|
turn::Symbol
|
|
piece_count::Int
|
|
end
|
|
|
|
# Initialize a simple board
|
|
function init_board()
|
|
board = Dict{String, String}()
|
|
|
|
# Place some pieces
|
|
board["e1"] = "K" # White King
|
|
board["e8"] = "k" # Black King
|
|
|
|
# Random pieces
|
|
board["d4"] = "P" # White Pawn
|
|
board["d5"] = "p" # Black Pawn
|
|
|
|
return board
|
|
end
|
|
|
|
# Check if position is on board
|
|
function on_board(pos::String)
|
|
cols = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
|
|
rows = ['1', '2', '3', '4', '5', '6', '7', '8']
|
|
length(pos) == 2 &&
|
|
pos[1] in cols &&
|
|
pos[2] in rows
|
|
end
|
|
|
|
# Game transition function
|
|
function chess_transition(state::Dict, args::NamedTuple)
|
|
current_step = get(state, :step, 0)
|
|
board = state[:board]
|
|
turn = state[:turn]
|
|
|
|
if current_step >= args.max_moves
|
|
# Max moves reached, end game
|
|
newstate = Dict(
|
|
:step => current_step + 1,
|
|
:board => board,
|
|
:turn => turn,
|
|
:reward => 0.0,
|
|
:isterminal => true
|
|
)
|
|
return Dict(
|
|
:newNodeKey => "max_moves",
|
|
:newstate => newstate,
|
|
:progressvalue => 5.0
|
|
)
|
|
end
|
|
|
|
# Generate possible moves
|
|
possible_moves = String[]
|
|
|
|
# Find all pieces of current turn's color
|
|
turn_prefix = turn == :white ? "upper" : "lower"
|
|
|
|
# Simple move generation: try moving each piece
|
|
for (pos, piece) in board
|
|
if !isempty(piece)
|
|
# Try moving to adjacent positions
|
|
for dx in [-1, 0, 1]
|
|
for dy in [-1, 0, 1]
|
|
if dx == 0 && dy == 0
|
|
continue
|
|
end
|
|
|
|
# Simple coordinate conversion
|
|
col = pos[1]
|
|
row = parse(Int, pos[2])
|
|
|
|
new_col = col + dx
|
|
new_row = row + dy
|
|
|
|
if new_col >= 'a' && new_col <= 'h' &&
|
|
new_row >= 1 && new_row <= 8
|
|
new_pos = string(new_col, new_row)
|
|
if on_board(new_pos)
|
|
push!(possible_moves, pos * new_pos)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if isempty(possible_moves)
|
|
# No moves available, game over
|
|
newstate = Dict(
|
|
:step => current_step + 1,
|
|
:board => board,
|
|
:turn => turn,
|
|
:reward => turn == :white ? 10.0 : -10.0,
|
|
:isterminal => true
|
|
)
|
|
return Dict(
|
|
:newNodeKey => "game_over",
|
|
:newstate => newstate,
|
|
:progressvalue => turn == :white ? 10.0 : 0.0
|
|
)
|
|
end
|
|
|
|
# LLM would select the best move
|
|
# For this example, pick a random valid move
|
|
move_idx = (current_step - 1) % length(possible_moves) + 1
|
|
move = possible_moves[move_idx]
|
|
|
|
# Simulate the move (simplified)
|
|
from_pos = move[1:2]
|
|
to_pos = move[3:4]
|
|
|
|
new_board = copy(board)
|
|
piece = get(new_board, from_pos, "")
|
|
new_board[to_pos] = piece
|
|
delete!(new_board, from_pos)
|
|
|
|
# Calculate reward based on capture
|
|
reward = 0.0
|
|
if !isempty(get(new_board, to_pos, ""))
|
|
reward = 5.0 # Capture!
|
|
end
|
|
|
|
# Progress value: estimate of game state quality
|
|
progressvalue = 5.0 + reward # Capturing is good
|
|
|
|
# Switch turns
|
|
new_turn = turn == :white ? :black : :white
|
|
|
|
newstate = Dict(
|
|
:step => current_step + 1,
|
|
:board => new_board,
|
|
:turn => new_turn,
|
|
:reward => reward,
|
|
:isterminal => false
|
|
)
|
|
|
|
return Dict(
|
|
:newNodeKey => "move_$current_step",
|
|
:newstate => newstate,
|
|
:progressvalue => progressvalue
|
|
)
|
|
end
|
|
|
|
# Initial state
|
|
initialstate = Dict(
|
|
:step => 0,
|
|
:board => init_board(),
|
|
:turn => :white,
|
|
:reward => 0,
|
|
:isterminal => false
|
|
)
|
|
|
|
# Transition arguments
|
|
transitionargs = (
|
|
max_moves = 10,
|
|
)
|
|
|
|
# Run MCTS
|
|
result = runMCTS(
|
|
initialstate,
|
|
chess_transition,
|
|
transitionargs;
|
|
maxiterations = 30,
|
|
explorationweight = 2.0, # More exploration for game playing
|
|
maxSimulationDepth = 4,
|
|
horizontalSampleExpansionPhase = 5
|
|
)
|
|
|
|
# Display results
|
|
println("Chess-like Game MCTS")
|
|
println("====================")
|
|
println()
|
|
println("Best move sequence:")
|
|
println(" Initial board state")
|
|
println(" → ", result.bestTerminalState[:step], " moves")
|
|
println()
|
|
println("Final board has ", length(result.bestTerminalState[:board]), " pieces")
|
|
println("Root node visits: ", result.root.visits)
|
|
println("High value states: ", length(result.highValueStateList))
|
|
```
|