OSDN Git Service

11980425d784db1c49fdeb904eae80d4fa0ad447
[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     total_time_str = nil
28     byoyomi_str = nil
29     if (game_name =~ /-(\d+)-(\d+)$/)
30       total_time_str = $1
31       byoyomi_str    = $2
32     end
33     total_time = total_time_str.to_i
34     byoyomi    = byoyomi_str.to_i
35  
36     if (byoyomi_str == "060")
37       @time_clock = StopWatchClock.new(least_time_per_move, total_time, byoyomi)
38     else
39       if least_time_per_move == 0
40         @time_clock = ChessClockWithLeastZero.new(least_time_per_move, total_time, byoyomi)
41       else
42         @time_clock = ChessClock.new(least_time_per_move, total_time, byoyomi)
43       end
44     end
45   end
46
47   def initialize(least_time_per_move, total_time, byoyomi)
48     @least_time_per_move = least_time_per_move
49     @total_time = total_time
50     @byoyomi     = byoyomi
51   end
52
53   # Returns thinking time duration
54   #
55   def time_duration(mytime, start_time, end_time)
56     # implement this
57     return 9999999
58   end
59
60   # Returns what "Time_Unit:" in CSA protocol should provide.
61   #
62   def time_unit
63     return "1sec"
64   end
65
66   # If thinking time runs out, returns true; false otherwise.
67   #
68   def timeout?(player, start_time, end_time)
69     # implement this
70     return true
71   end
72
73   # Updates a player's remaining time and returns thinking time.
74   #
75   def process_time(player, start_time, end_time)
76     t = time_duration(player.mytime, start_time, end_time)
77     
78     player.mytime -= t
79     if (player.mytime < 0)
80       player.mytime = 0
81     end
82
83     return t
84   end
85 end
86
87 # Calculates thinking time with chess clock.
88 #
89 class ChessClock < TimeClock
90   def initialize(least_time_per_move, total_time, byoyomi)
91     super
92   end
93
94   def time_duration(mytime, start_time, end_time)
95     return [(end_time - start_time).floor, @least_time_per_move].max
96   end
97
98   def timeout?(player, start_time, end_time)
99     t = time_duration(player.mytime, start_time, end_time)
100
101     if ((player.mytime - t <= -@byoyomi) && 
102         ((@total_time > 0) || (@byoyomi > 0)))
103       return true
104     else
105       return false
106     end
107   end
108
109   def to_s
110     return "ChessClock: LeastTimePerMove %d; TotalTime %d; Byoyomi %d" % [@least_time_per_move, @total_time, @byoyomi]
111   end
112 end
113
114 # Calculates thinking time with chess clock, truncating decimal seconds for
115 # thinking time. This is a new rule that CSA introduced in November 2014.
116 #
117 # least_time_per_move should be 0.
118 # byoyomi should be more than 0.
119 #
120 class ChessClockWithLeastZero < ChessClock
121   def initialize(least_time_per_move, total_time, byoyomi)
122     if least_time_per_move != 0
123       raise ArgumentError, "least_time_per_move #{least_time_per_move} should be 0."
124     end
125     super
126   end
127
128   def time_duration(mytime, start_time, end_time)
129     t = end_time - start_time
130     if @byoyomi > 0
131       # If the remaining thinking time covers the duration t, floor it.
132       if mytime + @byoyomi - t > 0
133         t = t.floor
134       else
135         t = t.ceil
136       end
137     else
138       # Thinking time only
139       t = t.floor
140     end
141
142     return t
143   end
144
145   def to_s
146     return "ChessClockWithLeastZero: LeastTimePerMove %d; TotalTime %d; Byoyomi %d" % [@least_time_per_move, @total_time, @byoyomi]
147   end
148 end
149
150 class StopWatchClock < TimeClock
151   def initialize(least_time_per_move, total_time, byoyomi)
152     super
153   end
154
155   def time_unit
156     return "1min"
157   end
158
159   def time_duration(mytime, start_time, end_time)
160     t = [(end_time - start_time).floor, @least_time_per_move].max
161     return (t / @byoyomi) * @byoyomi
162   end
163
164   def timeout?(player, start_time, end_time)
165     t = time_duration(player.mytime, start_time, end_time)
166
167     if (player.mytime <= t)
168       return true
169     else
170       return false
171     end
172   end
173
174   def to_s
175     return "StopWatchClock: LeastTimePerMove %d; TotalTime %d; Byoyomi %d" % [@least_time_per_move, @total_time, @byoyomi]
176   end
177 end
178
179 end