A little Tic-tac-toe program with the __str__ method, python 3 - python

I have to write a Tic-tac-toe program with python and I use Jupyter Notebook. I want to write a class with the __str__ method. I've first try with a method I've called afficher, in the class Terrain. And it seem to work. But when I try with the __str__ method, it doesn't work.
class Case:
def __init__(self, a = ' '):
self.occupe = a
def jouer1(self):
if self.occupe == ' ':
self.occupe = 'X'
def jouer2(self):
if self.occupe == ' ':
self.occupe = 'O'
*** In need to replace the affiche methode by __str__ methode ***
class Terrain:
def __init__(self):
self.grille = []
for i in range(0, 9):
self.grille.append(Case())
self.tour = 1
def afficher(self):
for i in range(9):
if (i + 1)%3 != 0:
print(self.grille[i].occupe + ' | ', end =" ")
else:
print(self.grille[i].occupe)
def jouer(self, k):
if self.tour == 1:
self.grille[k].jouer1()
self.tour = 2
else:
self.grille[k].jouer2()
self.tour = 1
** this is the output I need, but with the __str__ method in the class Terrain**
terrain = Terrain()
terrain
terrain.jouer(3)
terrain.jouer(2)
terrain.jouer(4)
terrain.jouer(6)
terrain.jouer(5)
terrain.afficher()
*** this is how I replace the afficher method in the Terrain class (It doesn't work ... I don't know why ...) ***
class Case:
def __init__(self, a = ' '):
self.occupe = a
def jouer1(self):
if self.occupe == ' ':
self.occupe = 'X'
def jouer2(self):
if self.occupe == ' ':
self.occupe = 'O'
class Terrain:
def __init__(self):
self.grille = []
for i in range(0, 9):
self.grille.append(Case())
self.tour = 1
def __str__(self):
for i in range(9):
if (i + 1)%3 != 0:
return self.grille[i].occupe + ' | '
else:
return self.grille[i].occupe + ' \ '
def jouer(self, k):
if self.tour == 1:
self.grille[k].jouer1()
self.tour = 2
else:
self.grille[k].jouer2()
self.tour = 1
terrain = Terrain()
terrain
terrain.jouer(3)
terrain.jouer(2)
terrain.jouer(4)
terrain.jouer(6)
terrain.jouer(5)
print(terrain)
Sorry for my english.

Try the following for generating a string for the entire range rather than only one row
def __str__(self):
content = []
for i in range(9):
if (i + 1)%3 != 0:
content.append(self.grille[i].occupe + ' | ')
else:
content.append(self.grille[i].occupe)
return '\n'.join(content)

Thank you so much OneCriketeer.
I try this, and it works !
'
def str(self):
content = []
for i in range(9):
if (i + 1)%3 != 0:
content.append(self.grille[i].occupe + ' | ')
else:
content.append(self.grille[i].occupe + ' \n')
return ''.join(content)
'

Related

Function adds an unwanted line

class board:
def __init__(self, length, height, letter):
self.layout = ((' ' + letter) * length + ' \n') * height
self.length = length
self.height = height
self.objects = {}
def draw(self, length=None, height=None, letter=None, double=False, show=True):
#adds a line every time
if length == None or height == None or letter == None:
print(self.layout)
else:
if letter != '':
letter = letter[0]
layout = self.layout.split('\n')[:-1]
if layout[0] == '':
layout = layout[1:]
old = ''
for num in range(height):
if num != height:
num = num - 1
old = old + layout[num] + '\n'
new = old
num = length * 2
n = 0
old = ''
for item in layout[height]:
n = n + 1
if n == num:
old_block = item
old = old + letter
else:
old = old + item
string = new + old + '\n'
print(len(layout[height-1:len(layout) -1]))
print(len(layout))
string = string + '\n'.join(layout[height-1:len(layout) -1]) + '\n'
self.layout = string
self.objects[letter] = (length, height, old_block)
if show:
if double:
print(string.replace(' ', ' '))
else:
print(string)
I am trying to create a module which a function that draws a board and you can also add an object at a specific space, but sadly my function called draw adds an unwanted line.
I would be very grateful if you could help me!
self.layout = (((' ' + letter) * length + ' \n') * height)[:-2]
also
self.objects[letter] = (length, height, old_block)
string = string[:-2]
if show:

TypeError in tic-tac-toe game in python

