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