【发布时间】:2021-11-19 10:33:47
【问题描述】:
我有两个井字游戏文件。一个是 game.py,另一个是 player.py。
运行我的主文件 game.py 后,我在 shell 中看到了空白。
我添加了 for _ in range(1000):
另外,我添加了极小极大算法。
player.py:
#separate player in two classes, for this is x and y player
import math
import random
class Player:
def __init__(self,letter):
# letter is x or 0
self.letter = letter
# we want player to guess their next move
def get_move(self,game):
pass
# super() function allow access to super class method in child classes
class randomcomputer_player(Player):
def __init__(self,letter):
super().__init__(letter)
def get_move(self,game):
square = random.choice(game.available_moves())
return square
class human_player(Player):
def __init__(self,letter):
super().__init__(letter)
# human_player will guess their next move
def get_move(self,game):
valid_square = False
val = None
while not valid_square:
square = input(self.letter + 'x or o turn. Input move from (0-8)')
try:
val = int(square) #square is a value that user put
if val not in game.available_moves():
raise ValueError
valid_square = True #if this steps are valid
except ValueError: #This excepts value error
print('Invalid square. Try again: ')
#once we got valid square
return val
# define a minimax algorithm to find the minimax steps
class GeniusComputerPlayer(Player):
def __init__(self,letter):
super().__init__(letter)
# computer is going to take moves. so
def get_move(self,game):
if len(game.available_moves()) == 9:
square = random.choice(game.available_moves()) #randomly choose
else:
# get the square box of the minimax algorithm
# Below line shows that only computer wins
square = self.minimax(game,self.letter)['position']
return square
def minimax(self,state,player):
max_player = self.letter # yourself wins
other_player = 'o' if player == 'x' else 'x'
# we want to check if previous move is winner
if state.current_winner == other_player:
return {'position':None,'score':1*(state.num_empty_square()+1) if other_player ==
max_player else -1*(state.num_empty_square()+1)}
elif not state.empty_square(): # No empty square
return {'position':None,'score':0}
# Intialize some dictionaries
if player == max_player: # this max_player is yourself
# I didn't get this line
# you want to maximize every single time step
# comparing every single score to this score, and you're trying to incrementwe #want
to intialize it with lowest possible score i.e. -e
best = {'position':None,'score':-math.inf} # Each score should maximize
else:
#player isn't max player
# value started at infinity because we want to decrement the value to it
best = {'position':None,'score':math.inf}
for possible_moves in state.available_moves():
# step1 : Make a move and try that spots
state.make_move(possible_moves,player)
# step2 : recurse using minimax to simulate a game after making that move
sim_score = self.minimax(state,other_player) # now we alternate players
# That means what happens if we make that move
# step3: Undo the moves, so we can try next one in future iteration
state.board[possible_moves] = ' ' # possible move set to empty square
# set current_winner to None that means nobody has won
state.current_winner = None
sim_score['position'] = possible_moves
# step4 : Update the dictionaries if neccessary
if player == max_player:
if sim_score['score']>best['score']:
best = sim_score # replace best with simulated score, moving to increment
else:
#your player is min_player, that means sim_score has low value
if sim_score['score']<best['score']:
best = sim_score
return best
game.py:
#This file will create a 3x3 board
import time
from player import human_player,randomcomputer_player,GeniusComputerPlayer
class TicTacToe():
def __init__(self):
self.board = self.make_board() #we will use single list for 3 x 3 board
self.current_winner = None #keep track of current winner
@staticmethod
def make_board():
return [' ' for _ in range(9)]
def print_board(self):
#getting each position in row
for row in [self.board[i*3:(i+1)*3] for i in range(3)]:
#-->row --->1 if 0, then self.board[0:3], 0 1 2 when range = 0
#-->row --->2 if 1, then self.board[3:6], 3 4 5 when range = 1
#-->row --->3 if 2, then self.board[6:9], 6 7 8 when range = 2
print('|' +'|'.join(row)+'|')
#static method can't modify, it's independent from other class, not require class method
instatnce
@staticmethod
def print_board_num():
#0|1|2 etc tells us what number correspond to what box
number_board = [[str(i) for i in range(j*3,(j+1)*3)] for j in range(3)]
for row in number_board:
print('|'+'|'.join(row)+'|')
def available_moves(self):
return [i for (i,spot) in enumerate(self.board) if spot == ' ']
#['x','x',o'---> [(0,'x'),(1,'x'),(2,'o')]
#if spot == ' ':
# moves.append(i)
#return moves
def empty_square(self):
return ' ' in self.board
#keep track of empty square
def num_empty_square(self):
return self.board.count(' ')
def make_move(self,square,letter):
#square the place if valid also, the valid letter
if self.board[square] == ' ':
self.board[square] = letter
if self.winner(square, letter):
self.current_winner = letter # current_winner depends on letter
return True
return False
# Create a function for check the winner
def winner(self,square,letter):
# winner if 3 rows anywhere
# The 3 letters can be row, column and diagoniall
# first check for row letters
row_ind = square//3 # square starts with 0
row = self.board[row_ind:(row_ind+1)*3]
# print('row',row)
if all([spot == letter for spot in row]):
return True # if all spots filled with letter
# if all spots are not filled then
# filled the column, we need column value
col_ind = square % 3 #add column index with
col = [self.board[col_ind+i*3] for i in range(3)]
# print('col : ',col)
if all([spot == letter for spot in col]):
return True
# if patterns doesn't come row or column then use diagonally
if square%2 == 0:
diagonal1 = [self.board[i] for i in [0,4,8]] #for left to right diagonal
if all([spot == letter for spot in diagonal1]):
return True
diagonal2 = [self.board[i] for i in [2,4,6]] #for right to left diagonal
if all([spot == letter for spot in diagonal2]):
return True
#if all of the checks fail, so no winner
return False
def play(game,x_player,o_player,print_game= True):
# return a winner if one or None for tie
if print_game:
game.print_board_num()
letter = 'x' #starting letter
# while game has empty squares
while game.empty_square():
# get the move from approiate player
if letter == 'o':
square = o_player.get_move(game)
else:
square = x_player.get_move(game)
#let's define a function to make a move
if game.make_move(square,letter):
if print_game:
print(letter+f" makes a move to square {square}")
game.print_board() #new representation of spot claimed by user
print(' ') # printing the empty line
if game.current_winner:
if print_game:
print(letter+"win")
return letter
# after we made our move, we need to alternate our letter
letter = "o" if letter == "x" else "x"
#we've to check who wins, so. we'll win after a move
#if no next steps and nobody wins then tie
# give tiny break
if print_game:
time.sleep(0.8)
if print_game:
print("It's a tie!")
# This module is running as main file.
if __name__ == '__main__':
x_wins = 0
o_wins = 0
ties = 0
for _ in range(1000):
# imported the player
x_player = randomcomputer_player('x')
o_player = GeniusComputerPlayer('o')
# Create a instance
t = TicTacToe()
# call a play function to execute the game
result = play(t,x_player,o_player,print_game=False)
if result == "x":
x_wins+=1
elif result == "o":
o_wins+=1
else:
ties+=1
print(f'After 1000 iterations we see {x_wins} x_wins, {o_wins} o wins, and {ties} ties')
运行我的主文件 game.py 后,我看到空白输出,为什么?
【问题讨论】:
-
这是一段很长的代码,但也不包括
game.py。阅读、理解和调试它需要花费很多时间。请尽量减少显示错误的最短代码量,然后编辑您的问题。 -
欢迎来到Stack Overflow。请花点时间重新访问How to Ask 和minimal reproducible example,以及相关的帮助页面。将 288 行格式错误的代码作为人们转储,让志愿者很难为您提供帮助。您可以edit您的问题帮助我们帮助您。
-
我尝试运行您的代码,但重新缩进您的代码并查看发生了什么很麻烦。我运行您的代码,它有一些输出(并接收输入),但我不知道这是否正确。请在您的问题中添加更多详细信息,并包含两个格式正确的文件。
标签: python python-3.x tic-tac-toe