Chess Engine
For RPG Maker VX
by Abigaila
What is this?
[spoiler]This is a chess engine for RPG Maker.[/spoiler]
How to use? IMPORTANT
[spoiler]
1. Download the attached Chess.dll and place it in your game directory. Make sure the name of the file doesn't change. This is the actual engine that does the thinking.
2a. Install the interface script like you would any other script, invoke it by calling Scene_Chess
-- Or --
2b. You can use the chess engine for some other functionality, or make your own interface. Here is a list of commands. (You must have an understanding of Win32API.)
1. Starting position: Win32API.new("Chess.dll", "reset", "", "V")
2. Does a move exist?: Win32API.new("Chess.dll", "move_exists", ['I','I'], "I")
3. Make a move: Win32API.new("Chess.dll", "do_move", ['I','I'], "I")
4. Take back move: Win32API.new("Chess.dll", "undo_move", "", "I")
5. Computer moves: Win32API.new("Chess.dll", "best_move", "", "L")
6. Get piece on given square (or empty): Win32API.new("Chess.dll", "get_square", "I", "I")
7. Get side to move: Win32API.new("Chess.dll", "side_to_move", "", "I")
@console = Win32API.new("Chess.dll", "console", "", "V")
[/spoiler]
Script (graphical interface)
[spoiler]
#==============================================================================
# ** Scene_Chess
#------------------------------------------------------------------------------
# This class performs chess game UI and AI
#==============================================================================
class Scene_Chess < Scene_Base
#--------------------------------------------------------------------------
# * Constants
#--------------------------------------------------------------------------
WHITE = 0; BLACK = 1;
W_PAWN=0; W_ROOK=1; W_KNIGHT=2; W_BISHOP=3; W_QUEEN=4; W_KING=5;
B_PAWN=6; B_ROOK=7; B_KNIGHT=8; B_BISHOP=9; B_QUEEN=10; B_KING=11;
EMPTY = 12;
BOARD_SIZE = 480
SQ_SIZE = BOARD_SIZE/8
#--------------------------------------------------------------------------
# * Start Processing
#--------------------------------------------------------------------------
def start
super
setup_engine
setup_graphics
@new_game.call()
#@console.call()
refresh
end
#--------------------------------------------------------------------------
# * Setup Engine
#--------------------------------------------------------------------------
def setup_engine
@new_game = Win32API.new("Chess.dll", "reset", "", "V")
@move_exists = Win32API.new("Chess.dll", "move_exists", ['I','I'], "I")
@do_move = Win32API.new("Chess.dll", "do_move", ['I','I'], "I")
@undo_move = Win32API.new("Chess.dll", "undo_move", "", "I")
@best_move = Win32API.new("Chess.dll", "best_move", "", "L")
@get_square = Win32API.new("Chess.dll", "get_square", "I", "I")
@side_to_move = Win32API.new("Chess.dll", "side_to_move", "", "I")
@console = Win32API.new("Chess.dll", "console", "", "V")
end
#--------------------------------------------------------------------------
# * Setup Graphics
#--------------------------------------------------------------------------
def setup_graphics
Graphics.resize_screen(640, 480)
# Cursor
@cursor = 55
@cursor_spr = Sprite.new
@cursor_spr.z = 50
@cursor_spr.opacity = 200
@cursor_spr.bitmap = Bitmap.new(SQ_SIZE, SQ_SIZE)
@cursor_spr.bitmap.fill_rect(0, 0, SQ_SIZE, SQ_SIZE, Color.new(255,255,100))
# From (blue indicating which piece has been selected)
@from = -1
@from_spr = Sprite.new
@from_spr.visible = false
@from_spr.z = 50
@from_spr.opacity = 255
@from_spr.bitmap = Bitmap.new(SQ_SIZE, SQ_SIZE)
@from_spr.bitmap.fill_rect(0, 0, SQ_SIZE, SQ_SIZE, Color.new(50,100,255))
# Board grid bitmap
@board_spr = Sprite.new
@board_spr.bitmap = Bitmap.new(BOARD_SIZE, BOARD_SIZE)
i = 0;
while(i < 64)
odd = (i/8+i%8) % 2
odd = 1 - odd;
x = SQ_SIZE * (i % 8)
y = SQ_SIZE * (i / 8)
color = Color.new(100+155*odd, 140+115*odd, 140+115*odd)
@board_spr.bitmap.fill_rect(x, y, SQ_SIZE, SQ_SIZE, color);
i+=1;
end
# Pieces bitmap
@piece_bitmap = Bitmap.new("pieces.png")
# Pieces sprite
@piece_sprite = Sprite.new()
@piece_sprite.x = 0; @piece_sprite.y = 0;
@piece_sprite.z = 100;
@piece_sprite.bitmap = Bitmap.new(BOARD_SIZE, BOARD_SIZE)
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
super
# Enter pressed
if(Input.trigger?(Input::C))
move_is_legal = move_exists?(@from, @cursor)
if(move_is_legal || !square_selectable?)
if(move_is_legal)
# Player move
do_move(@from, @cursor)
refresh
Graphics.update
# Computer move
best_move
refresh
else
@from = -1;
@from_spr.visible = false;
end
else #square holds your piece
@from = @cursor
@from_spr.x = SQ_SIZE * (@from % 8)
@from_spr.y = SQ_SIZE * (@from / 8)
@from_spr.visible = true;
end
end
# Undo pressed
if(Input.trigger?(Input::B))
@undo_move.call()
@undo_move.call()
refresh
Graphics.update
end
# Move cursor
@cursor -= 1 if(Input.trigger?(Input::LEFT))
@cursor += 1 if(Input.trigger?(Input::RIGHT))
@cursor -= 8 if(Input.trigger?(Input::UP))
@cursor += 8 if(Input.trigger?(Input::DOWN))
@cursor_spr.x = SQ_SIZE * (@cursor % 8)
@cursor_spr.y = SQ_SIZE * (@cursor / 8)
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
@piece_sprite.bitmap.clear
i = 0
while(i < 64)
pce_id = @get_square.call(i)
if(pce_id != EMPTY)
x = SQ_SIZE * (i % 8)
y = SQ_SIZE * (i / 8)
col = pce_id > W_KING ? 1 : 0
pce = pce_id - (col * B_PAWN)
source = Rect.new(pce*60, col*60, 60, 60)
@piece_sprite.bitmap.blt(x, y, @piece_bitmap, source);
end
i += 1
end
end
#--------------------------------------------------------------------------
# * Do Move
#--------------------------------------------------------------------------
def do_move(from, to)
@do_move.call(from, to)
@from_spr.visible = true
@from_spr.x = (to % 8) * SQ_SIZE;
@from_spr.y = (to / 8) * SQ_SIZE;
end
#--------------------------------------------------------------------------
# * Do Best Move
#--------------------------------------------------------------------------
def best_move()
best_move = @best_move.call
# From and To are stored in bits
from = 63 & (best_move >> 6);
to = 63 & best_move;
do_move(from, to)
end
#--------------------------------------------------------------------------
# * Move Exists
#--------------------------------------------------------------------------
def move_exists?(from, to)
result = @move_exists.call(from, to)
return result == 1
end
#--------------------------------------------------------------------------
# * Square is Selectable
#--------------------------------------------------------------------------
def square_selectable?
if(@get_square.call(@cursor) == EMPTY)
return false
elsif(@get_square.call(@cursor) <= W_KING && @side_to_move.call() == WHITE)
return true
elsif(@get_square.call(@cursor) >= B_PAWN && @side_to_move.call() == BLACK)
return true
else
return false
end
end
end
[/spoiler]
DLL-free version (V1):
This version is made entirely with RPG Maker scripts and doesn't rely on a dll. It is much weaker as a player though.
[spoiler]Chess_Constants:
module Chess
#--------------------------------------------------------------------------
# * Color
#--------------------------------------------------------------------------
WHITE = true
BLACK = false
#--------------------------------------------------------------------------
# * Pieces
#--------------------------------------------------------------------------
W_PAWN = 0
W_ROOK = 1
W_KNIGHT = 2
W_BISHOP = 3
W_QUEEN = 4
W_KING = 5
B_PAWN = 6
B_ROOK = 7
B_KNIGHT = 8
B_BISHOP = 9
B_QUEEN = 10
B_KING = 11
NO_PIECE = 12
OFF_BOARD = -2;
#--------------------------------------------------------------------------
# * Squares
#--------------------------------------------------------------------------
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;
A6 = 41; B6 = 42; C6 = 43; D6 = 44; E6 = 45; F6 = 46; G6 = 47; H6 = 48;
A5 = 51; B5 = 52; C5 = 53; D5 = 54; E5 = 55; F5 = 56; G5 = 57; H5 = 58;
A4 = 61; B4 = 62; C4 = 63; D4 = 64; E4 = 65; F4 = 66; G4 = 67; H4 = 68;
A3 = 71; B3 = 72; C3 = 73; D3 = 74; E3 = 75; F3 = 76; G3 = 77; H3 = 78;
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;
NO_SQUARE = -1;
#--------------------------------------------------------------------------
# * Ranks
#--------------------------------------------------------------------------
RANK_1 = 8; RANK_2 = 7; RANK_3 = 6; RANK_4 = 5;
RANK_5 = 4; RANK_6 = 3; RANK_7 = 2; RANK_8 = 1;
#--------------------------------------------------------------------------
# * Files
#--------------------------------------------------------------------------
FILE_A = 1; FILE_B = 2; FILE_C = 3; FILE_D = 4;
FILE_E = 5; FILE_F = 6; FILE_G = 7; FILE_H = 8;
#--------------------------------------------------------------------------
# * Strings
#--------------------------------------------------------------------------
SFILES = []
SFILES[FILE_A] = "a"; SFILES[FILE_B] = "b"; SFILES[FILE_C] = "c";
SFILES[FILE_D] = "d"; SFILES[FILE_E] = "e"; SFILES[FILE_F] = "f";
SFILES[FILE_G] = "g"; SFILES[FILE_H] = "h";
#--------------------------------------------------------------------------
# * Values
#--------------------------------------------------------------------------
PVALUE = []
PVALUE[NO_PIECE] = 0
PVALUE[W_PAWN] = 100
PVALUE[W_KNIGHT] = 300
PVALUE[W_BISHOP] = 300
PVALUE[W_ROOK] = 600
PVALUE[W_QUEEN] = 900
PVALUE[W_KING] = 0
PVALUE[B_PAWN] = -100
PVALUE[B_KNIGHT] = -300
PVALUE[B_BISHOP] = -300
PVALUE[B_ROOK] = -600
PVALUE[B_QUEEN] = -900
PVALUE[B_KING] = 0
DRAW = 0
CHECKMATE = 1000
INFINITY = CHECKMATE + 1
end
Chess_MoveGeneration:
class Chess_MoveGeneration
#--------------------------------------------------------------------------
# * Move exists?
#--------------------------------------------------------------------------
def move_exists(pos, move)
legalMoves = []
legalMoves += generateCapture(pos)
legalMoves += generateQuiet(pos)
legalMoves.each_index do |i|
if(legalMoves[i][0] == move[0] && legalMoves[i][1] == move[1])
return true
end
end
return false
end
#--------------------------------------------------------------------------
# * Generate quiet moves
#--------------------------------------------------------------------------
def generateQuiet(pos)
moves = []
i = -1
while(i < 120)
i += 1
p = pos.board[i]
next if(p == nil || p == Chess::OFF_BOARD || p == Chess::NO_PIECE)
color = (p <= Chess::W_KING) ? Chess::WHITE : Chess::BLACK
next if(color != pos.side_to_move)
is_rook = (p == Chess::W_ROOK || p == Chess::B_ROOK)
is_knight = (p == Chess::W_KNIGHT || p == Chess::B_KNIGHT)
is_bishop = (p == Chess::W_BISHOP || p == Chess::B_BISHOP)
is_queen = (p == Chess::W_QUEEN || p == Chess::B_QUEEN)
is_king = (p == Chess::W_KING || p == Chess::B_KING)
#
# Pawns
#
if(p == Chess::W_PAWN)
if(pos.board[i - 10] == Chess::NO_PIECE)
moves.push([i, i - 10])
if(i >= Chess::A2 && pos.board[i - 20] == Chess::NO_PIECE)
moves.push([i, i - 20])
end
end
end
if(p == Chess::B_PAWN)
if(pos.board[i + 10] == Chess::NO_PIECE)
moves.push([i, i + 10])
if(i <= Chess::H7 && pos.board[i + 20] == Chess::NO_PIECE)
moves.push([i, i + 20])
end
end
end
#
# Knight movement
#
if(is_knight)
moves.push([i, i+21]) if(pos.board[i+21] == Chess::NO_PIECE)
moves.push([i, i+19]) if(pos.board[i+19] == Chess::NO_PIECE)
moves.push([i, i+12]) if(pos.board[i+12] == Chess::NO_PIECE)
moves.push([i, i+8]) if(pos.board[i+8] == Chess::NO_PIECE)
moves.push([i, i-21]) if(pos.board[i-21] == Chess::NO_PIECE)
moves.push([i, i-19]) if(pos.board[i-19] == Chess::NO_PIECE)
moves.push([i, i-12]) if(pos.board[i-12] == Chess::NO_PIECE)
moves.push([i, i-8]) if(pos.board[i-8] == Chess::NO_PIECE)
end
#
# Linear movement
#
if(is_rook || is_queen)
j = 1
while(pos.board[i + j] == Chess::NO_PIECE)
moves.push([i, i+j])
j += 1
end
j = 1
while(pos.board[i - j] == Chess::NO_PIECE)
moves.push([i, i-j])
j += 1
end
j = 1
while(pos.board[i + j*10] == Chess::NO_PIECE)
moves.push([i, i+j*10])
j += 1
end
j = 1
while(pos.board[i - j*10] == Chess::NO_PIECE)
moves.push([i, i-j*10])
j += 1
end
end
#
# Diagonal movement
#
if(is_bishop || is_queen)
j = 1
while(pos.board[i + j*10 + j] == Chess::NO_PIECE)
moves.push([i, i+j*10 + j])
j += 1
end
j = 1
while(pos.board[i - j*10 + j] == Chess::NO_PIECE)
moves.push([i, i-j*10 + j])
j += 1
end
j = 1
while(pos.board[i + j*10 - j] == Chess::NO_PIECE)
moves.push([i, i+j*10 - j])
j += 1
end
j = 1
while(pos.board[i - j*10 - j] == Chess::NO_PIECE)
moves.push([i, i-j*10 - j])
j += 1
end
end
#
# King movement
#
if(is_king)
moves.push([i, i+1]) if(pos.board[i+1] == Chess::NO_PIECE)
moves.push([i, i-1]) if(pos.board[i-1] == Chess::NO_PIECE)
moves.push([i, i+10]) if(pos.board[i+10] == Chess::NO_PIECE)
moves.push([i, i-10]) if(pos.board[i-10] == Chess::NO_PIECE)
moves.push([i, i+11]) if(pos.board[i+11] == Chess::NO_PIECE)
moves.push([i, i-11]) if(pos.board[i-11] == Chess::NO_PIECE)
moves.push([i, i+9]) if(pos.board[i+9] == Chess::NO_PIECE)
moves.push([i, i-9]) if(pos.board[i-9] == Chess::NO_PIECE)
end
end
return moves
end
#--------------------------------------------------------------------------
# * Generate capture moves
#--------------------------------------------------------------------------
def generateCapture(pos)
moves = []
i = -1
while(i < 120)
i += 1
p = pos.board[i]
next if(p == nil || p == Chess::OFF_BOARD || p == Chess::NO_PIECE)
color = (p <= Chess::W_KING) ? Chess::WHITE : Chess::BLACK
next if(color != pos.side_to_move)
#
# Pawns
#
if(p == Chess::W_PAWN)
moves.push([i, i - 11]) if pos.is_black(pos.board[i - 11])
moves.push([i, i - 9]) if pos.is_black(pos.board[i - 9])
end
if(p == Chess::B_PAWN)
moves.push([i, i + 11]) if pos.is_white(pos.board[i + 11])
moves.push([i, i + 9]) if pos.is_white(pos.board[i + 9])
end
#
# Knight movement
#
if(p == Chess::W_KNIGHT)
moves.push([i, i+21]) if pos.is_black(pos.board[i+21])
moves.push([i, i+19]) if pos.is_black(pos.board[i+19])
moves.push([i, i+12]) if pos.is_black(pos.board[i+12])
moves.push([i, i+8]) if pos.is_black(pos.board[i+8])
moves.push([i, i-21]) if pos.is_black(pos.board[i-21])
moves.push([i, i-19]) if pos.is_black(pos.board[i-19])
moves.push([i, i-12]) if pos.is_black(pos.board[i-12])
moves.push([i, i-8]) if pos.is_black(pos.board[i-8])
end
if(p == Chess::B_KNIGHT)
moves.push([i, i+21]) if pos.is_white(pos.board[i+21])
moves.push([i, i+19]) if pos.is_white(pos.board[i+19])
moves.push([i, i+12]) if pos.is_white(pos.board[i+12])
moves.push([i, i+8]) if pos.is_white(pos.board[i+8])
moves.push([i, i-21]) if pos.is_white(pos.board[i-21])
moves.push([i, i-19]) if pos.is_white(pos.board[i-19])
moves.push([i, i-12]) if pos.is_white(pos.board[i-12])
moves.push([i, i-8]) if pos.is_white(pos.board[i-8])
end
#
# Linear movement
#
if(p == Chess::W_ROOK || p == Chess::W_QUEEN)
j = 1
j += 1 while(pos.board[i + j] == Chess::NO_PIECE)
moves.push([i, i+j]) if pos.is_black(pos.board[i + j])
j = 1
j += 1 while(pos.board[i - j] == Chess::NO_PIECE)
moves.push([i, i-j]) if pos.is_black(pos.board[i - j])
j = 1
j += 1 while(pos.board[i + j*10] == Chess::NO_PIECE)
moves.push([i, i+j*10]) if pos.is_black(pos.board[i + j*10])
j = 1
j += 1 while(pos.board[i - j*10] == Chess::NO_PIECE)
moves.push([i, i-j*10]) if pos.is_black(pos.board[i - j*10])
end
if(p == Chess::B_ROOK || p == Chess::B_QUEEN)
j = 1
j += 1 while(pos.board[i + j] == Chess::NO_PIECE)
moves.push([i, i+j]) if pos.is_white(pos.board[i + j])
j = 1
j += 1 while(pos.board[i - j] == Chess::NO_PIECE)
moves.push([i, i-j]) if pos.is_white(pos.board[i - j])
j = 1
j += 1 while(pos.board[i + j*10] == Chess::NO_PIECE)
moves.push([i, i+j*10]) if pos.is_white(pos.board[i + j*10])
j = 1
j += 1 while(pos.board[i - j*10] == Chess::NO_PIECE)
moves.push([i, i-j*10]) if pos.is_white(pos.board[i - j*10])
end
#
# Diagonal movement
#
if(p == Chess::W_BISHOP || p == Chess::W_QUEEN)
j = 1
j += 1 while(pos.board[i + j*10 + j] == Chess::NO_PIECE)
moves.push([i, i+j*10+j]) if pos.is_black(pos.board[i + j*10+j])
j = 1
j += 1 while(pos.board[i - j*10+j] == Chess::NO_PIECE)
moves.push([i, i-j*10+j]) if pos.is_black(pos.board[i - j*10+j])
j = 1
j += 1 while(pos.board[i + j*10-j] == Chess::NO_PIECE)
moves.push([i, i+j*10-j]) if pos.is_black(pos.board[i + j*10-j])
j = 1
j += 1 while(pos.board[i - j*10-j] == Chess::NO_PIECE)
moves.push([i, i-j*10-j]) if pos.is_black(pos.board[i - j*10-j])
end
if(p == Chess::B_BISHOP || p == Chess::B_QUEEN)
j = 1
j += 1 while(pos.board[i + j*10 + j] == Chess::NO_PIECE)
moves.push([i, i+j*10+j]) if pos.is_white(pos.board[i + j*10+j])
j = 1
j += 1 while(pos.board[i - j*10+j] == Chess::NO_PIECE)
moves.push([i, i-j*10+j]) if pos.is_white(pos.board[i - j*10+j])
j = 1
j += 1 while(pos.board[i + j*10-j] == Chess::NO_PIECE)
moves.push([i, i+j*10-j]) if pos.is_white(pos.board[i + j*10-j])
j = 1
j += 1 while(pos.board[i - j*10-j] == Chess::NO_PIECE)
moves.push([i, i-j*10-j]) if pos.is_white(pos.board[i - j*10-j])
end
#
# King movement
#
if(p == Chess::W_KING)
moves.push([i, i+1]) if pos.is_black(pos.board[i+1])
moves.push([i, i-1]) if pos.is_black(pos.board[i-1])
moves.push([i, i+10]) if pos.is_black(pos.board[i+10])
moves.push([i, i-10]) if pos.is_black(pos.board[i-10])
moves.push([i, i+11]) if pos.is_black(pos.board[i+11])
moves.push([i, i-11]) if pos.is_black(pos.board[i-11])
moves.push([i, i+9]) if pos.is_black(pos.board[i+9])
moves.push([i, i-9]) if pos.is_black(pos.board[i-9])
end
if(p == Chess::B_KING)
moves.push([i, i+1]) if pos.is_white(pos.board[i+1])
moves.push([i, i-1]) if pos.is_white(pos.board[i-1])
moves.push([i, i+10]) if pos.is_white(pos.board[i+10])
moves.push([i, i-10]) if pos.is_white(pos.board[i-10])
moves.push([i, i+11]) if pos.is_white(pos.board[i+11])
moves.push([i, i-11]) if pos.is_white(pos.board[i-11])
moves.push([i, i+9]) if pos.is_white(pos.board[i+9])
moves.push([i, i-9]) if pos.is_white(pos.board[i-9])
end
end
return moves
end
end
Chess_Search:
class Chess_Search
attr_reader :best_move
#--------------------------------------------------------------------------
# * Search
#--------------------------------------------------------------------------
def search(pos)
@move_gen = Chess_MoveGeneration.new
@best_move = [Chess::NO_SQUARE, Chess::NO_SQUARE]
negamax(pos, 4, -Chess::INFINITY, Chess::INFINITY)
end
#--------------------------------------------------------------------------
# * NegaMax
#--------------------------------------------------------------------------
def negamax(pos, depth, alpha, beta)
# Leaf Node
if(depth == 0)
if(pos.side_to_move == Chess::WHITE)
return pos.score
elsif(pos.side_to_move == Chess::BLACK)
return -pos.score
end
end
# Generate legal moves
moves = []
moves += @move_gen.generateCapture(pos)
moves += @move_gen.generateQuiet(pos)
if(moves.length == 0)
return Chess::DRAW
end
# Browse legal moves
moves.each_index do |i|
pos.make_move( moves[i] )
score = -negamax(pos, depth - 1, -beta, -alpha)
pos.unmake_move()
if(score >= beta)
return beta
end
if(score > alpha)
alpha = score
if(depth == 4)
@best_move = moves[i]
end
end
end
return alpha
end
end
Chess_Position:
class Chess_Position
#--------------------------------------------------------------------------
# * Public Variables
#--------------------------------------------------------------------------
attr_accessor :board
attr_reader :side_to_move
attr_reader :score
#--------------------------------------------------------------------------
# * Start
#--------------------------------------------------------------------------
def initialize
@side_to_move = Chess::WHITE
@board = []
@score = 0
@history = []
@history_capture = []
starting_position
end
#--------------------------------------------------------------------------
# * Start
#--------------------------------------------------------------------------
def clear
@score = 0
# 120
i = 0
while(i < 120)
@board[i] = Chess::OFF_BOARD
i += 1
end
# Real 64 board
i = 0
while(i < 64)
@board[sq120(i)] = Chess::NO_PIECE
i += 1
end
end
#--------------------------------------------------------------------------
# * Move
#--------------------------------------------------------------------------
def make_move(move)
# Update game score
@score -= Chess::PVALUE[@board[move[1]]]
# Record history
@history.push(move)
@history_capture.push(@board[move[1]])
# Move piece
@board[move[1]] = @board[move[0]]
@board[move[0]] = Chess::NO_PIECE
@side_to_move = !@side_to_move
end
#--------------------------------------------------------------------------
# * Undo Move
#--------------------------------------------------------------------------
def unmake_move()
move = @history.pop
captured = @history_capture.pop
# Refactor game score
@score += Chess::PVALUE[captured]
# Move back piece
@board[move[0]] = @board[move[1]]
@board[move[1]] = captured
@side_to_move = !@side_to_move
end
#--------------------------------------------------------------------------
# * Color
#--------------------------------------------------------------------------
def is_white(piece)
(piece >= Chess::W_PAWN && piece <= Chess::W_KING)
end
def is_black(piece)
(piece >= Chess::B_PAWN && piece <= Chess::B_KING)
end
#--------------------------------------------------------------------------
# * Square 64 => 120
#--------------------------------------------------------------------------
def sq120(s)
x = (s % 8)
y = (s / 8)
21 + y * 10 + x
end
#--------------------------------------------------------------------------
# * Square 120 => 64
#--------------------------------------------------------------------------
def sq64(s)
s -= 21;
x = (s % 10)
y = (s / 10)
y * 8 + x
end
#--------------------------------------------------------------------------
# * Starting position
#--------------------------------------------------------------------------
def starting_position
clear
# White
@board[Chess::A1] = Chess::W_ROOK
@board[Chess::B1] = Chess::W_KNIGHT
@board[Chess::C1] = Chess::W_BISHOP
@board[Chess::D1] = Chess::W_QUEEN
@board[Chess::E1] = Chess::W_KING
@board[Chess::F1] = Chess::W_BISHOP
@board[Chess::G1] = Chess::W_KNIGHT
@board[Chess::H1] = Chess::W_ROOK
@board[Chess::A2] = Chess::W_PAWN
@board[Chess::B2] = Chess::W_PAWN
@board[Chess::C2] = Chess::W_PAWN
@board[Chess::D2] = Chess::W_PAWN
@board[Chess::E2] = Chess::W_PAWN
@board[Chess::F2] = Chess::W_PAWN
@board[Chess::G2] = Chess::W_PAWN
@board[Chess::H2] = Chess::W_PAWN
# Black
@board[Chess::A8] = Chess::B_ROOK
@board[Chess::B8] = Chess::B_KNIGHT
@board[Chess::C8] = Chess::B_BISHOP
@board[Chess::D8] = Chess::B_QUEEN
@board[Chess::E8] = Chess::B_KING
@board[Chess::F8] = Chess::B_BISHOP
@board[Chess::G8] = Chess::B_KNIGHT
@board[Chess::H8] = Chess::B_ROOK
@board[Chess::A7] = Chess::B_PAWN
@board[Chess::B7] = Chess::B_PAWN
@board[Chess::C7] = Chess::B_PAWN
@board[Chess::D7] = Chess::B_PAWN
@board[Chess::E7] = Chess::B_PAWN
@board[Chess::F7] = Chess::B_PAWN
@board[Chess::G7] = Chess::B_PAWN
@board[Chess::H7] = Chess::B_PAWN
end
end
Scene_Chess: (VXA Version)
#==============================================================================
# ** Scene_Chess
#------------------------------------------------------------------------------
# This class performs chess game UI and AI
#==============================================================================
class Scene_Chess < Scene_Base
#--------------------------------------------------------------------------
# * Start Processing
#--------------------------------------------------------------------------
def start
super
@position = Chess_Position.new
@move_gen = Chess_MoveGeneration.new
@search = Chess_Search.new
@selected_square = @position.sq64(Chess::E2)
@from_square = Chess::NO_SQUARE
load_piece_sprite
create_chessboard_sprite
create_piece_sprite
redraw_pieces
end
#--------------------------------------------------------------------------
# * Make move
#--------------------------------------------------------------------------
def make_move(from, to)
from = @position.sq120(from)
to = @position.sq120(to)
move = [from, to]
move_legal = @move_gen.move_exists(@position, move)
if(move_legal)
# Make player move
@position.make_move(move)
redraw_pieces
# Pick computer move
@search.search(@position)
# Make move
@position.make_move(@search.best_move)
redraw_pieces
dx = (@position.sq64(@search.best_move[1]) % 8)
dy = (@position.sq64(@search.best_move[1]) / 8)
@last_move_sprite.x = dx * @square_size + @board_padding
@last_move_sprite.y = dy * @square_size
@last_move_sprite.visible = true
end
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# Move cursor
if(Input.trigger?(:UP))
@selected_square -= 8
elsif(Input.trigger?(:RIGHT))
@selected_square += 1
elsif(Input.trigger?(:LEFT))
@selected_square -= 1
elsif(Input.trigger?(:DOWN))
@selected_square += 8
end
@selected_square = 0 if(@selected_square < 0)
@selected_square = 63 if(@selected_square > 63)
# Enter
if(Input.trigger?(:C))
if(@from_square != Chess::NO_SQUARE)
make_move(@from_square, @selected_square)
@from_square = Chess::NO_SQUARE
else
@from_square = @selected_square
end
end
# Position sprite
@cursor_sprite.x = @square_size * (@selected_square % 8) + @board_padding
@cursor_sprite.y = @square_size * (@selected_square / 8)
@from_sprite.x = @square_size * (@from_square % 8) + @board_padding
@from_sprite.y = @square_size * (@from_square / 8)
super
end
#--------------------------------------------------------------------------
# * create_piece_sprite
#--------------------------------------------------------------------------
def create_piece_sprite
@piece_sprite = Sprite.new
@piece_sprite.x = @board_padding
@piece_sprite.y = 0
@piece_sprite.z = 150
@piece_sprite.bitmap = Bitmap.new(@board_size, @board_size)
end
#--------------------------------------------------------------------------
# * Redraw piece
#--------------------------------------------------------------------------
def redraw_pieces
@piece_sprite.bitmap.clear
x = 0; y = 0;
while(y < 8)
while(x < 8)
square64 = y * 8 + x
square120 = @position.sq120(square64)
piece = @position.board[square120]
if(piece != Chess::NO_PIECE)
dx = @square_size * x
dy = @square_size * y
rect = Rect.new(0, 0, @board_size, @board_size)
@piece_sprite.bitmap.blt(dx, dy, @piece_bitmaps[piece], rect)
end
x += 1
end
x = 0
y += 1
end
end
#--------------------------------------------------------------------------
# * Load Piece Sprite
#--------------------------------------------------------------------------
def load_piece_sprite
@piece_bitmaps = []
@piece_bitmaps[Chess::W_PAWN] = Bitmap.new("ChessPieces/white_pawn.png")
@piece_bitmaps[Chess::W_ROOK] = Bitmap.new("ChessPieces/white_rook.png")
@piece_bitmaps[Chess::W_KNIGHT] = Bitmap.new("ChessPieces/white_knight.png")
@piece_bitmaps[Chess::W_BISHOP] = Bitmap.new("ChessPieces/white_bishop.png")
@piece_bitmaps[Chess::W_QUEEN] = Bitmap.new("ChessPieces/white_queen.png")
@piece_bitmaps[Chess::W_KING] = Bitmap.new("ChessPieces/white_king.png")
@piece_bitmaps[Chess::B_PAWN] = Bitmap.new("ChessPieces/black_pawn.png")
@piece_bitmaps[Chess::B_ROOK] = Bitmap.new("ChessPieces/black_rook.png")
@piece_bitmaps[Chess::B_KNIGHT] = Bitmap.new("ChessPieces/black_knight.png")
@piece_bitmaps[Chess::B_BISHOP] = Bitmap.new("ChessPieces/black_bishop.png")
@piece_bitmaps[Chess::B_QUEEN] = Bitmap.new("ChessPieces/black_queen.png")
@piece_bitmaps[Chess::B_KING] = Bitmap.new("ChessPieces/black_king.png")
end
#--------------------------------------------------------------------------
# * Create chessboard sprite
#--------------------------------------------------------------------------
def create_chessboard_sprite
Graphics.resize_screen(640, 480)
# Size constants
@board_size = 480
@board_padding = (640 - @board_size) / 2
@square_size = @board_size / 8
# Create board sprite
@board_gfx = Sprite.new
@board_gfx.z = 10
@board_gfx.x = @board_padding
@board_gfx.bitmap = Bitmap.new(@board_size, @board_size)
y = 0
while(y < 8)
x = 0
while(x < 8)
x2 = x * @square_size
y2 = y * @square_size
if((x + y) % 2 == 0)
col = Color.new(255, 255, 255)
else
col = Color.new(80, 30, 0)
end
@board_gfx.bitmap.fill_rect(x2, y2, @square_size, @square_size, col)
x += 1
end
y += 1
end
# Create square cursor sprite
@cursor_sprite = Sprite.new
@cursor_sprite.bitmap = Bitmap.new(@square_size, @square_size)
@cursor_sprite.bitmap.fill_rect(0, 0, 640, 480, Color.new(255, 255, 100))
@cursor_sprite.z = 50
# Create from_square sprite
@from_sprite = Sprite.new
@from_sprite.bitmap = Bitmap.new(@square_size, @square_size)
@from_sprite.bitmap.fill_rect(0, 0, 640, 480, Color.new(100, 255, 100))
@from_sprite.z = 51
# Create last_move_to sprite
@last_move_sprite = Sprite.new
@last_move_sprite.bitmap = Bitmap.new(@square_size, @square_size)
@last_move_sprite.bitmap.fill_rect(0, 0, 640, 480, Color.new(200, 200, 100))
@last_move_sprite.z = 51
@last_move_sprite.visible = false
end
#--------------------------------------------------------------------------
# * Termination Processing
#--------------------------------------------------------------------------
def terminate
super
end
end
Scene_Chess (VX Version)
[code]
#==============================================================================
# ** Scene_Chess
#------------------------------------------------------------------------------
# This class performs chess game UI and AI
#==============================================================================
class Scene_Chess < Scene_Base
#--------------------------------------------------------------------------
# * Start Processing
#--------------------------------------------------------------------------
def start
super
Graphics.resize_screen(640, 480)
@position = Chess_Position.new
@move_gen = Chess_MoveGeneration.new
@search = Chess_Search.new
@selected_square = @position.sq64(Chess::E2)
@from_square = Chess::NO_SQUARE
load_piece_sprite
create_chessboard_sprite
create_piece_sprite
redraw_pieces
end
#--------------------------------------------------------------------------
# * Make move
#--------------------------------------------------------------------------
def make_move(from, to)
from = @position.sq120(from)
to = @position.sq120(to)
move = [from, to]
move_legal = @move_gen.move_exists(@position, move)
if(move_legal)
# Make player move
@position.make_move(move)
redraw_pieces
# Pick computer move
@search.search(@position)
# Make move
@position.make_move(@search.best_move)
redraw_pieces
dx = (@position.sq64(@search.best_move[1]) % 8)
dy = (@position.sq64(@search.best_move[1]) / 8)
@last_move_sprite.x = dx * @square_size + @board_padding
@last_move_sprite.y = dy * @square_size
@last_move_sprite.visible = true
end
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
super
# Move cursor
if(Input.trigger?(Input::UP))
@selected_square -= 8
elsif(Input.trigger?(Input::RIGHT))
@selected_square += 1
elsif(Input.trigger?(Input::LEFT))
@selected_square -= 1
elsif(Input.trigger?(Input::DOWN))
@selected_square += 8
end
@selected_square = 0 if(@selected_square < 0)
@selected_square = 63 if(@selected_square > 63)
# Enter
if(Input.trigger?(Input::C))
if(@from_square != Chess::NO_SQUARE)
make_move(@from_square, @selected_square)
@from_square = Chess::NO_SQUARE
else
@from_square = @selected_square
end
end
# Position sprite
@cursor_sprite.x = @square_size * (@selected_square % 8) + @board_padding
@cursor_sprite.y = @square_size * (@selected_square / 8)
@from_sprite.x = @square_size * (@from_square % 8) + @board_padding
@from_sprite.y = @square_size * (@from_square / 8)
end
#--------------------------------------------------------------------------
# * create_piece_sprite
#--------------------------------------------------------------------------
def create_piece_sprite
@piece_sprite = Sprite.new
@piece_sprite.x = @board_padding
@piece_sprite.y = 0
@piece_sprite.z = 150
@piece_sprite.bitmap = Bitmap.new(@board_size, @board_size)
end
#--------------------------------------------------------------------------
# * Redraw piece
#--------------------------------------------------------------------------
def redraw_pieces
@piece_sprite.bitmap.clear
x = 0; y = 0;
while(y < 8)
while(x < 8)
square64 = y * 8 + x
square120 = @position.sq120(square64)
piece = @position.board[square120]
if(piece != Chess::NO_PIECE)
dx = @square_size * x
dy = @square_size * y
rect = Rect.new(0, 0, @board_size, @board_size)
@piece_sprite.bitmap.blt(dx, dy, @piece_bitmaps[piece], rect)
end
x += 1
end
x = 0
y += 1
end
end
#--------------------------------------------------------------------------
# * Load Piece Sprite
#--------------------------------------------------------------------------
def load_piece_sprite
@piece_bitmaps = []
@piece_bitmaps[Chess::W_PAWN] = Bitmap.new("ChessPieces/white_pawn.png")
@piece_bitmaps[Chess::W_ROOK] = Bitmap.new("ChessPieces/white_rook.png")
@piece_bitmaps[Chess::W_KNIGHT] = Bitmap.new("ChessPieces/white_knight.png")
@piece_bitmaps[Chess::W_BISHOP] = Bitmap.new("ChessPieces/white_bishop.png")
@piece_bitmaps[Chess::W_QUEEN] = Bitmap.new("ChessPieces/white_queen.png")
@piece_bitmaps[Chess::W_KING] = Bitmap.new("ChessPieces/white_king.png")
@piece_bitmaps[Chess::B_PAWN] = Bitmap.new("ChessPieces/black_pawn.png")
@piece_bitmaps[Chess::B_ROOK] = Bitmap.new("ChessPieces/black_rook.png")
@piece_bitmaps[Chess::B_KNIGHT] = Bitmap.new("ChessPieces/black_knight.png")
@piece_bitmaps[Chess::B_BISHOP] = Bitmap.new("ChessPieces/black_bishop.png")
@piece_bitmaps[Chess::B_QUEEN] = Bitmap.new("ChessPieces/black_queen.png")
@piece_bitmaps[Chess::B_KING] = Bitmap.new("ChessPieces/black_king.png")
end
#--------------------------------------------------------------------------
# * Create chessboard sprite
#--------------------------------------------------------------------------
def create_chessboard_sprite
# Size constants
@board_size = 480
@board_padding = (640 - @board_size) / 2
@square_size = @board_size / 8
# Create board sprite
@board_gfx = Sprite.new
@board_gfx.z = 10
@board_gfx.x = @board_padding
@board_gfx.bitmap = Bitmap.new(@board_size, @board_size)
y = 0
while(y < 8)
x = 0
while(x < 8)
x2 = x * @square_size
y2 = y * @square_size
if((x + y) % 2 == 0)
col = Color.new(255, 255, 255)
else
col = Color.new(80, 30, 0)
end
@board_gfx.bitmap.fill_rect(x2, y2, @square_size, @square_size, col)
x += 1
end
y += 1
end
# Create square cursor sprite
@cursor_sprite = Sprite.new
@cursor_sprite.bitmap = Bitmap.new(@square_size, @square_size)
@cursor_sprite.bitmap.fill_rect(0, 0, 640, 480, Color.new(255, 255, 100))
@cursor_sprite.z = 50
# Create from_square sprite
@from_sprite = Sprite.new
@from_sprite.bitmap = Bitmap.new(@square_size, @square_size)
@from_sprite.bitmap.fill_rect(0, 0, 640, 480, Color.new(100, 255, 100))
@from_sprite.z = 51
# Create last_move_to sprite
@last_move_sprite = Sprite.new
@last_move_sprite.bitmap = Bitmap.new(@square_size, @square_size)
@last_move_sprite.bitmap.fill_rect(0, 0, 640, 480, Color.new(200, 200, 100))
@last_move_sprite.z = 51
@last_move_sprite.visible = false
end
#--------------------------------------------------------------------------
# * Termination Processing
#--------------------------------------------------------------------------&
Are you shitting me? You're shitting me. If his was for VX I would totally lose my shit. As it stands im impressed. Ahh, I need to get a new computer so I can try this out!
Quote from: Ser EvilM00s on May 17, 2014, 01:54:26 PM
Are you shitting me? You're shitting me. If his was for VX I would totally lose my shit. As it stands im impressed. Ahh, I need to get a new computer so I can try this out!
:D I'm not shitting you! Note however, that I haven't gotten around to the intricacies of check, checkmate, castling etc. yet, thus it's in progress.
Also the AI is fairly simple, but that too will be improved with time :)
Dude. When you have it down I will name my son's left foot after you to convert it to VX. It's EXACTLY whT I want!
Quote from: Ser EvilM00s on May 17, 2014, 01:59:34 PM
Dude. When you have it down I will name my son's left foot after you to convert it to VX. It's EXACTLY whT I want!
Haha :D I can probably convert it to VX, it shouldn't be much work at all. It doesn't depend on the standard scripts at all other than the scene.
Hmm, I found one problem right off the bat; It requires the VXA RTP to run. You need to fix that =p
Other than that, I like the concept, and if it actually has somewhat decent AI, then I am impressed :)
Quote from: PhoenixFire on May 17, 2014, 02:12:49 PM
Hmm, I found one problem right off the bat; It requires the VXA RTP to run. You need to fix that =p
Other than that, I like the concept, and if it actually has somewhat decent AI, then I am impressed :)
Thanks for telling me. Including the RTP will make the file enormous though. I'll see if I can remove dependencies on RTP.
Added VX Version
You actually don't have to include the whole RTP. Do you know how to do this? If no, I'll see if I can find the tutorial I used to use, and if it's gone, I'll just write up a new one.. It's pretty easy to do, and I'm sure you'll benefit from it a bit :)
Quote from: PhoenixFire on May 17, 2014, 04:05:42 PM
You actually don't have to include the whole RTP. Do you know how to do this? If no, I'll see if I can find the tutorial I used to use, and if it's gone, I'll just write up a new one.. It's pretty easy to do, and I'm sure you'll benefit from it a bit :)
That would be awesome
I do apologize that it's on another forum, but this is the guide I used when I was new to RMXP, and it was really easy for me to follow, so I tend to suggest this to new game makers..
http://forum.chaos-project.com/index.php/topic,41.0.html
New version up. It's now much stronger and fully functional with castling and check working.
it seems the dll can't be used in Windows XP
(https://rmrk.net/proxy.php?request=http%3A%2F%2Fi.imgur.com%2FRwy8Rxk.jpg&hash=01855f6ecfef2eee4e0bd2d95239c320786fcbdd)