Class: MailChess::Game

Inherits:
Object
  • Object
show all
Defined in:
lib/mail_chess/game.rb

Overview

Represents a chess game.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db, game_id, initiator) ⇒ Game

Create a new Game object.

Arguments:

db: Sequel database object
game_id: (Integer)
initiator: (Symbol) :white or :black


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/mail_chess/game.rb', line 33

def initialize db, game_id, initiator
  @db = db

  Game.create_tables(@db) if Game.need_to_create_tables?(@db)

  @db_entry = @db[:games].filter(:id => game_id).first

  @id = @db_entry[:id].to_i
  @reference = @db_entry[:reference]
  @current = @db_entry[:current].to_sym
  @board = Board.load! @db, :id, @db_entry[:board_id]

  @players = Hash.new
  @db[:pairs].filter(:game_id => @id).all.each do |p|
    @players[p[:color].to_sym] = Player.load!(@db, :id, p[:player_id].to_i)
  end

  @initiator = initiator
end

Instance Attribute Details

#boardObject (readonly)

Board belongs to this game.



16
17
18
# File 'lib/mail_chess/game.rb', line 16

def board
  @board
end

#currentObject

Current player’s color.



22
23
24
# File 'lib/mail_chess/game.rb', line 22

def current
  @current
end

#idObject (readonly)

Game ID in database.



10
11
12
# File 'lib/mail_chess/game.rb', line 10

def id
  @id
end

#initiatorObject (readonly)

Who tries to move.



25
26
27
# File 'lib/mail_chess/game.rb', line 25

def initiator
  @initiator
end

#playersObject (readonly)

Players hash. (keys: :white, :black)



19
20
21
# File 'lib/mail_chess/game.rb', line 19

def players
  @players
end

#referenceObject (readonly)

Game reference.



13
14
15
# File 'lib/mail_chess/game.rb', line 13

def reference
  @reference
end

Class Method Details

.create_tables(db) ⇒ Object

Create tables.



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
# File 'lib/mail_chess/game.rb', line 62

def self.create_tables db
  db.create_table? :boards do
    primary_key :id
  end

  db.create_table? :games do
    primary_key :id
    String :reference
    String :current
    foreign_key :board_id, :boards, :key => :id
  end

  db.create_table? :players do
    primary_key :id
    String :name
    String :email
  end

  db.create_table? :pairs do
    primary_key :id
    foreign_key :player_id, :players, :key => :id
    foreign_key :game_id, :games, :key => :id
    String :color
  end
end

.load!(db, filter, value, initiator) ⇒ Object

Load game from database.

Arguments:

db: Sequel database object
filter: (Symbol) :id or :reference
value: filters value
initiator: (Symbol) :white or :black

Returns: (Game)

Raises:

  • (ArgumentError)


123
124
125
126
127
128
129
130
# File 'lib/mail_chess/game.rb', line 123

def self.load! db, filter, value, initiator
  raise ArgumentError unless [:id, :reference].index(filter)
  dataset = db[:games].filter(filter => value)
  return nil unless dataset.all.size == 1
  id = dataset.first[:id]

  return Game.new db, id, initiator
end

.need_to_create_tables?(db) ⇒ Boolean

Checks if needed to create tables.

Returns: (Boolean)

Returns:

  • (Boolean)


56
57
58
59
# File 'lib/mail_chess/game.rb', line 56

def self.need_to_create_tables? db
  return (db.tables + [:boards, :games, :players, 
                       :pairs]).uniq.size != db.tables.size
end

.new!(db, white, black, reference) ⇒ Object

Create a new game object and save it to database.

Arguments:

db: Sequel database object
white: (Player) first player
black: (Player) second player
reference: (String)

Returns: (Game)



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/mail_chess/game.rb', line 97

def self.new! db, white, black, reference
  Game.create_tables(db) if Game.need_to_create_tables?(db)

  b = Board.new! db
  id = db[:games].insert(:reference => reference,
                         :current => 'white',
                         :board_id => b.id)
  db[:pairs].insert(:player_id => white.id,
                    :game_id => id,
                    :color => 'white')
  db[:pairs].insert(:player_id => black.id,
                    :game_id => id,
                    :color => 'black')

  return Game.new db, id, :white
end

Instance Method Details

#delete!Object

Delete game – save! won’t fix it!



138
139
140
141
142
143
# File 'lib/mail_chess/game.rb', line 138

def delete!
  @board.delete!
  @db[:pairs].filter(:game_id => @id).delete
  @db[:games].filter(:id => @id).delete
  @db[:boards].filter(:id => @board.id).delete
end

#perform!(move) ⇒ Object

Perform the move.

Arguments:

move: (String) eg.: e2e4

Exceptions:

(MoveError) if move is invalid
(TurnError) if this is not the requester's turn

Raises:



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/mail_chess/game.rb', line 153

def perform! move
  from, to = move[0] + move[1], move[2] + move[3]
  p = @board.pieces[from]
  k = nil

  @board.pieces.values.each do |piece|
    k = piece if piece.type == 'king' and piece.color == @current
  end

  raise TurnError.new('not your turn') if @initiator != @current
  raise MoveError.new('piece not exists') if p == nil
  raise MoveError.new('not your piece') if p.color != @current
  raise MoveError.new('invalid move') if !p.can_move?(to) & !p.can_hit?(to)

  old_p = @board.pieces[to]
  p.move to

  raise MoveError.new('checkmate') if k.in_checkmate?
  raise MoveError.new('king in check') if k.in_check?

  old_p.delete! if old_p
  @current = (@current == :white ? :black : :white)
  @board.save!
  save!
end

#save!Object

Save game – update the current field.



133
134
135
# File 'lib/mail_chess/game.rb', line 133

def save!
  @db[:games].filter(:id => @id).update(:current => current.to_s)
end