(current) and StopWatchClock (new).
StopWatchClock, which is usually used at official games of human
professional players, is a clock where thiking time less than a
miniute is regarded as zero.
To select StopWatchClock, use a special game name with "060"
byoyomi time. ex. "gamename_1500_060".
+2013-04-07 Daigo Moriwaki <daigo at debian dot org>
+
+ * [shogi-server]
+ - shogi_server/{game,time_clock}.rb:
+ Adds variations of thinking time calculation: ChessClock
+ (current) and StopWatchClock (new).
+ StopWatchClock, which is usually used at official games of human
+ professional players, is a clock where thiking time less than a
+ miniute is regarded as zero.
+ To select StopWatchClock, use a special game name with "060"
+ byoyomi time. ex. "gamename_1500_060".
+
2013-03-31 Daigo Moriwaki <daigo at debian dot org>
* [shogi-server]
require 'shogi_server/league/floodgate'
require 'shogi_server/game_result'
+require 'shogi_server/time_clock'
require 'shogi_server/util'
module ShogiServer # for a namespace
if (@game_name =~ /-(\d+)-(\d+)$/)
@total_time = $1.to_i
@byoyomi = $2.to_i
+
+ @time_clock = TimeClock::factory(Least_Time_Per_Move, @game_name)
end
if (player0.sente)
$league.games[@game_id] = self
log_message(sprintf("game created %s", @game_id))
+ log_message(" " + @time_clock.to_s)
@start_time = nil
@fh = open(@logfile, "w")
propose
end
- attr_accessor :game_name, :total_time, :byoyomi, :sente, :gote, :game_id, :board, :current_player, :next_player, :fh, :monitors
+ attr_accessor :game_name, :total_time, :byoyomi, :sente, :gote, :game_id, :board, :current_player, :next_player, :fh, :monitors, :time_clock
attr_accessor :last_move, :current_turn
attr_reader :result, :prepared_time
return nil
end
- finish_flag = true
@end_time = end_time
- t = [(@end_time - @start_time).floor, Least_Time_Per_Move].max
-
+ finish_flag = true
move_status = nil
- if ((@current_player.mytime - t <= -@byoyomi) &&
- ((@total_time > 0) || (@byoyomi > 0)))
+
+ if (@time_clock.timeout?(@current_player, @start_time, @end_time))
status = :timeout
elsif (str == :timeout)
return false # time isn't expired. players aren't swapped. continue game
else
- @current_player.mytime -= t
- if (@current_player.mytime < 0)
- @current_player.mytime = 0
- end
-
+ t = @time_clock.process_time(@current_player, @start_time, @end_time)
move_status = @board.handle_one_move(str, @sente == @current_player)
# log_debug("move_status: %s for %s's %s" % [move_status, @sente == @current_player ? "BLACK" : "WHITE", str])
--- /dev/null
+## $Id$
+
+## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
+## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+module ShogiServer # for a namespace
+
+# Abstract class to caclulate thinking time.
+#
+class TimeClock
+
+ def TimeClock.factory(least_time_per_move, game_name)
+ total_time_str = nil
+ byoyomi_str = nil
+ if (game_name =~ /-(\d+)-(\d+)$/)
+ total_time_str = $1
+ byoyomi_str = $2
+ end
+ total_time = total_time_str.to_i
+ byoyomi = byoyomi_str.to_i
+
+ if (byoyomi_str == "060")
+ @time_clock = StopWatchClock.new(least_time_per_move, total_time, byoyomi)
+ else
+ @time_clock = ChessClock.new(least_time_per_move, total_time, byoyomi)
+ end
+ end
+
+ def initialize(least_time_per_move, total_time, byoyomi)
+ @least_time_per_move = least_time_per_move
+ @total_time = total_time
+ @byoyomi = byoyomi
+ end
+
+ # Returns thinking time duration
+ #
+ def time_duration(start_time, end_time)
+ # implement this
+ return 9999999
+ end
+
+ # If thinking time runs out, returns true; false otherwise.
+ #
+ def timeout?(player, start_time, end_time)
+ # implement this
+ return true
+ end
+
+ # Updates a player's remaining time and returns thinking time.
+ #
+ def process_time(player, start_time, end_time)
+ t = time_duration(start_time, end_time)
+
+ player.mytime -= t
+ if (player.mytime < 0)
+ player.mytime = 0
+ end
+
+ return t
+ end
+end
+
+# Calculates thinking time with chess clock.
+#
+class ChessClock < TimeClock
+ def initialize(least_time_per_move, total_time, byoyomi)
+ super
+ end
+
+ def time_duration(start_time, end_time)
+ return [(end_time - start_time).floor, @least_time_per_move].max
+ end
+
+ def timeout?(player, start_time, end_time)
+ t = time_duration(start_time, end_time)
+
+ if ((player.mytime - t <= -@byoyomi) &&
+ ((@total_time > 0) || (@byoyomi > 0)))
+ return true
+ else
+ return false
+ end
+ end
+
+ def to_s
+ return "ChessClock: LeastTimePerMove %d; TotalTime %d; Byoyomi %d" % [@least_time_per_move, @total_time, @byoyomi]
+ end
+end
+
+class StopWatchClock < TimeClock
+ def initialize(least_time_per_move, total_time, byoyomi)
+ super
+ end
+
+ def time_duration(start_time, end_time)
+ t = [(end_time - start_time).floor, @least_time_per_move].max
+ return (t / @byoyomi) * @byoyomi
+ end
+
+ def timeout?(player, start_time, end_time)
+ t = time_duration(start_time, end_time)
+
+ if (player.mytime <= t)
+ return true
+ else
+ return false
+ end
+ end
+
+ def to_s
+ return "StopWatchClock: LeastTimePerMove %d; TotalTime %d; Byoyomi %d" % [@least_time_per_move, @total_time, @byoyomi]
+ end
+end
+
+end
require 'TC_pairing'
require 'TC_player'
require 'TC_rating'
+require 'TC_time_clock'
require 'TC_uchifuzume'
require 'TC_usi'
require 'TC_util'
c.decide_new_buoy_game_name
assert_equal "buoy_denou_13-14400-60", c.new_buoy_game
end
+
+ def test_new_buoy_game_name2
+ src = "%%FORK server+denou-14400-060+p1+p2+20130223185013"
+ c = ShogiServer::ForkCommand.new src, @player, "server+denou-14400-060+p1+p2+20130223185013", nil, 13
+ c.decide_new_buoy_game_name
+ assert_equal "buoy_denou_13-14400-060", c.new_buoy_game
+ end
end
#
--- /dev/null
+$:.unshift File.join(File.dirname(__FILE__), "..")
+require 'test/unit'
+require 'test/mock_player'
+require 'shogi_server/board'
+require 'shogi_server/game'
+require 'shogi_server/player'
+
+class DummyPlayer
+ def initialize(mytime)
+ @mytime = mytime
+ end
+ attr_reader :mytime
+end
+
+class TestTimeClockFactor < Test::Unit::TestCase
+ def test_chess_clock
+ c = ShogiServer::TimeClock::factory(1, "hoge-900-0")
+ assert_instance_of(ShogiServer::ChessClock, c)
+
+ c = ShogiServer::TimeClock::factory(1, "hoge-1500-60")
+ assert_instance_of(ShogiServer::ChessClock, c)
+ end
+
+ def test_stop_watch_clock
+ c = ShogiServer::TimeClock::factory(1, "hoge-1500-060")
+ assert_instance_of(ShogiServer::StopWatchClock, c)
+ end
+end
+
+class TestChessClock < Test::Unit::TestCase
+ def test_time_duration
+ tc = ShogiServer::ChessClock.new(1, 1500, 60)
+ assert_equal(1, tc.time_duration(100.1, 100.9))
+ assert_equal(1, tc.time_duration(100, 101))
+ assert_equal(1, tc.time_duration(100.1, 101.9))
+ assert_equal(2, tc.time_duration(100.1, 102.9))
+ assert_equal(2, tc.time_duration(100, 102))
+ end
+
+ def test_without_byoyomi
+ tc = ShogiServer::ChessClock.new(1, 1500, 0)
+
+ p = DummyPlayer.new 100
+ assert(!tc.timeout?(p, 100, 101))
+ assert(!tc.timeout?(p, 100, 199))
+ assert(tc.timeout?(p, 100, 200))
+ assert(tc.timeout?(p, 100, 201))
+ end
+
+ def test_with_byoyomi
+ tc = ShogiServer::ChessClock.new(1, 1500, 60)
+
+ p = DummyPlayer.new 100
+ assert(!tc.timeout?(p, 100, 101))
+ assert(!tc.timeout?(p, 100, 259))
+ assert(tc.timeout?(p, 100, 260))
+ assert(tc.timeout?(p, 100, 261))
+
+ p = DummyPlayer.new 30
+ assert(!tc.timeout?(p, 100, 189))
+ assert(tc.timeout?(p, 100, 190))
+ end
+
+ def test_with_byoyomi2
+ tc = ShogiServer::ChessClock.new(1, 0, 60)
+
+ p = DummyPlayer.new 0
+ assert(!tc.timeout?(p, 100, 159))
+ assert(tc.timeout?(p, 100, 160))
+ end
+end
+
+class TestStopWatchClock < Test::Unit::TestCase
+ def test_time_duration
+ tc = ShogiServer::StopWatchClock.new(1, 1500, 60)
+ assert_equal(0, tc.time_duration(100.1, 100.9))
+ assert_equal(0, tc.time_duration(100, 101))
+ assert_equal(0, tc.time_duration(100, 159.9))
+ assert_equal(60, tc.time_duration(100, 160))
+ assert_equal(60, tc.time_duration(100, 219))
+ assert_equal(120, tc.time_duration(100, 220))
+ end
+
+ def test_with_byoyomi
+ tc = ShogiServer::StopWatchClock.new(1, 600, 60)
+
+ p = DummyPlayer.new 60
+ assert(!tc.timeout?(p, 100, 159))
+ assert(tc.timeout?(p, 100, 160))
+ end
+end
+