I'm trying to make a tic-tac-toe game while trying to learn Python and keep getting TypeError and I have no idea why.
I have already looked at other questions similar to this (none with "NoneType") but I still don't understand where is my problem. I'm following a youtube tutorial and everything seems to check out, so I'm really lost here.
Here's the error:
File "game.py", line 93, in <module>
play(t, x_player, o_player, print_game=True)
File "game.py", line 71, in play
if game.make_move(square, letter):
File "game.py", line 29, in make_move
if self.board[square] == ' ':
TypeError: list indices must be integers or slices, not NoneType
And here is the code:
import time
from player import HumanPlayer, RandomComputerPlayer
class TicTacToe:
def __init__(self):
self.board = [' ' for _ in range(9)]
self.current_winner = None
def print_board(self):
for row in [self.board[i*3:(i+1)*3] for i in range(3)]:
print('| ' + ' | '.join(row) + ' |')
#staticmethod
def print_board_nums():
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 == ' ']
def empty_squares(self):
return ' ' in self.board
def num_empty_squares(self):
return self.board.count(' ')
def make_move(self, square, letter):
if self.board[square] == ' ':
self.board[square] = letter
if self.winner(square, letter):
self.current_winner = letter
return True
return False
def winner(self, square, letter):
row_ind = square // 3
row = self.board[row_ind*3:(row_ind+1)*3]
if all([spot == letter for spot in row]):
return True
col_ind = square % 3
column = self.board[col_ind*3:(col_ind+1)*3]
if all([spot == letter for spot in column]):
return True
if square % 2 == 0:
diag1 = [self.board[i] for i in [0, 4, 8]]
if all([spot == letter for spot in diag1]):
return True
diag2 = [self.board[i] for i in [2, 4, 6]]
if all([spot == letter for spot in diag2]):
return True
return False
def play(game, x_player, o_player, print_game=True):
if print_game:
game.print_board_nums()
letter = 'X'
while game.empty_squares():
if letter == 'O':
square = o_player.get_move(game)
else:
square = x_player.get_move(game)
if game.make_move(square, letter):
if print_game:
print(letter + f' makes a move to a square {square}')
game.print_board()
print('')
if game.current_winner:
if print_game:
print(letter + ' wins!')
return letter
letter = 'O' if letter == 'X' else 'X'
time.sleep(0.8)
if print_game:
print('It\'s a tie')
if __name__ == '__main__':
x_player = HumanPlayer('X')
o_player = RandomComputerPlayer('O')
t = TicTacToe()
play(t, x_player, o_player, print_game=True)
Edit: Here is the code from the player module:
import math
import random
class Player:
def __init__(self, letter):
self.letter = letter
def get_move(self, game):
pass
class RandomComputerPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self, game):
square = random.choice(game.available_moves())
return square
class HumanPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self, game):
valid_square = False
val = None
while not valid_square:
square = input(self.letter + '\'s turn. Input move (0-8):')
try:
val = int(square)
if val not in game.available_moves():
raise ValueError
valid_square = True
except ValueError:
print('Invalid square. Try again')

Redundant Elements Appear in Result when Executing Nested For-loop in Python

