ruby_chess 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +3 -0
- data/Gemfile +6 -0
- data/README.md +39 -0
- data/Rakefile +1 -0
- data/bin/ruby_chess +5 -0
- data/lib/board.rb +187 -0
- data/lib/errors.rb +32 -0
- data/lib/game.rb +60 -0
- data/lib/pieces/bishop.rb +19 -0
- data/lib/pieces/king.rb +21 -0
- data/lib/pieces/knight.rb +25 -0
- data/lib/pieces/pawn.rb +41 -0
- data/lib/pieces/piece.rb +42 -0
- data/lib/pieces/queen.rb +22 -0
- data/lib/pieces/rook.rb +20 -0
- data/lib/pieces/sliding_piece.rb +36 -0
- data/lib/pieces/stepping_piece.rb +19 -0
- data/lib/pieces.rb +6 -0
- data/lib/players/computer_player.rb +63 -0
- data/lib/players/human_player.rb +27 -0
- data/lib/ruby_chess/version.rb +3 -0
- data/lib/ruby_chess.rb +49 -0
- data/ruby_chess.gemspec +20 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0f9cebf323ed1409f108613fc3f1403b327858f4
|
4
|
+
data.tar.gz: 801a167cb2e0c90e86ae7811fd39ceb09e351eb5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f7cdb3f6eb1c0558f54fb686912fff36a4e468991f21aa4959bd1e3002c823df2a5181ec7192ed2fde286952dc1929debbfbca0a29a4ee90abe7b4ba4b60938
|
7
|
+
data.tar.gz: 6aa63e24024b75cb0d2e85d7edd3a8c50a14361527564cd51534b2b3d01295d495a3cb7bf254856f7047561837fbee952a66020755ac810925851c4d6e07872c
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# RubyChess
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ruby_chess`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'ruby_chess'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install ruby_chess
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it ( https://github.com/[my-github-username]/ruby_chess/fork )
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/ruby_chess
ADDED
data/lib/board.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'colorize'
|
3
|
+
require 'io/console'
|
4
|
+
require_relative 'pieces'
|
5
|
+
require_relative 'errors'
|
6
|
+
|
7
|
+
class Board
|
8
|
+
|
9
|
+
attr_reader :grid, :cursor
|
10
|
+
|
11
|
+
def initialize(setup = true)
|
12
|
+
@grid = Array.new(8) { Array.new(8) }
|
13
|
+
@cursor = [0,0]
|
14
|
+
|
15
|
+
populate_board if setup
|
16
|
+
end
|
17
|
+
|
18
|
+
def move(start_pos, end_pos, color)
|
19
|
+
raise OffBoardError unless on_board?(start_pos) && on_board?(end_pos)
|
20
|
+
raise NoPieceError unless piece_at(start_pos)
|
21
|
+
raise WrongColorError unless piece_at(start_pos).color == color
|
22
|
+
|
23
|
+
current_piece = piece_at(start_pos)
|
24
|
+
if current_piece.valid_moves.include?(end_pos)
|
25
|
+
move!(start_pos, end_pos)
|
26
|
+
else
|
27
|
+
raise InvalidMoveError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def move!(start_pos, end_pos)
|
32
|
+
current_piece = piece_at(start_pos)
|
33
|
+
self[start_pos] = nil
|
34
|
+
self[end_pos] = current_piece
|
35
|
+
current_piece.pos = end_pos
|
36
|
+
current_piece.moved = true
|
37
|
+
end
|
38
|
+
|
39
|
+
def move_cursor
|
40
|
+
input = ""
|
41
|
+
until input == "\r"
|
42
|
+
render(@cursor)
|
43
|
+
input = STDIN.getch
|
44
|
+
@cursor[0] += 1 if input == 'k' && @cursor[0] + 1 < 8
|
45
|
+
@cursor[0] -= 1 if input == 'i' && @cursor[0] - 1 >= 0
|
46
|
+
@cursor[1] -= 1 if input == 'j' && @cursor[1] - 1 >= 0
|
47
|
+
@cursor[1] += 1 if input == 'l' && @cursor[1] + 1 < 8
|
48
|
+
|
49
|
+
end
|
50
|
+
@cursor.dup
|
51
|
+
end
|
52
|
+
|
53
|
+
def [](pos)
|
54
|
+
@grid[pos.first][pos.last]
|
55
|
+
end
|
56
|
+
|
57
|
+
def []=(pos, piece)
|
58
|
+
@grid[pos.first][pos.last] = piece
|
59
|
+
end
|
60
|
+
|
61
|
+
def on_board?(pos)
|
62
|
+
(pos[0]).between?(0, 7) && (pos[1]).between?(0, 7)
|
63
|
+
end
|
64
|
+
|
65
|
+
def occupied?(pos)
|
66
|
+
return false unless on_board?(pos)
|
67
|
+
!!self[pos]
|
68
|
+
end
|
69
|
+
|
70
|
+
def won?
|
71
|
+
checkmate?(:white) || checkmate?(:black)
|
72
|
+
end
|
73
|
+
|
74
|
+
def stalemate?(color)
|
75
|
+
pieces(color).all? { |piece| piece.valid_moves.empty? } && !in_check?(color)
|
76
|
+
end
|
77
|
+
|
78
|
+
def piece_at(pos)
|
79
|
+
self[pos]
|
80
|
+
end
|
81
|
+
|
82
|
+
def checkmate?(color)
|
83
|
+
pieces(color).all? { |piece| piece.valid_moves.empty? } &&
|
84
|
+
in_check?(color)
|
85
|
+
end
|
86
|
+
|
87
|
+
def in_check?(color)
|
88
|
+
opponent_color = color == :white ? :black : :white
|
89
|
+
king_pos = king(color).pos
|
90
|
+
pieces(opponent_color).any? do |piece|
|
91
|
+
piece.moves.include?(king_pos)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def deep_dup
|
96
|
+
dup_board = Board.new(false)
|
97
|
+
|
98
|
+
[:white, :black].each do |color|
|
99
|
+
pieces(color).each do |piece|
|
100
|
+
duped_piece = piece.dup(dup_board)
|
101
|
+
dup_board[duped_piece.pos] = duped_piece
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
dup_board
|
106
|
+
end
|
107
|
+
|
108
|
+
def render(cursor = nil)
|
109
|
+
system('clear')
|
110
|
+
print (" " + ('a'..'h').to_a.join(" ") + "\n")
|
111
|
+
self.grid.each_with_index do |row, i|
|
112
|
+
print "#{i + 1} "
|
113
|
+
row.each_with_index do |space, j|
|
114
|
+
if cursor.nil?
|
115
|
+
if (i + j).odd?
|
116
|
+
background = :light_black
|
117
|
+
else
|
118
|
+
background = :light_blue
|
119
|
+
end
|
120
|
+
else
|
121
|
+
if @cursor == [i,j]
|
122
|
+
background = :yellow
|
123
|
+
elsif (i + j).odd?
|
124
|
+
background = :light_black
|
125
|
+
else
|
126
|
+
background = :light_blue
|
127
|
+
end
|
128
|
+
end
|
129
|
+
if space.nil?
|
130
|
+
print ' '.colorize(:background => background)
|
131
|
+
else
|
132
|
+
print "#{space.symbol} ".colorize(:color => space.color,
|
133
|
+
:background => background)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
print " #{i + 1}"
|
137
|
+
puts
|
138
|
+
end
|
139
|
+
print (" " + ('a'..'h').to_a.join(" ") + "\n")
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def king(color)
|
144
|
+
pieces(color).find { |piece| piece.is_a?(King)}
|
145
|
+
end
|
146
|
+
|
147
|
+
def pieces(color)
|
148
|
+
pieces = @grid.flatten.compact
|
149
|
+
pieces.select { |piece| piece.color == color}
|
150
|
+
end
|
151
|
+
|
152
|
+
def populate_board
|
153
|
+
[[1,:white], [6, :black]].each do |row|
|
154
|
+
@grid[row.first].map!.with_index do |space, i|
|
155
|
+
Pawn.new(self, row.last, [row.first, i])
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
[[0, :white], [7, :black]].each do |row|
|
160
|
+
@grid[row.first].map!.with_index do |space, i|
|
161
|
+
case i
|
162
|
+
when 0
|
163
|
+
Rook.new(self, row.last, [row.first, i])
|
164
|
+
when 1
|
165
|
+
Knight.new(self, row.last, [row.first, i])
|
166
|
+
when 2
|
167
|
+
Bishop.new(self, row.last, [row.first, i])
|
168
|
+
when 3
|
169
|
+
King.new(self, row.last, [row.first, i])
|
170
|
+
when 4
|
171
|
+
Queen.new(self, row.last, [row.first, i])
|
172
|
+
when 5
|
173
|
+
Bishop.new(self, row.last, [row.first, i])
|
174
|
+
when 6
|
175
|
+
Knight.new(self, row.last, [row.first, i])
|
176
|
+
when 7
|
177
|
+
Rook.new(self, row.last, [row.first, i])
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
if __FILE__ == $PROGRAM_NAME
|
185
|
+
board = Board.new
|
186
|
+
board.render
|
187
|
+
end
|
data/lib/errors.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
class MoveError < IOError
|
2
|
+
end
|
3
|
+
|
4
|
+
class InvalidMoveError < MoveError
|
5
|
+
def message
|
6
|
+
"Not one of the possible moves for that piece."
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class NoPieceError < MoveError
|
11
|
+
def message
|
12
|
+
"You didn't select a piece."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class WrongColorError < MoveError
|
17
|
+
def message
|
18
|
+
"You are attempting to move your opponent's piece"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class BadInputError < MoveError
|
23
|
+
def message
|
24
|
+
"Excuse me? Please provide valid input."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class OffBoardError < MoveError
|
29
|
+
def message
|
30
|
+
"That position is off the board."
|
31
|
+
end
|
32
|
+
end
|
data/lib/game.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'board'
|
3
|
+
require_relative 'players/human_player.rb'
|
4
|
+
require_relative 'players/computer_player.rb'
|
5
|
+
|
6
|
+
class Game
|
7
|
+
attr_accessor :board
|
8
|
+
|
9
|
+
def initialize(player_white, player_black)
|
10
|
+
@board = Board.new
|
11
|
+
@player_white = player_white
|
12
|
+
@player_white.board = @board
|
13
|
+
@player_black = player_black
|
14
|
+
@player_black.board = @board
|
15
|
+
@current_player = player_white
|
16
|
+
end
|
17
|
+
|
18
|
+
def right_color?(pos)
|
19
|
+
@board[pos].color == @current_player.color
|
20
|
+
end
|
21
|
+
|
22
|
+
def switch_player
|
23
|
+
if @current_player == @player_white
|
24
|
+
@current_player = @player_black
|
25
|
+
else
|
26
|
+
@current_player = @player_white
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def game_status
|
31
|
+
message = ""
|
32
|
+
if @board.in_check?(@current_player.color)
|
33
|
+
message += "#{@current_player.color.to_s.capitalize} is in check \n"
|
34
|
+
end
|
35
|
+
message += "#{@current_player.color.to_s.capitalize}'s turn \n"
|
36
|
+
end
|
37
|
+
|
38
|
+
def play
|
39
|
+
until @board.won? || @board.stalemate?(@current_player.color)
|
40
|
+
begin
|
41
|
+
board.render
|
42
|
+
puts game_status
|
43
|
+
start_pos, end_pos = @current_player.make_move
|
44
|
+
@board.move(start_pos, end_pos, @current_player.color)
|
45
|
+
switch_player
|
46
|
+
rescue MoveError => e
|
47
|
+
puts e.message
|
48
|
+
puts "Enter to continue"
|
49
|
+
gets
|
50
|
+
end
|
51
|
+
end
|
52
|
+
board.render
|
53
|
+
if @board.stalemate?(@current_player.color)
|
54
|
+
puts "Stalemate"
|
55
|
+
else
|
56
|
+
switch_player
|
57
|
+
puts "#{@current_player.color.to_s.capitalize} wins!"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/pieces/king.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'stepping_piece'
|
3
|
+
|
4
|
+
class King < SteppingPiece
|
5
|
+
def symbol
|
6
|
+
'♚'
|
7
|
+
end
|
8
|
+
|
9
|
+
def move_diffs
|
10
|
+
[
|
11
|
+
[1, 1],
|
12
|
+
[1, 0],
|
13
|
+
[0, 1],
|
14
|
+
[-1, 1],
|
15
|
+
[1, -1],
|
16
|
+
[-1, -1],
|
17
|
+
[-1, 0],
|
18
|
+
[0, -1]
|
19
|
+
]
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'stepping_piece'
|
3
|
+
|
4
|
+
class Knight < SteppingPiece
|
5
|
+
def symbol
|
6
|
+
'♞'
|
7
|
+
end
|
8
|
+
|
9
|
+
def move_diffs
|
10
|
+
[
|
11
|
+
[1, 2],
|
12
|
+
[2, 1],
|
13
|
+
[-1, 2],
|
14
|
+
[2, -1],
|
15
|
+
[-1, -2],
|
16
|
+
[-2, -1],
|
17
|
+
[-2, 1],
|
18
|
+
[1, -2]
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def value
|
23
|
+
3
|
24
|
+
end
|
25
|
+
end
|
data/lib/pieces/pawn.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'piece'
|
3
|
+
|
4
|
+
class Pawn < Piece
|
5
|
+
NORMAL_MOVE = [1, 0]
|
6
|
+
INITIAL_MOVE = [2, 0]
|
7
|
+
ATTACK_MOVES = [[1, 1], [1, -1]]
|
8
|
+
|
9
|
+
|
10
|
+
def symbol
|
11
|
+
'♟'
|
12
|
+
end
|
13
|
+
|
14
|
+
def moves
|
15
|
+
moves = []
|
16
|
+
modifier = self.color == :white ? 1 : -1
|
17
|
+
|
18
|
+
normal_move = sum_positions(NORMAL_MOVE.map { |move| move * modifier }, @pos)
|
19
|
+
unless @board.occupied?(normal_move)
|
20
|
+
moves << normal_move
|
21
|
+
end
|
22
|
+
|
23
|
+
initial_move = sum_positions(INITIAL_MOVE.map { |move| move * modifier }, @pos)
|
24
|
+
if !@moved && moves.include?(normal_move) && !@board.occupied?(initial_move)
|
25
|
+
moves << initial_move
|
26
|
+
end
|
27
|
+
|
28
|
+
ATTACK_MOVES.each do |attack_move|
|
29
|
+
potential_pos = sum_positions(@pos.dup, attack_move.map { |move| move * modifier })
|
30
|
+
if @board.occupied?(potential_pos) && @board.piece_at(potential_pos).color != @color
|
31
|
+
moves << potential_pos
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
moves.select { |move| @board.on_board?(move)}
|
36
|
+
end
|
37
|
+
|
38
|
+
def value
|
39
|
+
1
|
40
|
+
end
|
41
|
+
end
|
data/lib/pieces/piece.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
class Piece
|
3
|
+
attr_reader :color
|
4
|
+
attr_accessor :pos, :moved
|
5
|
+
|
6
|
+
def initialize(board, color, pos)
|
7
|
+
@board = board
|
8
|
+
@color = color
|
9
|
+
@pos = pos
|
10
|
+
@moved = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def in_range_of_enemy?
|
14
|
+
@color == :white ? enemy_color = :black : enemy_color = :white
|
15
|
+
@board.pieces(enemy_color).each do |piece|
|
16
|
+
return true if piece.valid_moves.include?(@pos)
|
17
|
+
end
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def symbol
|
22
|
+
raise NotImplementedError.new ("No symbol!")
|
23
|
+
end
|
24
|
+
|
25
|
+
def dup(dup_board)
|
26
|
+
self.class.new(dup_board, @color, @pos.dup)
|
27
|
+
end
|
28
|
+
|
29
|
+
def valid_moves
|
30
|
+
moves.reject { |move| move_into_check?(move) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def move_into_check?(move)
|
34
|
+
duped_board = @board.deep_dup
|
35
|
+
duped_board.move!(self.pos, move)
|
36
|
+
duped_board.in_check?(@color)
|
37
|
+
end
|
38
|
+
|
39
|
+
def sum_positions(pos1, pos2)
|
40
|
+
[pos1.first + pos2.first, pos1.last + pos2.last]
|
41
|
+
end
|
42
|
+
end
|
data/lib/pieces/queen.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'sliding_piece'
|
3
|
+
|
4
|
+
class Queen < SlidingPiece
|
5
|
+
def symbol
|
6
|
+
'♛'
|
7
|
+
end
|
8
|
+
|
9
|
+
def move_dirs
|
10
|
+
[[1, 0],
|
11
|
+
[0, 1],
|
12
|
+
[-1, 0],
|
13
|
+
[0, -1],
|
14
|
+
[1, 1],
|
15
|
+
[-1, 1],
|
16
|
+
[1, -1],
|
17
|
+
[-1, -1]]
|
18
|
+
end
|
19
|
+
def value
|
20
|
+
9
|
21
|
+
end
|
22
|
+
end
|
data/lib/pieces/rook.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'piece'
|
3
|
+
|
4
|
+
class SlidingPiece < Piece
|
5
|
+
|
6
|
+
def moves
|
7
|
+
moves = []
|
8
|
+
move_dirs.each do |dir|
|
9
|
+
moves += explore(dir)
|
10
|
+
end
|
11
|
+
|
12
|
+
moves
|
13
|
+
end
|
14
|
+
|
15
|
+
def explore(dir)
|
16
|
+
pos = @pos.dup
|
17
|
+
positions = []
|
18
|
+
|
19
|
+
while @board.on_board?([pos[0] + dir[0], pos[1] + dir[1]])
|
20
|
+
pos[0] += dir[0]
|
21
|
+
pos[1] += dir[1]
|
22
|
+
if @board.occupied?(pos)
|
23
|
+
if @board.piece_at(pos).color == self.color
|
24
|
+
break
|
25
|
+
else
|
26
|
+
positions << pos.dup
|
27
|
+
break
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
positions << pos.dup
|
32
|
+
end
|
33
|
+
|
34
|
+
positions
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'piece'
|
3
|
+
|
4
|
+
class SteppingPiece < Piece
|
5
|
+
|
6
|
+
def moves
|
7
|
+
moves = []
|
8
|
+
move_diffs.each do |diff|
|
9
|
+
new_pos = [@pos.first + diff.first, @pos.last + diff.last]
|
10
|
+
next unless @board.on_board?(new_pos)
|
11
|
+
if @board.occupied?(new_pos)
|
12
|
+
next if @board.piece_at(new_pos).color == self.color
|
13
|
+
end
|
14
|
+
moves << new_pos
|
15
|
+
end
|
16
|
+
|
17
|
+
moves
|
18
|
+
end
|
19
|
+
end
|
data/lib/pieces.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
class ComputerPlayer
|
2
|
+
attr_reader :color
|
3
|
+
attr_writer :board
|
4
|
+
|
5
|
+
def initialize(color)
|
6
|
+
@color = color
|
7
|
+
end
|
8
|
+
|
9
|
+
def make_move
|
10
|
+
valid_moves_hash = {}
|
11
|
+
@board.pieces(@color).each do |piece|
|
12
|
+
valid_moves_hash[piece.pos] = piece.valid_moves unless piece.valid_moves.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
rand_key = valid_moves_hash.keys.sample
|
16
|
+
random_move = [rand_key, valid_moves_hash[rand_key].sample]
|
17
|
+
|
18
|
+
good_moves = []
|
19
|
+
neutral_moves = []
|
20
|
+
death_moves = []
|
21
|
+
|
22
|
+
valid_moves_hash.each_pair do |start_pos, potential_positions|
|
23
|
+
potential_positions.each do |potential_pos|
|
24
|
+
if death_move?([start_pos, potential_pos])
|
25
|
+
death_moves << [start_pos, potential_pos]
|
26
|
+
elsif @board.piece_at(potential_pos)
|
27
|
+
good_moves << [start_pos, potential_pos]
|
28
|
+
else
|
29
|
+
neutral_moves << [start_pos, potential_pos]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
sleep(0.001)
|
34
|
+
|
35
|
+
if !good_moves.empty?
|
36
|
+
chosen_move = best_move(good_moves)
|
37
|
+
elsif !neutral_moves.empty?
|
38
|
+
chosen_move = neutral_moves.sample
|
39
|
+
else
|
40
|
+
chosen_move = death_moves.sample
|
41
|
+
end
|
42
|
+
chosen_move
|
43
|
+
end
|
44
|
+
|
45
|
+
#finds highest value target from good_moves
|
46
|
+
#GOOD MOVES MUST BE AN ARRAY OF CAPTURE MOVES
|
47
|
+
def best_move(good_moves)
|
48
|
+
best_move = good_moves.sample
|
49
|
+
good_moves.each do |move|
|
50
|
+
if @board.piece_at(move.last).value >
|
51
|
+
@board.piece_at(best_move.last).value
|
52
|
+
best_move = move
|
53
|
+
end
|
54
|
+
end
|
55
|
+
best_move
|
56
|
+
end
|
57
|
+
|
58
|
+
def death_move?(move)
|
59
|
+
duped_board = @board.deep_dup
|
60
|
+
duped_board.move!(move.first, move.last)
|
61
|
+
duped_board.piece_at(move.last).in_range_of_enemy?
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class HumanPlayer
|
2
|
+
attr_reader :color
|
3
|
+
attr_writer :board
|
4
|
+
|
5
|
+
def initialize(color)
|
6
|
+
@color = color
|
7
|
+
end
|
8
|
+
|
9
|
+
def make_move
|
10
|
+
# puts "Enter your move"
|
11
|
+
# i1, i2 = gets.chomp.split
|
12
|
+
# raise BadInputError if i2.nil?
|
13
|
+
|
14
|
+
i1 = @board.move_cursor
|
15
|
+
|
16
|
+
i2 = @board.move_cursor
|
17
|
+
|
18
|
+
[i1, i2]
|
19
|
+
end
|
20
|
+
|
21
|
+
# def input_to_pos(input)
|
22
|
+
# letter, number = input.split("")
|
23
|
+
# coord2 = letter.ord - 'a'.ord
|
24
|
+
# coord1 = number.to_i - 1
|
25
|
+
# [coord1, coord2]
|
26
|
+
# end
|
27
|
+
end
|
data/lib/ruby_chess.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'game'
|
3
|
+
require_relative 'players/human_player.rb'
|
4
|
+
require_relative 'players/computer_player.rb'
|
5
|
+
|
6
|
+
class RubyChess
|
7
|
+
|
8
|
+
def run
|
9
|
+
clear_screen
|
10
|
+
choose_players
|
11
|
+
game = Game.new(@white_player, @black_player)
|
12
|
+
game.play
|
13
|
+
run if reset == 'y' || reset =='Y' || reset == 'yes' || reset == 'Yes'
|
14
|
+
end
|
15
|
+
|
16
|
+
def choose_players
|
17
|
+
puts "Welcome to RubyChess by Joe Daly"
|
18
|
+
puts
|
19
|
+
puts "Who will play white? (Human or Computer)"
|
20
|
+
white_choice = gets.chomp
|
21
|
+
puts "Who will play black? (Human or Computer)"
|
22
|
+
black_choice = gets.chomp
|
23
|
+
|
24
|
+
set_players(white_choice, black_choice)
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear_screen
|
28
|
+
system('clear')
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset
|
32
|
+
puts "Would you like to play again? (y/n)"
|
33
|
+
gets.chomp
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_players(white_choice, black_choice)
|
37
|
+
if white_choice == 'Human' || white_choice == 'human'
|
38
|
+
@white_player = HumanPlayer.new(:white)
|
39
|
+
else
|
40
|
+
@white_player = ComputerPlayer.new(:white)
|
41
|
+
end
|
42
|
+
if black_choice == 'Human' || black_choice == 'human'
|
43
|
+
@black_player = HumanPlayer.new(:black)
|
44
|
+
else
|
45
|
+
@black_player = ComputerPlayer.new(:black)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/ruby_chess.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ruby_chess/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ruby_chess"
|
8
|
+
spec.version = RubyChess::VERSION
|
9
|
+
spec.authors = ["Joseph Daly"]
|
10
|
+
spec.email = ["josefdaly@gmail.com"]
|
11
|
+
spec.summary = "Joe's Chess game for ruby"
|
12
|
+
spec.description = "Joe's Chess game for ruby"
|
13
|
+
spec.homepage = "https://github.com/josefdaly/RubyChess"
|
14
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
15
|
+
spec.executables = ["ruby_chess"]
|
16
|
+
spec.require_paths = ["lib"]
|
17
|
+
|
18
|
+
spec.add_development_dependency "bundler", "~> 1.9"
|
19
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_chess
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joseph Daly
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.9'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.9'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Joe's Chess game for ruby
|
42
|
+
email:
|
43
|
+
- josefdaly@gmail.com
|
44
|
+
executables:
|
45
|
+
- ruby_chess
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- ".travis.yml"
|
51
|
+
- Gemfile
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- bin/ruby_chess
|
55
|
+
- lib/board.rb
|
56
|
+
- lib/errors.rb
|
57
|
+
- lib/game.rb
|
58
|
+
- lib/pieces.rb
|
59
|
+
- lib/pieces/bishop.rb
|
60
|
+
- lib/pieces/king.rb
|
61
|
+
- lib/pieces/knight.rb
|
62
|
+
- lib/pieces/pawn.rb
|
63
|
+
- lib/pieces/piece.rb
|
64
|
+
- lib/pieces/queen.rb
|
65
|
+
- lib/pieces/rook.rb
|
66
|
+
- lib/pieces/sliding_piece.rb
|
67
|
+
- lib/pieces/stepping_piece.rb
|
68
|
+
- lib/players/computer_player.rb
|
69
|
+
- lib/players/human_player.rb
|
70
|
+
- lib/ruby_chess.rb
|
71
|
+
- lib/ruby_chess/version.rb
|
72
|
+
- ruby_chess.gemspec
|
73
|
+
homepage: https://github.com/josefdaly/RubyChess
|
74
|
+
licenses: []
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.4.6
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Joe's Chess game for ruby
|
96
|
+
test_files: []
|