-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchess.rb
executable file
·149 lines (124 loc) · 3.97 KB
/
chess.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
raise 'Ruby should be >= 2.2.0' unless RUBY_VERSION.to_f > 2.0
lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib)
require 'rubygems'
require 'bundler/setup'
require 'colorize'
require 'byebug'
require 'game_controller'
require 'cli_display'
FLASH_MESSAGES = {
:invalid_selection => "Invalid selection!",
:no_moves_available => "No moves available for that piece",
:player_is_in_check => "<PLAYER>, you are in check! Your moves are limited.",
:invalid_move => "Invalid move! Try again.",
:invalid_move_check => "No moves available for that piece - protect your king!",
:captured_piece => "You captured a <PIECE>!",
:castling => "(You may castle your king)",
:game_over => "CHECKMATE – <PLAYER> is victorious! Congratulations!"
}
# this is the heart of the chess game. this loop will run over and over
# until the user exits. it updates the screen, prompts the user based
# on the current state of the game, and waits for input.
def main_loop
@game = GameController.new
@display = CliDisplay.new(board: @game.board_state)
@input_state = :select_piece # select_piece
@active_tile = nil
while true
@display.update(@game.board_state)
exit if @game.state == :checkmate
prompt_for @input_state
input = gets.chomp
parse input
end # while true
end
private
def prompt_for(state)
# this determines what to display in each circumstance.
puts " "
prompt = "(#{@game.current_player[:name]}, #{@game.current_player[:home_base]})"
case state
when :select_piece
string = "#{prompt} Select a piece (e.g. a1)"
when :move_piece
string = "#{prompt} Select a highlighted tile (or '" + "c".underline + "ancel')"
when :game_won
exit
end
print string + " > "
end
def parse(cmd)
# takes the user's string and decides what to do with it.
case cmd
when "exit", "x", "q"; exit
when "cancel", "c"; process_command cmd
when "byebug"; byebug
when cmd[/^[a^-hA-H][1-8]$/]
# matches two-character commands beginning with a letter
# and ending with a number.
process_command cmd
else
@display.flash.push FLASH_MESSAGES[:invalid_selection]
select_piece @cur_piece if @cur_piece
end
end
def process_command(cmd)
case @input_state
when :select_piece; select_piece(cmd)
when :move_piece; move_piece(cmd)
end
end
def select_piece(cmd)
begin
cur_possible_moves = @game.select_piece(cmd)
if cur_possible_moves.any?
cur_possible_moves.each do |coord, move_type|
@display.paint_square coord, move_type, :high_priority
end
@active_tile = cmd
@input_state = :move_piece
if cur_possible_moves.values.include?(:castling_move)
@display.flash.push FLASH_MESSAGES[:castling]
end
else
@display.flash.push FLASH_MESSAGES[:no_moves_available]
@input_state = :select_piece
end
rescue Game::InvalidSelectionError
@display.flash.push FLASH_MESSAGES[:invalid_selection]
end
end
def move_piece(cmd)
return if cmd == "cancel"
result = @game.move_piece(cmd)
if result[:captured_piece]
@display.flash.push FLASH_MESSAGES[:captured_piece].gsub("<PIECE>", result[:captured_piece].to_s)
end
case result[:state]
when :success
@display.reset_display
when :invalid_move
@display.flash.push FLASH_MESSAGES[:invalid_move]
return select_piece(@active_tile)
when :invalid_move_check
@display.flash.push FLASH_MESSAGES[:invalid_move_check]
return select_piece(@active_tile)
when :check
@display.reset_display
@display.flash.push FLASH_MESSAGES[:player_is_in_check].gsub("<PLAYER>",@game.current_player[:name])
when :checkmate
@display.reset_display
@display.flash.push FLASH_MESSAGES[:game_over].gsub("<PLAYER>",@game.current_player[:name])
# yaaaay!
(1..8).each do |x|
(1..8).each do |y|
@display.paint_square [x,y], :win_square, :high_priority
end
end
else
raise
end
@input_state = :select_piece
end
main_loop