OSDN Git Service

Fix #36230: Support Fischer Time Control
[shogi-server/shogi-server.git] / shogi_server / time_clock.rb
1 ## $Id$
2
3 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
4 ## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
5 ##
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
10 ##
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ## GNU General Public License for more details.
15 ##
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, write to the Free Software
18 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 module ShogiServer # for a namespace
21
22 # Abstract class to caclulate thinking time.
23 #
24 class TimeClock
25
26   def TimeClock.factory(least_time_per_move, game_name)
27     time_map = Game.parse_time game_name
28
29     if time_map[:stop_watch]
30       @time_clock = StopWatchClock.new(least_time_per_move, time_map[:total_time], time_map[:byoyomi])
31     else
32       if least_time_per_move == 0
33         @time_clock = ChessClockWithLeastZero.new(least_time_per_move,
34                                                   time_map[:total_time],
35                                                   time_map[:byoyomi],
36                                                   time_map[:fischer])
37       else
38         @time_clock = ChessClock.new(least_time_per_move,
39                                      time_map[:total_time],
40                                      time_map[:byoyomi],
41                                      time_map[:fischer])
42       end
43     end
44
45     @time_clock
46   end
47
48   def initialize(least_time_per_move, total_time, byoyomi, fischer=0)
49     @least_time_per_move = least_time_per_move
50     @total_time = total_time
51     @byoyomi    = byoyomi
52     @fischer    = fischer
53   end
54
55   # Returns thinking time duration
56   #
57   def time_duration(mytime, start_time, end_time)
58     # implement this
59     return 9999999
60   end
61
62   # Returns what "Time_Unit:" in CSA protocol should provide.
63   #
64   def time_unit
65     return "1sec"
66   end
67
68   # If thinking time runs out, returns true; false otherwise.
69   #
70   def timeout?(player, start_time, end_time)
71     # implement this
72     return true
73   end
74
75   # Updates a player's remaining time and returns thinking time.
76   #
77   def process_time(player, start_time, end_time)
78     t = time_duration(player.mytime, start_time, end_time)
79
80     player.mytime += @fischer
81     player.mytime -= t
82     if (player.mytime < 0)
83       player.mytime = 0
84     end
85
86     return t
87   end
88 end
89
90 # Calculates thinking time with chess clock.
91 #
92 class ChessClock < TimeClock
93   def initialize(least_time_per_move, total_time, byoyomi, fischer=0)
94     super
95   end
96
97   def time_duration(mytime, start_time, end_time)
98     return [(end_time - start_time).floor, @least_time_per_move].max
99   end
100
101   def timeout?(player, start_time, end_time)
102     t = time_duration(player.mytime, start_time, end_time)
103
104     if ((player.mytime - t + @byoyomi + @fischer <= 0) &&
105         ((@total_time > 0) || (@byoyomi > 0) || (@fischer > 0)))
106       return true
107     else
108       return false
109     end
110   end
111
112   def to_s
113     return "ChessClock: LeastTimePerMove %d; TotalTime %d; Byoyomi %d; Fischer" %
114       [@least_time_per_move, @total_time, @byoyomi, @fischer]
115   end
116 end
117
118 # Calculates thinking time with chess clock, truncating decimal seconds for
119 # thinking time. This is a new rule that CSA introduced in November 2014.
120 #
121 # least_time_per_move should be 0.
122 # byoyomi should be more than 0.
123 #
124 class ChessClockWithLeastZero < ChessClock
125   def initialize(least_time_per_move, total_time, byoyomi, fischer=0)
126     if least_time_per_move != 0
127       raise ArgumentError, "least_time_per_move #{least_time_per_move} should be 0."
128     end
129     super
130   end
131
132   def to_s
133     return "ChessClockWithLeastZero: LeastTimePerMove %d; TotalTime %d; Byoyomi %d; Fischer %d" %
134       [@least_time_per_move, @total_time, @byoyomi, @fischer]
135   end
136 end
137
138 # StopWatchClock does not support Fischer time.
139 #
140 class StopWatchClock < TimeClock
141   def initialize(least_time_per_move, total_time, byoyomi)
142     super least_time_per_move, total_time, byoyomi, 0
143   end
144
145   def time_unit
146     return "1min"
147   end
148
149   def time_duration(mytime, start_time, end_time)
150     t = [(end_time - start_time).floor, @least_time_per_move].max
151     return (t / @byoyomi) * @byoyomi
152   end
153
154   def timeout?(player, start_time, end_time)
155     t = time_duration(player.mytime, start_time, end_time)
156
157     if (player.mytime <= t)
158       return true
159     else
160       return false
161     end
162   end
163
164   def to_s
165     return "StopWatchClock: LeastTimePerMove %d; TotalTime %d; Byoyomi %d" % [@least_time_per_move, @total_time, @byoyomi]
166   end
167 end
168
169 end