Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
#!/usr/bin/env ruby
# coding: utf-8
#===============================================================================
#
# どうぶつしょうぎ
#
#---------------------------------------------------------------
#
# 将棋盤クラス
#
# ABC
# ##########
# 1##麒獅象##
# 2## 雛 ##
# 3## 雛 ##
# 4##象獅麒##
# ##########
#
class Board < Array
def initialize(objs)
@objs = objs
wall = @objs[Wall]; empt = @objs[Empt]
self.clear
self << wall << wall << wall << wall << wall
self << wall << empt << empt << empt << wall
self << wall << empt << empt << empt << wall
self << wall << empt << empt << empt << wall
self << wall << empt << empt << empt << wall
self << wall << wall << wall << wall << wall
end
def [](x, y)
super(5 * y + x)
end
def []=(x, y, obj)
super(5 * y + x, obj)
end
def show(indent = '')
puts(indent + ' ABC')
axis_y = [ ' ', '1', '2', '3', '4', ' ' ]
(0..5).each {|y|
print(indent + axis_y.shift)
(0..4).each {|x|
print(self[x, y].char)
}
puts
}
end
def each_place
(1..4).each {|y|
(1..3).each {|x|
yield(self[x, y], x, y)
}
}
end
def each_piece(side)
each_place {|obj, x, y|
obj.side == side and yield(obj, x, y)
}
end
def each_empty_place
each_place {|obj, x, y|
obj.class == Empt and yield(x, y)
}
end
def pick(x, y)
piece = self[x, y]
self[x, y] = @objs[Empt]
piece
end
def tried?(side)
y = @objs[side][Lion].op_area
(1..3).each {|x|
(piece = self[x, y]).side == side and piece.class == Lion and return(true)
}
false
end
def caught?(side)
each_place {|obj, x, y|
obj.side == side and obj.class == Lion and return(false)
}
true
end
end
#---------------------------------------------------------------
#
# 持ち駒クラス
#
class Standby < Hash
def initialize(objs)
@objs = objs
self[:A] = []
self[:B] = []
end
def dup
dupe = super
dupe[:A] = self[:A].dup
dupe[:B] = self[:B].dup
dupe
end
def each_piece(side)
self[side].each {|piece|
yield(piece)
}
end
def show(side, indent = '')
pieces_h = ''; each_piece(side) {|piece|
pieces_h << piece.char
}
puts(indent + '持ち駒: [%s]' % pieces_h)
end
def pick(piece)
(pieces = self[piece.side]).each_index {|n|
pieces[n].class == piece.class and return(pieces.delete_at(n))
}
raise('you do not have it.')
end
end
#---------------------------------------------------------------
#
# 指し手クラス
#
class Hand < Array
def piece
self[0]
end
def to
self[1, 2]
end
def from
self.size == 3 ? false : self[3, 2]
end
def view
from ? '[%s][%d, %d]=>[%d, %d]' % [piece.char, *from, *to] : '[%s]=>[%d, %d]' % [piece.char, *to]
end
end
#---------------------------------------------------------------
#
# 勝負クラス
#
class Game
attr_reader :board, :standby
def initialize(objs, game = nil)
@objs = objs
if(game) # 状況のコピーを返す
@board = game.board.dup
@standby = game.standby.dup
else # 初期の状況を返す
@board = Board.new(objs)
@standby = Standby.new(objs)
end
end
def show(indent = '')
puts
@standby.show(:B, indent)
@board.show(indent)
@standby.show(:A, indent)
puts
end
#-----------------------------------------------------------
#
# 駒を取る
#
def pick(hand)
hand.from ? @board.pick(*hand.from) : @standby.pick(hand.piece) # 自分の駒/持ち駒を手に取った
end
#-----------------------------------------------------------
#
# 駒を置く
#
def put(hand)
# 対象の場所のオブジェクト/駒を得る
piece = hand.piece; x, y = *hand.to
obj = @board[x, y]
# 空き地に置けた
if(obj.class == Empt)
@board[x, y] = put_with_evol(hand)
# 壁があった
elsif(obj.class == Wall)
false
# 自分の駒があった
elsif(obj.side == piece.side)
false
# 相手の駒を取った
elsif(obj.side == piece.op_side)
@standby[piece.side] << @objs[piece.side][(it = obj.class) == Cock ? Baby : it] # (雛に戻して)持ち駒に加える
@board[x, y] = put_with_evol(hand)
end
end
#-----------------------------------------------------------
#
# 駒が成るか?
#
def put_with_evol(hand)
piece = hand.piece; x, y = *hand.to
(hand.from and piece.class == Baby and y == piece.op_area) ? @objs[piece.side][Cock] : piece
end
end
#---------------------------------------------------------------
#
# プレーヤクラス
#
class Player
attr_reader :side, :op_side, :name
def initialize(objs, side)
@objs = objs
@op_side = (@side = side) == :A ? :B : :A # :A 自分は手前、奥に攻める, :B 自分は奥、手前に攻める
end
#-----------------------------------------------------------
#
# 初期状態に駒を並べる
#
def setup(game, test = false)
if(@side == :A)
x = 1; y1 = 3; y2 = 4
elsif(@side == :B)
x = -1; y1 = 2; y2 = 1
end
game.put(Hand.new([@objs[@side][Baby], 2, y1]))
game.put(Hand.new([@objs[@side][Elep], 2 - x, y2]))
game.put(Hand.new([@objs[@side][Lion], 2, y2]))
game.put(Hand.new([@objs[@side][Graf], 2 + x, y2]))
end
end
#---------------------------------------------------------------
#
# 人間プレーヤクラス
#
class HumanPlayer < Player
def initialize(objs, side)
super
@name = 'あなた'
@inputs = {
'a' => 1, 'b' => 2, 'c' => 3,
'g' => objs[@side][Graf],
'e' => objs[@side][Elep],
'y' => objs[@side][Baby],
}
end
def think(game)
print('どれをどこに[ a1b2 | yc3 ]移動する?'); move = $stdin.readline
if((it = @inputs[move[0]]).is_a?(Numeric)) # anxn / bnxn / cnxn ?
piece = game.board[it, move[1].to_i]
hand = Hand.new([piece, @inputs[move[2]], move[3].to_i, it, move[1].to_i])
else
hand = Hand.new([it, @inputs[move[1]], move[2].to_i])
end
end
end
#---------------------------------------------------------------
#
# コンピュータプレーヤクラス
#
class ComputerPlayerX < Player
def initialize(objs, side, think_depth)
super(objs, side)
@name = 'ワタシ'
@think_depth = think_depth
@weight = {
Lion => 1000,
Graf => 60,
Elep => 50,
Baby => 30,
Cock => 70,
}
end
#-----------------------------------------------------------
#
# 再帰的に思考し、最善の手/状況の評価点を返す
#
def think(game, depth = 0, turn = 1) # turn 1:自分, -1:相手
debug = depth < 0 ? '> ' * (depth + 1) : false
#-------------------------------------------------------
#
# 読みの深さが一定に達したら、その状況の評価点を返す
#
if(depth > @think_depth)
return(evaluate(game) * turn)
#-------------------------------------------------------
#
# 打てる手について順に評価し、最高の評価点を返す
#
else
side, op_side, turn_h = turn > 0 ? [@side, @op_side, '自分'] : [@op_side, @side, '相手']
maxpoint = -999999; besthand = nil
tried = game.board.tried?(op_side) # 相手がトライ状態か?
game.board.each_piece(side) {|piece, x, y|
piece.each_move(x, y) {|tx, ty|
hand = Hand.new([piece, tx, ty, x, y])
virt_game = Game.new(@objs, game) # 状況を複製
virt_game.pick(hand)
virt_game.put(hand) or next # 手を打ってみて…
puts("\n" + debug + '[%s]の手%s...' % [turn_h, hand.view]) if(debug)
virt_game.show(debug) if(debug)
if(virt_game.board.caught?(op_side)) # 相手をキャッチしたか? → 勝ち
point = 999900 - depth
elsif(tried) # 相手がトライ状態か? → 負け
point = -999900 + depth
else
point = -think(virt_game, depth + 1, -turn) # 再帰的に思考する
end
point > maxpoint and maxpoint = point and besthand = hand
puts(debug + '[%s]の手%s...評価点[%d]' % [turn_h, hand.view, point]) if(debug)
}
}
tried or game.standby.each_piece(side) {|piece| # 相手がトライ状態なら持ち駒は考えない
game.board.each_empty_place {|tx, ty|
hand = Hand.new([piece, tx, ty])
virt_game = Game.new(@objs, game) # 状況を複製
virt_game.pick(hand)
virt_game.put(hand) or next # 手を打ってみて…
puts("\n" + debug + '[%s]の手%s...' % [turn_h, hand.view]) if(debug)
virt_game.show(debug) if(debug)
point = -think(virt_game, depth + 1, -turn) # 再帰的に思考する
point > maxpoint and maxpoint = point and besthand = hand
puts(debug + '[%s]の手%s...評価点[%d]' % [turn_h, hand.view, point]) if(debug)
}
}
depth == 0 and maxpoint.abs > 990000 and puts('読み切りました[%s]の勝ちです。' % (maxpoint > 0 ? 'ワタシ' : 'あなた'))
puts(debug + '最善の手を選択、[%s]の手%s...評価点[%d]' % [turn_h, besthand.view, maxpoint]) if(debug)
return(depth == 0 ? besthand : maxpoint) # 最後は評価点でなく、最善の手を返す
end
end
#-----------------------------------------------------------
#
# 手番後の状況の評価点を返す
#
def evaluate(game)
point = 0
game.board.each {|obj| # 将棋盤の駒の評価点
point += ((it = @weight[obj.class]) ? it : 0) * (obj.side == @side ? 1 : -1)
}
game.standby.each {|side, pieces| # 持ち駒の評価点
pieces.each {|piece|
point += ((it = @weight[piece.class]) ? it : 0) * (piece.side == @side ? 1 : -1)
}
}
point
end
end
#---------------------------------------------------------------
#
# 各オブジェクトの定義
#
class Obj
attr_reader :side, :op_side
def initialize
@side = @op_side = :N
end
end
class Empt < Obj
def initialize
super
end
def char
' '
end
end
class Wall < Obj
def initialize
super
end
def char
'##'
end
end
class Piece < Obj
attr_reader :moves, :op_area
def initialize(side)
@op_side, @op_area = (@side = side) == :A ? [:B, 1] : [:A, 4] # :A 自分は手前、奥に攻める
@side == :B and @moves.each {|xy| xy[1] = -xy[1] } # :B 自分は奥、手前に攻める
end
def color(char)
@side == :A and return("\e[34m\e[1;1m%s\e[0m" % char) # 青色
@side == :B and return("\e[31m\e[1;1m%s\e[0m" % char) # 赤色
return(char)
end
def each_move(x, y)
@moves.each {|dx, dy|
yield(x + dx, y + dy)
}
end
end
class Lion < Piece
def initialize(side)
@moves = [ [ 0, -1], [-1, -1], [-1, 0], [-1, 1], [ 0, 1], [ 1, 1], [ 1, 0], [ 1, -1] ]
super(side)
end
def char
color('獅')
end
end
class Graf < Piece
def initialize(side)
@moves = [ [ 0, -1], [-1, 0], [ 0, 1], [ 1, 0] ]
super(side)
end
def char
color('麒')
end
end
class Elep < Piece
def initialize(side)
@moves = [ [-1, -1], [-1, 1], [ 1, 1], [ 1, -1] ]
super(side)
end
def char
color('象')
end
end
class Baby < Piece
def initialize(side)
@moves = [ [ 0, -1], ]
super(side)
end
def char
color('雛')
end
end
class Cock < Piece
def initialize(side)
@moves = [ [ 0, -1], [-1, -1], [-1, 0], [ 0, 1], [ 1, 0], [ 1, -1] ]
super(side)
end
def char
color('鶏')
end
end
#---------------------------------------------------------------
#
# 各オブジェクトの準備
#
objs = {
Empt => Empt.new,
Wall => Wall.new,
:A => {
Lion => Lion.new(:A),
Graf => Graf.new(:A),
Elep => Elep.new(:A),
Baby => Baby.new(:A),
Cock => Cock.new(:A),
},
:B => {
Lion => Lion.new(:B),
Graf => Graf.new(:B),
Elep => Elep.new(:B),
Baby => Baby.new(:B),
Cock => Cock.new(:B),
},
}
#---------------------------------------------------------------
#
# メイン
#
think_depth = 4 # 0: 自分の手、1: 自分、相手の手、2: 自分、相手、自分の手…
game = Game.new(objs)
playerA = HumanPlayer.new(objs, :A ); playerA.setup(game)
playerB = ComputerPlayerX.new(objs, :B, think_depth ); playerB.setup(game)
game.show
round = 0; loop {
[playerA, playerB].each {|player|
hand = player.think(game)
puts('%d: %sの手%s' % [round += 1, player.name, hand.view])
game.pick(hand)
game.put(hand) or raise('unexpected error')
game.show
}
}
__END__