Skip to content

Instantly share code, notes, and snippets.

@umaz
Created February 9, 2017 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save umaz/8d85336c45c0b1cf546797560cb2047a to your computer and use it in GitHub Desktop.
Save umaz/8d85336c45c0b1cf546797560cb2047a to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
require "date"
require "fileutils"
#定数の定義
BOARD_SIZE = 8 #盤のサイズ(8*8)
EMPTY = 0 #空きマス
BLACK = 1 #黒石のマス
WHITE = -1 #白石のマス
WALL = 2 #番兵(ひっくり返すときに使う)
ROW_NUM = {"a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 5, "f" => 6, "g" => 7, "h" => 8} #列番号
COL_NUM = {"1" => 1, "2" => 2, "3" => 3, "4" => 4, "5" => 5, "6" => 6, "7" => 7, "8" => 8} #行番号
COLOR = {BLACK => "黒", WHITE => "白"}
#ひっくり返せる方向
NONE = 0
UPPER_LEFT = 1
UPPER = 2
UPPER_RIGHT = 4
RIGHT = 8
LOWER_RIGHT = 16
LOWER = 32
LOWER_LEFT = 64
LEFT = 128
#モード番号
COM = 1
HUMAN = 2
WATCH = 3
RECORD = 4
#新しい盤
def new_board
#盤面を表す二重配列の作成
@board = Array.new(BOARD_SIZE+2){Array.new(BOARD_SIZE+2,EMPTY)}
#壁の配置
@board[0].fill(WALL)
@board[9].fill(WALL)
@board.each do |col|
col[0] = WALL
col[9] = WALL
end
#石の初期配置
@board[4][4] = WHITE
@board[5][5] = WHITE
@board[5][4] = BLACK
@board[4][5] = BLACK
end
#現在の盤の状態を表示
def show_board
print("\n\n #{ROW_NUM.keys.join(" ")}\n") #列
@board.slice(1...-1).each_with_index do |col, i| #番兵を除く
print(COL_NUM[(i+1).to_s])
col.each do |row|
case row
when EMPTY
print "\e[32m"
print(" □")
print "\e[0m"
when BLACK
print(" ○")
when WHITE
print(" ●")
end
end
print("\n")
end
print("\n")
stone_count = count
print("\n 黒:#{count[0]}, 白:#{count[1]}\n\n")
end
#ゲームの開始
def start_game
new_board
show_board
@record = [] #棋譜を保存する配列
@turn = 0
@pass_count = 0
@stone_color = BLACK #黒石からスタート
phase
end
#ゲームの終了
def end_game
judge
if @mode != RECORD
save_record
end
end
#ひっくり返せる方向の取得
def turnable_direction (col, row)
direction = NONE
#左上
if @board[col-1][row-1] == -@stone_color #相手の色がある場合
i = 2
while @board[col-i][row-i] == -@stone_color #相手の色が続くまで
i += 1
end
if @board[col-i][row-i] == @stone_color #相手の色に続くのが自分の色の場合
direction |= UPPER_LEFT
end
end
if @board[col-1][row] == -@stone_color #上
i = 2
while @board[col-i][row] == -@stone_color
i += 1
end
if @board[col-i][row] == @stone_color
direction |= UPPER
end
end
if @board[col-1][row+1] == -@stone_color #右上
i = 2
while @board[col-i][row+i] == -@stone_color
i += 1
end
if @board[col-i][row+i] == @stone_color
direction |= UPPER_RIGHT
end
end
if @board[col][row+1] == -@stone_color #右
i = 2
while @board[col][row+i] == -@stone_color
i += 1
end
if @board[col][row+i] == @stone_color
direction |= RIGHT
end
end
if @board[col+1][row+1] == -@stone_color #右下
i = 2
while @board[col+i][row+i] == -@stone_color
i += 1
end
if @board[col+i][row+i] == @stone_color
direction |= LOWER_RIGHT
end
end
if @board[col+1][row] == -@stone_color #下
i = 2
while @board[col+i][row] == -@stone_color
i += 1
end
if @board[col+i][row] == @stone_color
direction |= LOWER
end
end
if @board[col+1][row-1] == -@stone_color #左下
i = 2
while @board[col+i][row-i] == -@stone_color
i += 1
end
if @board[col+i][row-i] == @stone_color
direction |= LOWER_LEFT
end
end
if @board[col][row-1] == -@stone_color #左
i = 2
while @board[col][row-i] == -@stone_color
i += 1
end
if @board[col][row-i] == @stone_color
direction |= LEFT
end
end
return direction
end
#ひっくり返せるマスの一覧を取得
def get_turnable_cells
turnable_cells = []
@board.each_with_index do |col, i|
col.each_with_index do |row, j|
if row == EMPTY #空きマス
turnable_direction = turnable_direction (i,j)
if turnable_direction != NONE #ひっくり返せる方向が存在する=石を置けるマス
turnable_cells.push([i,j]) #座標を格納
end
end
end
end
return turnable_cells
end
#手番の流れ
def phase
turnable_cells = get_turnable_cells
if turnable_cells.size == 0
@stone_color = -@stone_color
if get_turnable_cells.size == 0
end_game
else
print("#{@turn+1}手目\n")
print("#{COLOR[-@stone_color]}の手番です\n")
print("パスしました\n")
show_board
phase
end
else
print("#{@turn+1}手目\n")
print("#{COLOR[@stone_color]}の手番です\n")
print("undo(y/n):")
back = gets.chomp
if back == "y"
undo
else
print("#{@turn+1}手目:")
case @mode
when COM #COM戦
if @stone_color == @player_color #プレイヤーのターンの時
human(turnable_cells)
else #COMのターンの時
com(turnable_cells)
end
when HUMAN #対人戦
human(turnable_cells)
when WATCH #観戦
com(turnable_cells)
when RECORD #棋譜再生
read_record(@read_record[@turn])
end
end
show_board
phase
end
end
#プレイヤーの着手
def human(turnable_cells)
cell_list = "" #着手可能場所の一覧
turnable_cells.each do |val|
cell_list += "(" + ROW_NUM.key(val[1]) + COL_NUM.key(val[0]) + ")"
end
move = gets.chomp! #手の取得
if move =~ /[a-h][1-8]/
cell = cordinate_transformation(move) #座標の変換
if turnable_cells.include?(cell)
put_stone(cell, move)
else
print("そのマスには打つことはできません\n")
print("打てるマスは#{cell_list}です\n")
phase
end
else
print("正しいマスを指定してください\n")
phase
end
end
#COMの着手
def com(turnable_cells)
cell = turnable_cells.sample #空きますからランダムに1つ取得
col = COL_NUM.key(cell[0])
row = ROW_NUM.key(cell[1])
move = row + col
print(move)
put_stone(cell, move)
end
#棋譜の着手
def read_record(move)
print(move)
cell = cordinate_transformation(move)
put_stone(cell, move)
end
#座標の変換
def cordinate_transformation(move)
cell = move.split("")
col = COL_NUM[cell[1]]
row = ROW_NUM[cell[0]]
cell = [col, row]
return cell
end
#石を置く
def put_stone(cell, move)
col = cell[0]
row = cell[1]
@record[@turn] = [move, @stone_color]
@board[col][row] = @stone_color
reverse_stone(col, row)
@stone_color = -@stone_color #処理が終わったら色を変える
@turn += 1
@pass_count = 0
end
#待った
def undo
if @turn != 0 #1ターン目でない時
@pass_count = 0
@turn -= 1
cell = cordinate_transformation(@record[@turn][0])
@board[cell[0]][cell[1]] = EMPTY
@stone_color = -@record[@turn][1]
@record[@turn][2].each do |cell|
@board[cell[0]][cell[1]] = @stone_color
end
@stone_color = -@stone_color
end
end
#石をひっくり返す
def reverse_stone(col, row) #石をおいた位置
turn_direction = turnable_direction(col, row) #返せる方向を取得
turned_cells = [] #返す方向と返した枚数
if turn_direction & UPPER_LEFT != 0
i = 1
while @board[col-i][row-i] == -@stone_color #相手の色が続くまで
@board[col-i][row-i] = @stone_color
turned_cells.push([col-i,row-i])
i += 1
end
end
if turn_direction & UPPER != 0
i = 1
while @board[col-i][row] == -@stone_color
@board[col-i][row] = @stone_color
turned_cells.push([col-i,row])
i += 1
end
end
if turn_direction & UPPER_RIGHT != 0
i = 1
while @board[col-i][row+i] == -@stone_color
@board[col-i][row+i] = @stone_color
turned_cells.push([col-i,row+i])
i += 1
end
end
if turn_direction & RIGHT != 0
i = 1
while @board[col][row+i] == -@stone_color
@board[col][row+i] = @stone_color
turned_cells.push([col,row+i])
i += 1
end
end
if turn_direction & LOWER_RIGHT != 0
i = 1
while @board[col+i][row+i] == -@stone_color
@board[col+i][row+i] = @stone_color
turned_cells.push([col+i,row+i])
i += 1
end
end
if turn_direction & LOWER != 0
i = 1
while @board[col+i][row] == -@stone_color
@board[col+i][row] = @stone_color
turned_cells.push([col+i,row])
i += 1
end
end
if turn_direction & LOWER_LEFT != 0
i = 1
while @board[col+i][row-i] == -@stone_color
@board[col+i][row-i] = @stone_color
turned_cells.push([col+i,row-i])
i += 1
end
end
if turn_direction & LEFT != 0
i = 1
while @board[col][row-i] == -@stone_color
@board[col][row-i] = @stone_color
turned_cells.push([col,row-i])
i += 1
end
end
@record[@turn].push(turned_cells)
end
#石の数のカウント
def count
black = 0
white = 0
@board.each do |col|
col.each do |row|
case row
when BLACK
black += 1
when WHITE
white += 1
end
end
end
count = [black, white]
return count
end
#勝敗の判定
def judge
stone_count = count
black = count[0]
white = count[1]
if black > white
print("\n黒:#{black} 対 白:#{white} で黒の勝ち\n\n")
elsif white > black
print("\n黒:#{black} 対 白:#{white} で白の勝ち\n\n")
else
print("\n黒:#{black} 対 白:#{white} で引き分け\n\n")
end
end
#棋譜の保存
def save_record
print("棋譜を保存しますか?(y/n)\n")
ans = gets.chomp!
if ans =~ /(y|n)/
if ans == "y"
#recordディレクトリがない場合作成する
FileUtils.mkdir_p("record") unless FileTest.exist?("record")
#現在時刻の取得
time = DateTime.now.strftime('%Y%m%d%H%M')
File.open("record/#{time}.record", "w") do |f|
@record.each do |rec|
f.puts(rec[0])
end
end
print("#{time}.record で保存しました\n\n")
end
else
print("yかnを入力してください\n")
save_record
end
end
#メインメニュー
def menu
while true
print("COMと対戦: 1\n")
print("二人で対戦: 2\n")
print("観戦: 3\n")
print("棋譜読み込み: 4\n")
print("終了: 5\n\n")
mode = gets.chomp!
if mode.to_i == 5
break
end
if mode =~ /[1-4]/
@mode = mode.to_i
case @mode
when COM
print("手番を選択してください\n")
print("1: 先手(黒), 2: 後手(白)")
player = gets.chomp!.to_i
case player
when 1
print("あなたの先手で始めます\n")
@player_color = BLACK
when 2
print("comの先手で始めます\n")
@player_color = WHITE
end
when RECORD
dir = Dir.glob("record/*.record") #棋譜の一覧の取得
if dir.size == 0
print("棋譜が存在しません\n\n")
menu
else
print("棋譜一覧\n")
dir.sort!
dir.each_with_index do |name, i|
print("#{i+1}: #{name}\n")
end
print("棋譜ファイル番号を入力してください:")
num = gets.chomp!.to_i - 1
file = dir[num]
@read_record = []
File.open(file) do |f|
f.each_line do |line|
@read_record.push(line)
end
end
end
end
start_game
else
print("1~4で選択してください\n\n")
menu
end
end
end
menu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment