From 35e307a6e3ecac136e18f68afb406d46df36bddf Mon Sep 17 00:00:00 2001
From: Paolo Capriotti
Date: Sun, 28 Jun 2009 17:29:21 +0200
Subject: [PATCH] Refactored controller event handling.
---
lib/controller.rb | 70 +++++++++++++++++++++----------------------
lib/history.rb | 8 +++++
lib/interaction/match.rb | 20 +++++++++++--
lib/mainwindow.rb | 2 +-
lib/plugins/engines/xboard.rb | 2 +-
5 files changed, 62 insertions(+), 40 deletions(-)
diff --git a/lib/controller.rb b/lib/controller.rb
index cd7fa9e..a99fa9d 100644
--- a/lib/controller.rb
+++ b/lib/controller.rb
@@ -49,6 +49,7 @@ class Controller
def reset(match)
@match = match
@policy = match.game.policy.new
+ @current = match.history.current
@table.reset(@match)
@board = @table.elements[:board]
@@ -74,13 +75,13 @@ class Controller
clock.data = { :color => col,
:player => match.player(col).name }
end
- @noncontrolled = @match.observe(:move) do |data|
- unless @controlled[data[:player].color] == data[:player]
- animate(:forward, data[:state], data[:move])
- @board.highlight(data[:move])
- @clocks[data[:old_state].turn].stop
- @clocks[data[:state].turn].start
- end
+
+ @match.history.observe(:current_changed) { refresh }
+ @match.history.observe(:new_move) { refresh }
+
+ @match.observe(:move) do |data|
+ @clocks[data[:old_state].turn].stop
+ @clocks[data[:state].turn].start
end
@clocks[@match.game.players.first].active = true
@@ -93,45 +94,44 @@ class Controller
def perform!(move, opts = {})
col = @match.state.turn
- if @controlled[col] and @match.move(@controlled[col], move)
- animate(:forward, @match.state, move, opts)
- @board.highlight(move)
-
- @clocks[col].stop
- @clocks[@match.state.turn].start
+ if @controlled[col]
+ @match.move(@controlled[col], move)
end
end
def back
- state, move = @match.history.back
- animate(:back, state, move)
- @board.highlight(@match.history.move)
+ @match.history.back
rescue History::OutOfBound
puts "error: first move"
end
def forward
- state, move = @match.history.forward
- animate(:forward, state, move)
- @board.highlight(move)
+ @match.history.forward
rescue History::OutOfBound
puts "error: last move"
end
- def go_to(index)
- cur = @match.history.current
- state, move = @match.history.go_to(index)
- if index > cur
- (cur + 1..index).each do |i|
- animate(:forward, @match.history[i].state, @match.history[i].move)
- end
- @board.highlight(move)
- elsif index < cur
- (cur).downto(index + 1).each do |i|
- animate(:back, @match.history[i - 1].state, @match.history[i].move)
+ # sync displayed state with current history item
+ #
+ def refresh
+ if @match
+ index = @match.history.current
+ if index > @current
+ (@current + 1..index).each do |i|
+ animate(:forward, @match.history[i].state, @match.history[i].move)
+ end
+ elsif index < @current
+ @current.downto(index + 1).each do |i|
+ animate(:back, @match.history[i - 1].state, @match.history[i].move)
+ end
end
- @board.highlight(@match.history.move)
+ @current = index
+ @board.highlight(@match.history[@current].move)
end
+ end
+
+ def go_to(index)
+ @match.history.go_to(index)
rescue History::OutOfBound
puts "error: no such index #{index}"
end
@@ -257,11 +257,9 @@ class Controller
end
def color=(value)
- if @match
- # ignore further moves from other players
- @match.delete_observer(@noncontrolled)
- @match.close
- end
+ @match.close if @match
+ @match = nil
+
@color = value
if @color
@controlled = { @color => self }
diff --git a/lib/history.rb b/lib/history.rb
index b33e6f6..e4a90a7 100644
--- a/lib/history.rb
+++ b/lib/history.rb
@@ -55,6 +55,14 @@ class History
[item.state, item.move]
end
+ def go_to_last
+ go_to(size - 1)
+ end
+
+ def go_to_first
+ go_to(0)
+ end
+
def state
@history[current].state
end
diff --git a/lib/interaction/match.rb b/lib/interaction/match.rb
index 4bf00ba..ae1e2eb 100644
--- a/lib/interaction/match.rb
+++ b/lib/interaction/match.rb
@@ -21,6 +21,7 @@ class Match
@history = nil
@kind = opts[:kind] || :local
@editable = opts.fetch(:editable, true)
+ @closed = false
@info = { }
end
@@ -53,7 +54,14 @@ class Match
end
def move(player, move, state = nil)
+ return false if @closed
return false unless @history
+
+ # if the match is non-editable, jump to the last move
+ unless editable?
+ @history.go_to_last
+ end
+
# if player is nil, assume the current player is moving
if player == nil
player = current_player
@@ -64,7 +72,10 @@ class Match
validate = @game.validator.new(@history.state)
valid = validate[move]
- return false unless valid
+ unless valid
+ warn "Invalid move from #{player.name}: #{move}"
+ return false
+ end
old_state = @history.state
state = old_state.dup
@@ -95,7 +106,7 @@ class Match
end
def state
- @history.state
+ @history[index].state
end
def editable?
@@ -106,11 +117,16 @@ class Match
@players.keys.find{|p| p.color == color }
end
+ # end the match
+ # players must not send any more 'move' events to
+ # a closed game
+ #
def close(result = nil, message = nil)
@info[:result] = result if result
broadcast nil, :close => {
:result => result,
:message => message }
+ @closed = true
end
def info
diff --git a/lib/mainwindow.rb b/lib/mainwindow.rb
index eefde55..f6944fb 100644
--- a/lib/mainwindow.rb
+++ b/lib/mainwindow.rb
@@ -157,7 +157,7 @@ private
diag = NewGame.new(self, @engine_loader, current_game)
diag.observe(:ok) do |data|
game = data[:game]
- match = Match.new(game)
+ match = Match.new(game, :editable => data[:engines].empty?)
match.observe(:started) { @controller.reset(match) }
diff --git a/lib/plugins/engines/xboard.rb b/lib/plugins/engines/xboard.rb
index 6810f57..28fb74c 100644
--- a/lib/plugins/engines/xboard.rb
+++ b/lib/plugins/engines/xboard.rb
@@ -115,7 +115,7 @@ class XBoardEngine
end
def on_command_move(move)
- move = @serializer.deserialize(move, @match.history.state)
+ move = @serializer.deserialize(move, @match.state)
if move
@match.move(self, move)
end
--
2.11.4.GIT