def gets_safe(t = nil)
if (t && t > 0)
begin
+ return :exception if closed?
timeout(t) do
return self.gets
end
end
else
begin
+ return nil if closed?
return self.gets
rescue
return nil
Release.concat("-") if (Release == "")
Revision = "$Revision$".gsub(/[^\.\d]/, '')
-
-
class League
class Floodgate
begin
sleep(10)
next if Time.now < @next_time
+ @league.reload
match_game
charge
rescue Exception => ex
Floodgate.game_name?(pl.game_name) &&
pl.sente == nil
end
- random_match(players)
- end
-
- def random_match(players)
- if players.size < 2
- log_message("Floodgate: too few players [%d]" % [players.size])
- return
- end
- log_message("Floodgate: found %d players. Making games..." % [players.size])
- random_players = players.sort{ rand < 0.5 ? 1 : -1 }
- pairs = [[random_players.shift]]
- while !random_players.empty? do
- if pairs.last.size < 2
- pairs.last << random_players.shift
- else
- pairs << [random_players.shift]
- end
- end
- if pairs.last.size < 2
- pairs.pop
- end
- pairs.each do |pair|
- start_game(pair.first, pair.last)
- end
- end
-
- def start_game(p1, p2)
- p1.sente = true
- p2.sente = false
- Game.new(p1.game_name, p1, p2)
+ load File.join(File.dirname(__FILE__), "pairing.rb")
+ Pairing.default_pairing.match(players)
end
end # class Floodgate
attr_accessor :players, :games, :event, :dir
def shutdown
+ @mutex.synchronize do
+ @players.each {|a| save(a)}
+ end
@floodgate.shutdown
end
def delete(player)
@mutex.synchronize do
+ save(player)
@players.delete(player.name)
end
end
+ def reload
+ @mutex.synchronize do
+ @players.each {|player| load(player)}
+ end
+ end
+
def find_all_players
found = nil
@mutex.synchronize do
def load(player)
hash = search(player.id)
- if hash
- # a current user
- player.name = hash['name']
- player.rate = hash['rate']
- player.modified_at = hash['last_modified']
- player.rating_group = hash['rating_group']
+ return unless hash
+
+ # a current user
+ player.name = hash['name']
+ player.rate = hash['rate'] || 0
+ player.modified_at = hash['last_modified']
+ player.rating_group = hash['rating_group']
+ player.win = hash['win'] || 0
+ player.loss = hash['loss'] || 0
+ player.last_game_win = hash['last_game_win'] || false
+ end
+
+ def save(player)
+ @db.transaction do
+ break unless @db["players"]
+ @db["players"].each do |group, players|
+ hash = players[player.id]
+ if hash
+ hash['last_game_win'] = player.last_game_win
+ break
+ end
+ end
end
end
def search(id)
hash = nil
- @db.transaction do
+ @db.transaction(true) do
break unless @db["players"]
@db["players"].each do |group, players|
hash = players[id]
class BasicPlayer
+ def initialize
+ @id = nil
+ @name = nil
+ @password = nil
+ @last_game_win = false
+ end
+
# Idetifier of the player in the rating system
attr_accessor :id
# Score in the rating sysem
attr_accessor :rate
+
+ # Number of games for win and loss in the rating system
+ attr_accessor :win, :loss
# Group in the rating system
attr_accessor :rating_group
# Last timestamp when the rate was modified
attr_accessor :modified_at
- def initialize
- @name = nil
- @password = nil
- end
+ # Whether win the previous game or not
+ attr_accessor :last_game_win
def modified_at
@modified_at || Time.now
@id != nil
end
+ def last_game_win?
+ return @last_game_win
+ end
+
def simple_id
if @trip
simple_name = @name.gsub(/@.*?$/, '')
begin
$mutex.lock
- if (@writer_thread == nil || @writer_thread.status == false)
+ if (@writer_thread == nil || !@writer_thread.status)
# The writer_thread has been killed because of socket errors.
return
end
rival = nil
if (League::Floodgate.game_name?(game_name))
if (my_sente_str != "*")
- write_safe(sprintf("##[ERROR] You are not allowed to specify TEBAN %s for the game %s\n"), my_sente_str, game_name)
+ write_safe(sprintf("##[ERROR] You are not allowed to specify TEBAN %s for the game %s\n", my_sente_str, game_name))
next
end
@sente = nil
return false
end
else # gote
- if ((rival_ou.y != 0) &&
+ if ((rival_ou.y != 1) &&
(@array[rival_ou.x][rival_ou.y - 1]) &&
(@array[rival_ou.x][rival_ou.y - 1].name == "FU") &&
(@array[rival_ou.x][rival_ou.y - 1].sente == sente)) # uchifu true
return false
end
end
-
+
## case: rival_ou is moving
- escaped = false
rival_ou.movable_grids.each do |(cand_x, cand_y)|
tmp_board = Marshal.load(Marshal.dump(self))
s = tmp_board.move_to(rival_ou.x, rival_ou.y, cand_x, cand_y, "OU", ! sente)
if (@array[x][y] &&
(@array[x][y].sente != sente) &&
@array[x][y].movable_grids.include?([fu_x, fu_y])) # capturable
+
+ names = []
if (@array[x][y].promoted)
- name = @array[x][y].promoted_name
+ names << @array[x][y].promoted_name
else
- name = @array[x][y].name
+ names << @array[x][y].name
+ if @array[x][y].promoted_name &&
+ @array[x][y].move_to?(fu_x, fu_y, @array[x][y].promoted_name)
+ names << @array[x][y].promoted_name
+ end
end
- tmp_board = Marshal.load(Marshal.dump(self))
- s = tmp_board.move_to(x, y, fu_x, fu_y, name, ! sente)
- raise "internal error" if (s != true)
- if (! tmp_board.checkmated?(! sente)) # good move
- return false
+ names.map! do |name|
+ tmp_board = Marshal.load(Marshal.dump(self))
+ s = tmp_board.move_to(x, y, fu_x, fu_y, name, ! sente)
+ if s == :illegal
+ s # result
+ else
+ tmp_board.checkmated?(! sente) # result
+ end
end
+ all_illegal = names.find {|a| a != :illegal}
+ raise "internal error: legal move not found" if all_illegal == nil
+ r = names.find {|a| a == false} # good move
+ return false if r == false # found good move
end
y = y + 1
end
def initialize(winner, loser)
super
@winner, @loser = winner, loser
+ @winner.last_game_win = true
+ @loser.last_game_win = false
end
def to_s
end
class GameResultDraw < GameResult
-
+ def initialize(p1, p2)
+ super
+ p1.last_game_win = false
+ p2.last_game_win = false
+ end
end
class Game
STDOUT.sync = true
STDERR.sync = true
TCPSocket.do_not_reverse_lookup = true
- Thread.abort_on_exception = true
+ Thread.abort_on_exception = $DEBUG ? true : false
LEAGUE = ShogiServer::League::new
main