I'm writing a program in Python that fetches all possible first moves for X and O. In this program, X goes first and O goes second. Once X and O finish their moves, I want to print all possible states that the game board can be in.
Initially, X can make nine moves since there are nine empty positions on the board; then, O can make eight moves since there are eight empty positions left.
So, when I print the results, I should get 72 results. Instead, I am getting 108 results.
This is because after getting the first move for X, for some reason that I can't figure out, the previous moves for X gets added to the nextStates.nextStates.
Thus, instead of getting 9*8 results, I get (0 + 8) + (1 + 8) + ... + (8 + 8) = 108 results.
I don't know why this is the case since as far as I'm concerned, I'm just using an equivalent of a double for-loop.
import copy
class GameBoard:
def __init__ (self):
self.SIZE = 3
self.currentState = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']]
self.nextStates = []
EMPTY = ' '
X = 'X'
O = 'O'
def printBoard(gameBoard):
for row in range(0, gameBoard.SIZE):
for col in range(0, gameBoard.SIZE):
print('[' + gameBoard.currentState[row][col] + ']', end = '')
print()
print()
def getNextStatesO(gameBoard):
for row in range(0, gameBoard.SIZE):
for col in range(0, gameBoard.SIZE):
if(gameBoard.currentState[row][col] == EMPTY):
tempBoard = copy.deepcopy(gameBoard)
tempBoard.currentState[row][col] = O
gameBoard.nextStates.append(tempBoard)
return gameBoard
def getNextStatesX(gameBoard):
for row in range(0, gameBoard.SIZE):
for col in range(0, gameBoard.SIZE):
if(gameBoard.currentState[row][col] == EMPTY):
tempBoard = copy.deepcopy(gameBoard)
tempBoard.currentState[row][col] = X
gameBoard.nextStates.append(tempBoard)
return gameBoard
def getNextStates(gameBoard):
gameBoard = getNextStatesX(gameBoard)
for i in range(0, len(gameBoard.nextStates)):
gameBoard.nextStates[i] = getNextStatesO(gameBoard.nextStates[i])
return gameBoard
def main():
gameBoard = GameBoard()
gameBoard = getNextStates(gameBoard)
counter = 1
for x in range(0, len(gameBoard.nextStates)):
for o in range(0, len(gameBoard.nextStates[x].nextStates)):
print(str(counter) + ' X: ' + str(x) + ' O: ' + str(o))
printBoard(gameBoard.nextStates[x].nextStates[o])
counter += 1
main()
You are not updating the current state. The only thing you are doing is to update the temporary game board, which gets thrown away everytime you finish the execution of getNextStatesX or getNextStatesO. By changing the state in the current board, the following iteration shows the previous marking.
Also, I'm not sure you can preserve the state by referring to GameBoard statically, like you're doing. Always use self to refer to the current instance of a class.
Here is a version that displays the 72 possibilities (notice that some modifications are required to actually reflect the rules of Tic-tac-toe):
import copy
class GameBoard:
def __init__ (self):
self.SIZE = 3
self.currentState = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']]
self.nextStates = []
EMPTY = ' '
X = 'X'
O = 'O'
def printBoard(self):
for row in range(0, self.SIZE):
for col in range(0, self.SIZE):
print('[' + self.currentState[row][col] + ']', end = '')
print()
print()
def getNextStatesO(self):
for row in range(0, self.SIZE):
for col in range(0, self.SIZE):
if(self.currentState[row][col] == EMPTY):
self.currentState[row][col] = O
tempBoard = copy.deepcopy(self)
tempBoard.currentState[row][col] = O
self.nextStates.append(tempBoard)
return self
def getNextStatesX(self):
for row in range(0, self.SIZE):
for col in range(0, self.SIZE):
if(self.currentState[row][col] == EMPTY):
self.currentState[row][col] = X
tempBoard = copy.deepcopy(self)
tempBoard.currentState[row][col] = X
self.nextStates.append(tempBoard)
return self
def getNextStates(self):
gameBoard = getNextStatesX(self)
for i in range(0, len(self.nextStates)):
self.nextStates[i] = getNextStatesO(self.nextStates[i])
return self
def main():
gameBoard = GameBoard()
gameBoard = getNextStates(gameBoard)
counter = 1
for x in range(0, len(gameBoard.nextStates)):
for o in range(0, len(gameBoard.nextStates[x].nextStates)):
print(str(counter) + ' X: ' + str(x) + ' O: ' + str(o))
printBoard(gameBoard.nextStates[x].nextStates[o])
counter += 1
main()

I got stuck on Python error TypeError: unhashable type: 'slice'

