## $Id$
## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 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
class Board
+ # Initial board setup.
+ # The string ends with '+', not a line break.
+ #
+ INITIAL_HIRATE_POSITION = (<<-EOF).chomp
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI * * * * * -KA *
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 * * * * * * * * *
+P5 * * * * * * * * *
+P6 * * * * * * * * *
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA * * * * * +HI *
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
+EOF
+
# Split a moves line into an array of a move string.
# If it fails to parse the moves, it raises WrongMoves.
- # @param moves a moves line. Ex. "+776FU-3334Fu"
- # @return an array of a move string. Ex. ["+7776FU", "-3334FU"]
+ # @param moves a moves line. Ex. "+776FU-3334FU" or
+ # moves with times. Ex "+776FU,T2-3334FU,T5"
+ # @return an array of a move string. Ex. ["+7776FU", "-3334FU"] or
+ # an array of arrays. Ex. [["+7776FU","T2"], ["-3334FU", "T5"]]
#
def Board.split_moves(moves)
ret = []
- rs = moves.gsub %r{[\+\-]\d{4}\w{2}} do |s|
- ret << s
- ""
- end
- raise WrongMoves, rs unless rs.empty?
+ i=0
+ tmp = ""
+ while i<moves.size
+ if moves[i,1] == "+" ||
+ moves[i,1] == "-" ||
+ i == moves.size - 1
+ if i == moves.size - 1
+ tmp << moves[i,1]
+ end
+ unless tmp.empty?
+ a = tmp.split(",")
+ if a[0].size != 7
+ raise WrongMoves, a[0]
+ end
+ if a.size == 1 # "+7776FU"
+ ret << a[0]
+ else # "+7776FU,T2"
+ unless /^T\d+/ =~ a[1]
+ raise WrongMoves, a[1]
+ end
+ ret << a
+ end
+ tmp = ""
+ end
+ end
+ tmp << moves[i,1]
+ i += 1
+ end
return ret
end
+
def initialize(move_count=0)
@sente_hands = Array::new
@gote_hands = Array::new
@move_count = move_count
@teban = nil # black => true, white => false
@initial_moves = []
+ @move = nil
+ @ous = [nil, nil] # keep OU pieces of Sente and Gote
end
attr_accessor :array, :sente_hands, :gote_hands, :history, :sente_history, :gote_history, :teban
attr_reader :move_count
# moves.
attr_reader :initial_moves
+ # A move parsed by handle_one_move. If the move is not :normal, the board
+ # position may or may not be rolled back.
+ #
+ attr_reader :move
+
# See if self equals rhs, including a logical board position (i.e.
# not see object IDs) and sennichite stuff.
#
@teban = true
end
+ # Cache OU piece.
+ # Piece#new will call back this method.
+ #
+ def add_ou(ou)
+ if ou.sente
+ @ous[0] = ou
+ else
+ @ous[1] = ou
+ end
+ end
+
# Set up a board with the strs.
# Failing to parse the moves raises an StandardError.
# @param strs a board text
# Set up a board starting with a position after the moves.
# Failing to parse the moves raises an ArgumentError.
- # @param moves an array of moves. ex. ["+7776FU", "-3334FU"]
+ # @param moves an array of moves. ex. ["+7776FU", "-3334FU"] or
+ # an array of arrays. ex. [["+7776FU","T2"], ["-3334FU","T5"]]
#
def set_from_moves(moves)
initial()
return :normal if moves.empty?
rt = nil
moves.each do |move|
- rt = handle_one_move(move, @teban)
+ rt = nil
+ case move
+ when Array
+ rt = handle_one_move(move[0], @teban)
+ when String
+ rt = handle_one_move(move, @teban)
+ end
raise ArgumentError, "bad moves: #{moves}" unless rt == :normal
end
@initial_moves = moves.dup
end
# def each_reserved_square
-
+
def look_for_ou(sente)
- x = 1
- while (x <= 9)
- y = 1
- while (y <= 9)
- if (@array[x][y] &&
- (@array[x][y].name == "OU") &&
- (@array[x][y].sente == sente))
- return @array[x][y]
- end
- y = y + 1
- end
- x = x + 1
+ if sente
+ return @ous[0]
+ else
+ return @ous[1]
end
- raise "can't find ou"
end
# See if sente is checked (i.e. loosing) or not.
return :illegal # can't put on existing piece
end
- move = Move.new(x0, y0, x1, y1, name, sente)
- result = move_to(move)
+ @move = Move.new(x0, y0, x1, y1, name, sente)
+ result = move_to(@move)
if (result == :illegal)
# self is unchanged
return :illegal
end
if (checkmated?(sente))
- move_back(move)
+ move_back(@move)
return :oute_kaihimore
end
if ((x0 == 0) && (y0 == 0) && (name == "FU") && uchifuzume?(sente))
- move_back(move)
+ move_back(@move)
return :uchifuzume
end
update_sennichite(sente)
os_result = oute_sennichite?(sente)
if os_result # :oute_sennichite_sente_lose or :oute_sennichite_gote_lose
- move_back(move)
+ move_back(@move)
restore_sennichite_stuff(*sennichite_stuff)
return os_result
end
if sennichite?
- move_back(move)
+ move_back(@move)
restore_sennichite_stuff(*sennichite_stuff)
return :sennichite
end
return :normal
end
+ # Return a CSA-styled string notation of the current position.
+ #
def to_s
a = Array::new
y = 1
a.push("%s\n" % [@teban ? "+" : "-"])
return a.join
end
+
+ # Return a CSA-styled string notation of the initial position.
+ #
+ def initial_string
+ tmp_board = self.class.new
+ tmp_board.initial
+ return tmp_board.to_s
+ end
end
end # ShogiServer