Skip to content

Instantly share code, notes, and snippets.

@spreered
Created September 18, 2017 04:07
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 spreered/2ca11608e2ccd139eea2db545d01a303 to your computer and use it in GitHub Desktop.
Save spreered/2ca11608e2ccd139eea2db545d01a303 to your computer and use it in GitHub Desktop.
Tic Tac Toe created by FredHung - https://repl.it/LNmu/0
class Game
attr_accessor :state ,:player
# attr_accessor 會自動設定getter和setter
def initialize(k=[' ']*9 ,p='X')
@state = k
@player = p
end
def opponent
if @player == 'X'
return 'O'
else
return 'X'
end
end
def switchturn
if(@player == 'X')
@player ='O'
else
@player = 'X'
end
end
def setMove(move)
@state[move] = @player
# puts "::#{self} : setMove , state object_id is : #{@state.object_id}"
end
# print the state of game
def print_game
if is_new_game?
print(" \n")
puts(" 0 | 1 | 2 ")
puts("-----------")
puts(" 3 | 4 | 5 ")
puts("-----------")
puts(" 6 | 7 | 8 ")
print(" \n")
else
# print "\n"
# puts(" #{@state[0]} | #{@state[1]} | #{@state[2]} ")
# puts("-----------")
# puts(" #{@state[3]} | #{@state[4]} | #{@state[5]} ")
# puts("-----------")
# puts(" #{@state[6]} | #{@state[7]} | #{@state[8]} ")
# print "\n"
# print("\n")
@state.each_with_index do |value,index|
if value == ' '
print " #{index} "
else
print " #{value} "
end
case index
when 2,5
print("\n-----------\n")
when 8
print("\n\n")
else
print("|")
end
end
end
end
#==game win?
def win?(player)
#player is X or O
if @state[0]==player
return true if (@state[3]==player && @state[6]==player ) || (@state[1]==player && @state[2]==player )
end
if @state[4]==player
return true if (@state[0]==player && @state[8]==player ) || (@state[2]==player && @state[6]==player ) || (@state[1]==player && @state[7]==player ) || (@state[3]==player && @state[5]==player )
end
if @state[8]==player
return true if (@state[2]==player && @state[5]==player ) || (@state[6]==player && @state[7]==player )
end
return false
end
#==game over?
def over?
return true if(win?('X')||win?('O')||!@state.include?(' '))
end
#== get_new_state :return new state
def clone_new_state(move)
new_game = self.clone
new_game.state= Array.new
@state.each do|i|
new_game.state<<i
end
new_game.setMove(move)
new_game.player = @player
new_game.switchturn
return new_game
end
#== get_available_moves :retrun available move []
def get_available_moves
arr = Array.new(0)
(0...9).each do|i|
if @state[i] == ' '
arr<<i
end
end
arr
end
#== is new game? ======
def is_new_game?
@state.each do|i|
if i != ' '
return false
end
end
return true
end
end
#=====class Game end====
#===::getMove : get move form user===
def getMove(game)
move = -1
while move<0 || move > 8
puts "Player #{game.player} : please enter your move between 0 to 8"
move = gets.chomp.to_i
if game.state[move] != ' '
puts "this move is unavailable"
move = -1
end
end
move
end
#====::getMove end=========
#===::score retrun the score in minimax====
def score(game,depth,active_player)
#if game win? return 10-depth
#else if game lose return -10+depth
#else return 0
# puts("::score : active_player:#{active_player}")
if game.win?(active_player)
return 10 - depth
elsif game.win?(game.opponent)
return depth -10
else
return 0
end
end
#====::score end=========
#====::minimax: return the minimax score====
def minimax(game, depth,active_player)
choice = {}
# return hash choice={:move => best_move_value , :score => best_score }
scores = []
#scores list of available moves
moves = []
#available moves list
if game.over?
choice[:score]= score(game,depth,active_player)
# puts("retrun score")
return choice
end
depth = depth + 1
# puts("::minimax: depth #{depth}, game.plyer #{game.player}, active_playe #{active_player}")
## collecttion the available moves
# puts("minimax: depth : #{depth} , get_available_moves : #{game.get_available_moves} ")
game.get_available_moves.each do|move|
try_game= game.clone_new_state(move)
# puts("::minimax : try game :depth : #{depth} ,game.plyer #{game.player}, try_game.player:#{try_game.player}try move : #{move} ")
# set move and change to next player
c = minimax(try_game,depth,active_player)
# puts("get score : #{c[:score]}, move: #{move}, try_game.player: #{try_game.player}")
scores<< c[:score]
moves<<move
# puts("::minimax : try game ")
# try_game.print
end
# print("moves : #{moves}, scores : #{scores} \n")
# print("---------end availabe_moves-----------\n")
#minimax calculation
if game.player == active_player
# return max {:move ,:score}
max_score_index = scores.each_with_index.max[1]
choice[:move] = moves[max_score_index]
choice[:score] = scores[max_score_index]
else #the opponent
#return min {:move ,:score}
min_score_index = scores.each_with_index.min[1]
choice[:move] = moves[min_score_index]
choice[:score] = scores[min_score_index]
end
# print("minimax return choice : #{choice}\n")
# game.print
# print("---------minimax-----------------\n")
return choice
end
#====::minimax end====
#====::autoMove====
def autoMove(game)
#ruten the best move by computer
# minimax return an hash[:move=>move, :score=>score]
# puts("::automove start!!!!!")
if game.is_new_game?
return rand(0...8)
end
choice = Hash.new
choice = minimax(game,0,game.player)
# puts("autoMove : #{choice}")
# puts("inside game")
# game.print
return choice[:move]
end
#==autoMove end====
##===game start====
game = Game.new([' ']*9,'X')
move = -1
puts "Let's play a Game !"
userPick=' '
until (userPick == 'X') || (userPick =='O')
puts("Please select the player you whant : X ? O ?")
userPick=gets.chomp
end
game.print_game
while !game.over?
puts("this is #{game.player}'s turn ")
if userPick == 'X'
if game.player == 'X'
move = getMove(game)
else
move = autoMove(game)
end
else
if game.player == 'O'
move = autoMove(game)
else
move = getMove(game)
end
end
game.setMove(move)
game.switchturn
game.print_game
end
puts "player #{game.player} take turn"
if(game.win?(game.player))
puts "Player #{game.player} wins!!"
else
puts "end in a draw!"
end
=begin
建立一個棋局Game (class)
棋局狀態state
現在的玩家 player
method 換player
method 印出棋局
method 輸入棋步
method 判斷是否遊戲結束
如果 win?(X) 或 win?(O) 或 沒格子 則遊戲結束
method win?
如果player 三點連成一條線,則win
end Game
minimax
如果遊戲結束,回傳這格的分數,如果是player(電腦)則+10分 對手-10分 平手0分,
另外深度越深(步數),則得分越低(max= 10- depth mini= -10+depth)
如果還沒結束,尋訪每個可以走的棋步move
使用minimax算出這格的分數
結束本迴圈,所有的棋步move可以算出相對的分數陣列
挑選max分數
如果現在的minimax假設棋局的player是電腦,回傳最高的分數和move
挑選mini分數
如果現在minimax假設棋局的player是對手,回傳最低的分數和move
end minimax
電腦下棋
如果是第一步棋,勝率相當,隨便挑一個
其他的 使用minimax算出最佳棋步
end 電腦下棋
開始遊戲,玩家選擇X 或O ,X先攻
while 遊戲結束(全部下完或者是有任一方贏)
X: 如果是使用者,請使用者輸入
如果是電腦 請電腦下棋
O: 如果是使用者,請使用者輸入
如果是電腦 請電腦下棋
印出現在的棋局
end while
結束遊戲 輸出結果
=end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment