Python Forum
Help with tic-tac-toe project
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help with tic-tac-toe project
#1
Hello Ive been teaching myself python for almost a month now and Im trying to implement classes into this project which is something Im new to. Its not finished but Im getting a wrong output when I try to determine if someone won. I sometimes get a random 'You won'(sometimes 2-4 of them) even though there aren't three in a row of the same letter. I feel like I dont understand how classes work anymore.
import random
class Tic:
    board=[[' ',' ',' '],[' ',' ',' '],[' ',' ',' ']]
    placement=[[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2]]
    def __init__(self):
        pass
    def print_board(self):
        print('{}\n{}\n{}'.format(self.board[0],self.board[1],self.board[2]))
    def change_board(self,row,column):
        if player1 is self:
            self.board[row][column]='X'
        if comp is self:
            self.board[row][column]='O'
    def did_someone_win(self,letter):
        if self.board[0][0] and self.board[1][0] and self.board[2][0] == letter:
            print('You won!')
        if self.board[0][1] and self.board[1][1] and self.board[2][1] == letter:
            print('You won!')
        if self.board[0][2] and self.board[1][2] and self.board[2][2] == letter:
            print('You won!')
        if self.board[0][0] and self.board[0][1] and self.board[0][2] == letter:
            print('You won!')
        if self.board[1][0] and self.board[1][1] and self.board[1][2] == letter:
            print('You won!')
        if self.board[2][0] and self.board[2][1] and self.board[2][2] == letter:
            print('You won!')
        if self.board[0][0] and self.board[1][1] and self.board[2][2] == letter:
            print('You won!')
        if self.board[2][0] and self.board[1][1] and self.board[0][2] == letter:
            print('You won!')
        else:
            pass
game=Tic();player1=Tic();comp=Tic()

print('First move will be randomly chosen.  Enter s to start game: ')
starting_key=input('')

if starting_key is 's':
    start_game=True
else:
    start_game=False

player1_move=False;comp_move=False

if random.randint(0, 1) == 1:
    print('Player1 goes first.')
    player1_move = True
else:
    print('Computer goes first.')
    comp_move = True

while start_game:

    while player1_move:
        print('Please enter one of the possible coordinates: ',game.placement) #shows available coordinates
        var1, var2 = input("Enter your coordinates separated by a space here: ").split()#enter coordinates
        var1=int(var1);var2=int(var2)#changes inputs into int's to avoid error
        player1.change_board(var1,var2)#using class method to change board array
        game.print_board()#using method to print the board with new inputs
        game.placement.pop(game.placement.index([var1,var2]))#removes coordinates already used.
        game.did_someone_win('X')#This is what doesnt work as I get 'You won' randomly sometimes.
        comp_move=True
        player1_move=False
    while comp_move:
        print('Computers move.')
        comp_choice = random.choice(game.placement)#randomly chooses computer's choice
        comp.change_board(comp_choice[0],comp_choice[1])#using class method to change board array
        game.placement.pop(game.placement.index([comp_choice[0], comp_choice[1]]))#remove used coordinates
        game.print_board()
        print(game.placement)
        game.did_someone_win('O')#Again doesnt work properly cant figure out why
        player1_move = True
        comp_move=False
/python]
[hr]
[python]
import random
class Tic:
    board=[[' ',' ',' '],[' ',' ',' '],[' ',' ',' ']]
    placement=[[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2]]
    def __init__(self):
        pass
    def print_board(self):
        print('{}\n{}\n{}'.format(self.board[0],self.board[1],self.board[2]))
    def change_board(self,row,column):
        if player1 is self:
            self.board[row][column]='X'
        if comp is self:
            self.board[row][column]='O'
    def did_someone_win(self,letter):
        if self.board[0][0] and self.board[1][0] and self.board[2][0] == letter:
            print('You won!')
        if self.board[0][1] and self.board[1][1] and self.board[2][1] == letter:
            print('You won!')
        if self.board[0][2] and self.board[1][2] and self.board[2][2] == letter:
            print('You won!')
        if self.board[0][0] and self.board[0][1] and self.board[0][2] == letter:
            print('You won!')
        if self.board[1][0] and self.board[1][1] and self.board[1][2] == letter:
            print('You won!')
        if self.board[2][0] and self.board[2][1] and self.board[2][2] == letter:
            print('You won!')
        if self.board[0][0] and self.board[1][1] and self.board[2][2] == letter:
            print('You won!')
        if self.board[2][0] and self.board[1][1] and self.board[0][2] == letter:
            print('You won!')
        else:
            pass
game=Tic();player1=Tic();comp=Tic()

print('First move will be randomly chosen.  Enter s to start game: ')
starting_key=input('')

if starting_key is 's':
    start_game=True
else:
    start_game=False

player1_move=False;comp_move=False

if random.randint(0, 1) == 1:
    print('Player1 goes first.')
    player1_move = True
else:
    print('Computer goes first.')
    comp_move = True

while start_game:

    while player1_move:
        print('Please enter one of the possible coordinates: ',game.placement) #shows available coordinates
        var1, var2 = input("Enter your coordinates separated by a space here: ").split()#enter coordinates
        var1=int(var1);var2=int(var2)#changes inputs into int's to avoid error
        player1.change_board(var1,var2)#using class method to change board array
        game.print_board()#using method to print the board with new inputs
        game.placement.pop(game.placement.index([var1,var2]))#removes coordinates already used.
        game.did_someone_win('X')#This is what doesnt work as I get 'You won' randomly sometimes.
        comp_move=True
        player1_move=False
    while comp_move:
        print('Computers move.')
        comp_choice = random.choice(game.placement)#randomly chooses computer's choice
        comp.change_board(comp_choice[0],comp_choice[1])#using class method to change board array
        game.placement.pop(game.placement.index([comp_choice[0], comp_choice[1]]))#remove used coordinates
        game.print_board()
        print(game.placement)
        game.did_someone_win('O')#Again doesnt work properly cant figure out why
        player1_move = True
        comp_move=False

Just figured out it was the if statements and that the 'ands' didnt pool all of the other coordinates, only the last one. Anyway, any comments or advice to improve my code would be appreciated!- thanks
Reply
#2
if self.board[0][0] will always be True if it contains something. Instead use
if letter == self.board[0][0] == self.board[1][0] == self.board[2][0]:
Reply
#3
Hi,

Here are some ideas you might consider for your program:
>>> board = [['']*3]*3
>>> board
[['', '', ''], ['', '', ''], ['', '', '']]
>>> for row in board: #compare rows
...   all(field == '' for field in row)
... 
True
True
True
>>> transposed_board = list(map(list, zip(*board))) #you may not need the outer list()
>>> transposed_board #for comparing collumns
[['', '', ''], ['', '', ''], ['', '', '']]
>>> all(row[i] == '' for i, row in enumerate(board)) #compare diagonal
True
>>> 
>>> all(row[-i] == '' for i, row in enumerate(board)) #compare the other diagonal
True
Reply
#4
I restructured the code above. As of programming point of view, it is important to define
helper methods, such as make_move, get_row_winner, get_column_winner etc.

import random

class Tic:
    '''Tic-tac-toe simulator
    '''
    
    board = [[None for j in range(3)]] * 3
    markers = ['X', '0']
    
    def make_move(self, i, j, move_type='X'):
        if i not in [0, 1, 2] or j not in [0, 1, 2]:
            print("Illegal indecies: (%s, %s)" % (i, j))
            return False # be silent or print warning message here!
        if self.board[i][j] is not None:
            print("This position is already marked: (%s, %s)"%(i, j))
            return False # be silent or print warning message here!
        self.board[i][j] = move_type
        return True
    
    def _get_diagonal_winner(self):
        if self.board[0][0] == self.board[1][1] == self.board[2][2]:
            return self.board[0][0]
        if self.board[1][1] == self.board[1][1] == self.board[2][0]:
            return self.board[1][1]
        return None
    
    def _get_row_winner(self):
        for j in range(3):
            if self.board[j][0] == self.board[j][1] == self.board[j][2]:
                return self.board[j][0]
        return None
    
    def _get_column_winner(self):
        self.board = self._transpose(self.board)
        result = self._get_row_winner()
        self.board = self._transpose(self.board)
        return result
    
    @property
    def has_empty_cell(self):
        return any([None in row for row in self.board])
   
    
    @staticmethod
    def _transpose(input_board):
        'Returns transponsed (over main diagonal) board'
        return list(map(list, zip(*input_board))) 
   
    def get_winner(self):
        return self._get_row_winner() or self._get_column_winner() or self._get_diagonal_winner()

    
    def run(self, style='random'):
        ind = 0
        while self.get_winner() is None and self.has_empty_cell:
            i = random.randint(0, 2) if style == 'random' else int(input("Player_%s: Enter i-position of your move (%s):" % (ind % 2, self.markers[ind % 2])))
            j = random.randint(0, 2)  if style == 'random' else int(input("Player_%s: Enter j-position of your move (%s):" % (ind % 2, self.markers[ind % 2])))
            if self.make_move(i, j, self.markers[ind % 2]):
                print('The board state: \n{}\n{}\n{}'.format(self.board[0], self.board[1], self.board[2]))
                ind += 1
        if self.get_winner():
            print('Game over! The winner is Player_%s, marker=%s' % ((ind + 1) % 2, self.get_winner()))
        else:
            print('Sorry... no one wins!')
        print('The board state: \n{}\n{}\n{}'.format(self.board[0], self.board[1], self.board[2]))

if __name__ == '__main__':
    game = Tic()
    game.run('random')
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020