Home > Mobile >  python: Is there better way to implement this?
python: Is there better way to implement this?

Time:10-13

I'm coding simple terminal Tic Tac Toe game in python. I'm having problems with how should I implement the setting and checking for the 9 slots. I now have set functions for all the slots but it just feels stupid doing that is there any better way? I'm also coding the checking system where I would need Switch something even better.

Thank you!

main.py

#!/usr/bin/env python3
#file -- grid.py --
import grid 

def welcome():
    print("Welcome")



def main():
    welcome()
    grid.setgrid()
    print(grid.grid)
    while 1:
        xinput = input("Player X: ")
        if xinput.lower() == "a1":
            grid.seta1("X")
        elif xinput.lower() == "a2":
            grid.seta2("X")
        elif xinput.lower() == "a3":
            grid.seta3("X")
        #and so on

        print(grid.grid)
        oinput = input("Player O: ")




if __name__ == "__main__":
    main()

grid.py

a1,a2,a3,b1,b2,b3,c1,c2,c3 = " "," "," "," "," "," "," "," "," "
grid = f"""
   1   2   3
  ┌───┬───┬───┐\n
a │ {a1} │ {a2} │ {a3} │\n
  ├───┼───┼───┤\n
b │ {b1} │ {b2} │ {b3} │\n
  ├───┼───┼───┤\n
c │ {c1} │ {c2} │ {c3} │\n
  └───┴───┴───┘"""

def setgrid():
   global grid
   grid = f""" ┌───┬───┬───┐\n
 │ {a1} │ {a2} │ {a3} │\n
 ├───┼───┼───┤\n
 │ {b1} │ {b2} │ {b3} │\n
 ├───┼───┼───┤\n
 │ {c1} │ {c2} │ {c3} │\n
 └───┴───┴───┘"""

#set functions 
def seta1(val):
    global a1
    a1=val
    setgrid()

def seta2(val):
    global a2
    a2=val
    setgrid()

def seta3(val):
    global a3
    a3=val
    setgrid()

def setb1(val):
    global b1
    b1=val
    setgrid()

def setb2(val):
    global b2
    b2=val
    setgrid()

def setb3(val):
    global b3
    b3=val
    setgrid()

def setc1(val):
    global c1
    c1=val
    setgrid()


def setc2(val):
    global c2
    c2=val
    setgrid()

def setc3(val):
    global c3
    c3=val
    setgrid()

CodePudding user response:

The #1 thing that will make your life easier is using a single data structure rather than N different variables. I'd suggest getting rid of everything in grid.py and using a simple two-dimensional list, like this:

grid = [[" " for _ in range(3)] for _ in range(3)]

while True:
    for mark in "XO":
        row, col = input(f"Player {mark}: ")
        grid[ord(row) - ord('a')][int(col) - 1] = mark

        print(*('|'.join(row) for row in grid), sep='\n-----\n')

prints:

Player X: a2
 |X|
-----
 | |
-----
 | |
Player O: b3
 |X|
-----
 | |O
-----
 | |
Player X:

Modifying the print statement so that it prints the grid in the exact form you want is left as an exercise to the reader (hint: you probably want to define a function like def print_grid(grid): with a couple of nested for loops), but hopefully seeing that you can handle the input part with one line of code instead of thirty-six lines of code gives you the general idea of how much easier the logic of looking up individual squares in the grid can be if you use a data structure rather than one variable per square.

(Having things in an organized data structure can also make it easier when it's time to implement checking for win conditions -- instead of enumerating every possible winning board configuration by hand, you can iterate over each row, iterate over each column across all rows, etc.)

CodePudding user response:

This isn't a complete solution but it covers the core elements for simplifying the task. The game grid has 9 locations:

1 | 2 | 3
---------
4 | 5 | 6
---------
7 | 8 | 9

It's much simpler to use the numbers 1 to 9 as possible input values.

def initialise_grid():
    return [str(n) for n in range(1, 10)]

grid_state = initialise_grid()
# ['1', '2', '3', '4', '5', '6', '7', '8', '9']

Validating the player input becomes a lot simpler.

player_move = int(input())

if (player_move < 1
or player_move > 9
or grid_state[player_move - 1] != str(player_move)):
    print("Invalid choice!")

Update grid_state to assign the player's token ('X' / 'O') to the chosen grid location.

grid_state[player_move - 1] = player_token

There are 8 possible winning scenarios to check. A win is determined by confirming that the current player's token is present in each of the three locations for one of the listed winning scenarios.

def has_won(player_token, grid_state):
    win_scenarios = [(0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6),
                     (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6)]

    for scenario in win_scenarios:
        if all(player_token in grid_state[position] for position in scenario):
            return True

    return False
  • Related