Created
February 9, 2017 13:46
-
-
Save umaz/8d85336c45c0b1cf546797560cb2047a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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