from informedSearch import *
from search import *
class EightPuzzleProblem(InformedProblemState):
"""
Inherited from the InformedProblemState class. To solve
the eight puzzle problem.
"""
def __init__(self, myList, list = {}, operator = None):
self.myList = list
self.operator = operator
def __str__(self):
## Method returns a string representation of the state.
result = ""
if self.operator != None:
result += "Operator: " + self.operator + ""
result += " " + ' '.join(self.myList[0:3]) + "\n"
result += " " + ' '.join(self.myList[3:6]) + "\n"
result += " " + ' '.join(self.myList[6:9]) + "\n"
return result
def illegal(self):
## Tests whether the state is illegal.
if self.myList < 0 or self.myList > 9: return 1
return 0
def equals(self, state):
## Method to determine whether the state instance
## and the given state are equal.
return ' '.join(self.myList) == ' '.join(state.myList)
## The five methods below perform the tree traversing
def move(self, value):
nList = self.myList[:] # make copy of the current state
position = nList.index('P') # P acts as the key
val = nList.pop(position + value)
nList.insert(position + value, 'P')
nList.pop(position)
nList.insert(position, val)
return nList
def moveleft(self):
n = self.move(-1)
return EightPuzzleProblem(n, "moveleft")
def moveright(self):
n = self.move(1)
return EightPuzzleProblem(n, "moveright")
def moveup(self):
n = self.move(-3)
return EightPuzzleProblem(n, "moveup")
def movedown(self):
n = self.move(+3)
return EightPuzzleProblem(n, "movedown")
def operatorNames(self):
return ["moveleft", "moveright", "moveup", "movedown"]
def enqueue(self):
q = []
if (self.myList.index('P') != 0) and (self.myList.index('P') != 3) and (self.myList.index('P') != 6):
q.append(self.moveleft())
if (self.myList.index('P') != 2) and (self.myList.index('P') != 5) and (self.myList.index('P') != 8):
q.append(self.moveright())
if self.myList.index('P') >= 3:
q.append(self.moveup())
if self.myList.index('P') >= 5:
q.append(self.movedown())
def applyOperators(self):
return [self.moveleft(), self.moveright(), self.moveup(), self.movedown()]
def heuristic():
counter = 0
for i in range(len(self.myList)):
if ((self.myList[i] != goal.myList[i]) and self.myList[i] != 'P'):
## Position of current:
current = goal.myList.index(self.myList[i])
if current < 3: goalRow = 0
elif current < 6: goalRow = 1
else: goalRow = 2
if i < 3: initRow = 0
elif i < 6: initRow = 1
else: startRow = 2
initColumn = i % 3
goalColumn = current % 3
counter += (abs(goalColumn - initColumn) + abs(goalRow - initRow))
return counter
#Uncomment to test the starting states:
init = ['1','3','P','8','2','4','7','6','5'] #A
#init = ['1','3','4','8','6','2','P','7','5'] #B
#init = ['P','1','3','4','2','5','8','7','6'] #C
#init = ['7','1','2','8','P','3','6','5','4'] #D
#init = ['8','1','2','7','P','4','6','5','3'] #E
#init = ['2','6','3','4','P','5','1','8','7'] #F
#init = ['7','3','4','6','1','5','8','P','2'] #G
#init = ['7','4','5','6','P','3','8','1','2'] #H
goal = ['1','2','3','8','P','4','7','6','5'] #goal state
InformedSearch(EightPuzzleProblem(init), EightPuzzleProblem(goal))
I run it and it shows error
line 34, in __str__ result += " " + ' '.join(self.myList[0:3]) + "\n"
TypeError: unhashable type: 'slice'
Any Ideas?
You're setting the "list" to a dictionary as a default value: list = {} in:
def __init__(self, myList, list = {}, operator = None):
and then assigning it to myList with:
self.myList = list
A dictionary cannot be sliced like a list. So when you try to slice it:
self.myList[0:3]
it fails.

(Python) Why doesn't my method object execute when I call it after my class definition?

