patternrubyMinor
Object-Oriented Chess Game in Ruby
Viewed 0 times
chessgamerubyorientedobject
Problem
I wrote a chess game in Ruby using object-oriented principles.
One of the challenges was deciding which particular methods/actions belonged to a particular class, as there were some that felt as if they could go in any class.
General rationale for OOP choices:
Chess
Player
```
class Player
attr_accessor :color, :pieces, :captured_pieces
def initialize(color)
@color = color
@captured_pieces = []
@pieces = [Pawn.new(color),
Pawn.new(color),
Pawn.new(color),
Pawn.new(color),
Pawn.ne
One of the challenges was deciding which particular methods/actions belonged to a particular class, as there were some that felt as if they could go in any class.
General rationale for OOP choices:
- Pieces should be as dumb as possible. They should return their available moves regardless of the current state of the board/game (I tried to ensure they didn't hold much information).
- Board should be made up of Square objects which have Pieces on them (or not). Board should have a general idea of what moves are available and what moves are not, based on the state of the board. It should also keep a History of past moves.
- Player should generally know about his/her own pieces and they should be the ones that know what a piece can and cannot do.
- Game should control the flow of the game (whose turn it is, what move that player wants to make, whether or not that move is a valid choice, etc.) Game also checks for stalemate, three-fold repetition, fifty-move rule, insufficient material, check, and checkmate.
- The game can also be saved in YAML and saved games can be loaded from the YAML file.
Chess
require 'colored'
require './lib/player'
require './lib/board'
require './lib/history'
require './lib/square'
require './lib/game'
require './lib/piece'
require './lib/pawn'
require './lib/rook'
require './lib/knight'
require './lib/bishop'
require './lib/queen'
require './lib/king'
require 'yaml'
def play_again?
puts "Play again? (yes or no)".green
answer = gets.chomp.downcase
return answer == "yes"
end
loop do
Game.new.play_game
unless play_again?
puts "Goodbye"
break
end
endPlayer
```
class Player
attr_accessor :color, :pieces, :captured_pieces
def initialize(color)
@color = color
@captured_pieces = []
@pieces = [Pawn.new(color),
Pawn.new(color),
Pawn.new(color),
Pawn.new(color),
Pawn.ne
Solution
Biggest syntax suggestion
There's a lot of repetition and naming issues that makes the code hard to read. For example,
Biggest OOP design suggestion
Pieces should be as dumb as possible
If
There's a lot of repetition and naming issues that makes the code hard to read. For example,
Player#valid_move? could instead be (ignoring correctness of logic):def valid_move?(from_square, to_square, piece)
is_pawn = piece.is_a?(Pawn) # not sure why of all piece types, pawns are specifically being singled out here
same_x = to_square.x == from_square.x # not sure why only x is being checked
dest_occupied = !!to_square.piece_on_square
land_on_enemy_piece = dest_occupied && to_square.piece_on_square.color == piece.color # give a name to this "concept"
if is_pawn && !same_x && land_on_enemy_piece
piece.get_valid_captures(from_square, to_square)
elsif !is_pawn || (same_x && !dest_occupied)
piece.get_valid_moves(from_square, to_square)
else
false
end
end
Biggest OOP design suggestion
Pieces should be as dumb as possible
Pieces ought to define how they move, but they shouldn't be able to Piece.get_valid_moves. Determining valid moves requires a few things:- How a piece generally moves
- The piece's position on the board
- State of the board/where other pieces are
- Whether pieces in their path are allies or enemies
If
Pieces can determine valid moves, they'd need to "know" nearly everything on the board. This defeats the purpose of OO Encapsulation! If pieces are "dumb" and well-encapsulated, then Piece is a lower level abstraction and Board and Player depends on Piece, not the other way around.Context
StackExchange Code Review Q#116994, answer score: 2
Revisions (0)
No revisions yet.