When I try to run my program in IDLE (the text editor i'm using at the moment, notepad ++ said indentation error and I don't know why) it only does the code in __init__, which shows it's been created into an object. But the line after that I tried to use the main method and it doesn't do anything. I also changed it to a different method but that didn't work either. Here's my program:
import sys
class Main:
def __init__(self):
WinX = False
WinO = False
Turn = 'X'
LastTurn = 'X'
a, b, c, d, e, f, g, h, i = ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
PosList = []
PosList.append(a)
PosList.append(b)
PosList.append(c)
PosList.append(d)
PosList.append(e)
PosList.append(f)
PosList.append(g)
PosList.append(h)
PosList.append(i)
self.board = '+---+---+---+\n| ' + PosList[0] +' | '+ PosList[1] +' | '+ PosList[2] +' |\n+---+---+---+\n| '+ PosList[3] +' | '+ PosList[4] +' | '+ PosList[5] +' |\n+---+---+---+\n| '+ PosList[6] +' | '+ PosList[7] +' | '+ PosList[8] +' |\n+---+---+---+'
print self.board
def UpdateTurn(self):
if LastTurn == 'X':
Turn == 'O'
elif LastTurn == 'O':
Turn == 'X'
LastTurn = Turn
def WinChecker(self):
if a and b and c == 'X' or a and d and g == 'X' or a and e and i == 'X' or g and e and c == 'X' or g and h and i == 'X' or c and f and i == 'X':
WinX = True
if a and b and c == 'O' or a and d and g == 'O' or a and e and i == 'O' or g and e and c == 'O' or g and h and i == 'O' or c and f and i == 'O':
WinO = True
def UpdateBoard(self):
print self.board
def Starter(self):
while True:
try:
i = int(input(''))
except TypeError:
print 'Not a Number, Try Again.'
continue
i -= 1
PosList[i] = Turn
self.UpdateBoard
self.WinChecker
if Winx == True:
print 'X Wins!'
sys.exit()
elif Wino == True:
print 'O Wins!'
sys.exit()
self.UpdateTurn
s = Main()
s.Starter
I just (4 days) finished python's own tutorial.
call Starter function like
s.Starter()
And also there might be an logical error The while loop below will be always true.
def Starter(self):
while True:
try:
i = int(input(''))
except TypeError:
print 'Not a Number, Try Again.'
continue
You haven't called the method.
s.Starter()
You are not actually calling the Starter method in the last line, just referencing it. Do this instead:
s.Starter()
That calls it.
For interest, here is a rewritten version. I've used some more advanced constructs - #classmethod and #property and 'magic methods' like __str__ and __repr__. Hope you find it useful!
def getInt(prompt='', lo=None, hi=None):
"""
Get integer value from user
If lo is given, value must be >= lo
If hi is given, value must be <= hi
"""
while True:
try:
val = int(raw_input(prompt))
if lo is not None and val < lo:
print("Must be at least {}".format(lo))
elif hi is not None and val > hi:
print("Must be no more than {}".format(hi))
else:
return val
except ValueError:
print("Must be an integer!")
class TicTacToe(object):
players = ('X', 'O') # player characters
blank = ' ' # no-player character
wins = ( # lines that give a win
(0,1,2),
(3,4,5),
(6,7,8),
(0,3,6),
(1,4,7),
(2,5,8),
(0,4,8),
(2,4,6)
)
board_string = '\n'.join([ # format string
"",
"+---+---+---+",
"| {} | {} | {} |",
"+---+---+---+",
"| {} | {} | {} |",
"+---+---+---+",
"| {} | {} | {} |",
"+---+---+---+"
])
#classmethod
def ch(cls, state):
"""
Given the state of a board square (None or turn number)
return the output character (blank or corresponding player char)
"""
if state is None:
return cls.blank
else:
return cls.players[state % len(cls.players)]
def __init__(self, bd=None):
"""
Set up a game of TicTacToe
If board is specified, resume playing (assume board state is valid),
otherwise set up a new game
"""
if bd is None:
# default constructor - new game
self.turn = 0
self.board = [None for i in range(9)]
elif hasattr(bd, "board"): # this is 'duck typing'
# copy constructor
self.turn = sum(1 for sq in bd if sq is not None)
self.board = bd.board[:]
else:
# given board state, resume game
self.turn = sum(1 for sq in bd if sq is not None)
self.board = list(bd)
#property
def board_chars(self):
"""
Return the output characters corresponding to the current board state
"""
getch = type(self).ch
return [getch(sq) for sq in self.board]
#property
def winner(self):
"""
If the game has been won, return winner char, else None
"""
bd = self.board_chars
cls = type(self)
for win in cls.wins:
c0, c1, c2 = (bd[sq] for sq in win)
if c0 != cls.blank and c0 == c1 and c0 == c2:
return c0
return None
def __str__(self):
"""
Return a string representation of the board state
"""
cls = type(self)
return cls.board_string.format(*self.board_chars)
def __repr__(self):
"""
Return a string representation of the object
"""
cls = type(self)
return "{}({})".format(cls.__name__, self.board)
def do_move(self):
"""
Get next player's move
"""
cls = type(self)
next_player = cls.ch(self.turn)
while True:
pos = getInt("Player {} next move? ".format(next_player), 1, 9) - 1
if self.board[pos] is None:
self.board[pos] = self.turn
self.turn += 1
break
else:
print("That square is already taken")
def play(self):
print("Welcome to Tic Tac Toe. Board squares are numbered 1-9 left-to-right, top-to-bottom.")
while True:
print(self) # show the board - calls self.__str__
w = self.winner
if w is None:
self.do_move()
else:
print("{} is the winner!".format(w))
break
def main():
TicTacToe().play()
if __name__=="__main__":
main()

Categories

Resources