# algorithm steps # # prerequisites # 01 clear the screen # 02 allow a user to determine the size of the playfield # 03 allow a user to enter names of two players # # 1 clear the screen # 2 print the current state of the game # 3 allow for one player or the other to insert coords # 4 place an 'o' or an 'x' to the coresponding coords # 5 check if the game should end (if someone won) # 5.1 if yes -> end the game # 5.2 if no -> jump to step 1 import os # these global variables are flags end = 0 turn = 0 error = 0 # error codes # # 1 - invalid value # 2 - invalid index/position # 3 - index/position occupied def init(): global end, turn, pf # prerequisite 01 -> clear the screen clearScreen() # prerequisite 02 -> allow a user to determine the size of the playfield size = None F_printOneMoreTime = 0 # variables starting with 'F_' are flags while size == None: try: size = int(input("Size of the playfield (n*n): ")) except ValueError: clearScreen() print("Enter a number") F_printOneMoreTime = 1 continue if F_printOneMoreTime == 1: clearScreen() print("Size of the playfield (n*n):", size) F_printOneMoreTime = 0 if size <= 2: clearScreen() print("Size of the playfield (n*n):", size, "(changed to 3*3)") size = 3 # prerequisite 03 -> allow a user to enter names of two players name1 = input("Name of the first player: ") name2 = input("Name of the second player: ") pf = [] # pf is shor for PlayField temp = [] for i in range(size): for j in range(size): temp.append(' ') pf.append(temp) temp = [] while end == 0: gameRound(pf, name1, name2) def clearScreen(): if os.name == "posix": os.system("clear") if os.name == "nt": os.system("cls") def inBound(a, b, c, d): global pf if len(pf) <= a >= 0 or len(pf) <= b >= 0 and len(pf) <= c >= 0 or len(pf) <= d >= 0: return 1 else: return 0 def gameState(pf, name1, name2): global error if error == 1: print("Invalid value") error = 0 if error == 2: print("Invalid position") error = 0 if error == 3: print("Position occupied") error = 0 print(name1, "(o) vs", name2, "(x)") for i in range(len(pf)): for j in range(len(pf)): print(f"[{pf[i][j]}]", end=" ") print(" ") def check(pf): # horizontal checking # 0 is for when 'o's win and 1 is for when 'x's win o = x = 0 for i in range(len(pf)): for j in range(len(pf)): if pf[i][j] == 'o': o += 1 if pf[i][j] == 'x': x += 1 if o == 3: return 0 elif x == 3: return 1 if o < 3 or x < 3: o = x = 0 # vertical checking o = x = 0 for i in range(len(pf)): for j in range(len(pf)): if pf[j][i] == 'o': o += 1 if pf[j][i] == 'x': x += 1 if o == 3: return 0 elif x == 3: return 1 if o < 3 or x < 3: o = x = 0 # diagonal checking for i in range(len(pf)): for j in range(len(pf)): if pf[i][j] == 'o': # only 6 possibilities, so the program will try all of them try: if pf[i-1][j-1] == 'o' and pf[i-2][j-2] == 'o' and inBound(i-1, j-1, i-2, j-2) == 1: return 0 except IndexError: continue try: if pf[i-1][j+1] == 'o' and pf[i-2][j+2] == 'o' and inBound(i-1, j+1, i-2, j+2) == 1: return 0 except IndexError: continue try: if pf[i+1][j-1] == 'o' and pf[i+2][j-2] == 'o' and inBound(i+1, j-1, i+2, j-2) == 1: return 0 except IndexError: continue try: if pf[i+1][j+1] == 'o' and pf[i+2][j+2] == 'o' and inBound(i+1, j+1, i+2, j+2) == 1: return 0 except IndexError: continue try: if pf[i-1][j-1] == 'o' and pf[i+1][j+1] == 'o' and inBound(i-1, j-1, i+1, j+1) == 1: return 0 except IndexError: continue try: if pf[i-1][j+1] == 'o' and pf[i+1][j-1] == 'o' and inBound(i-1, j+1, i+1, j-1) == 1: return 0 except IndexError: continue for i in range(len(pf)): for j in range(len(pf)): if pf[i][j] == 'x': # only 6 possibilities, so the program will try all of them try: if pf[i-1][j-1] == 'x' and pf[i-2][j-2] == 'x' and inBound(i-1, j-1, i-2, j-2) == 1: return 1 except IndexError: continue try: if pf[i-1][j+1] == 'x' and pf[i-2][j+2] == 'x' and inBound(i-1, j+1, i-2, j+2) == 1: return 1 except IndexError: continue try: if pf[i+1][j-1] == 'x' and pf[i+2][j-2] == 'x' and inBound(i+1, j-1, i+2, j-2) == 1: return 1 except IndexError: continue try: if pf[i+1][j+1] == 'x' and pf[i+2][j+2] == 'x' and inBound(i+1, j+1, i+2, j+2) == 1: return 1 except IndexError: continue try: if pf[i-1][j-1] == 'x' and pf[i+1][j+1] == 'x' and inBound(i-1, j-1, i+1, j+1) == 1: return 1 except IndexError: continue try: if pf[i-1][j+1] == 'x' and pf[i+1][j-1] == 'x' and inBound(i-1, j+1, i+1, j-1) == 1: return 1 except IndexError: continue # draw checking # 2 is for when a draw occurs count = 0 for i in range(len(pf)): for j in range(len(pf)): if pf[i][j] == 'o' or pf[i][j] == 'x': count += 1 if count == len(pf)*len(pf): return 2 def gameRound(pf, name1, name2): global end, turn, error # step 1 -> clear the screen # # cross-platform (Windows, Unix-like OSs) clearScreen() # step 2 -> print the current state of the game gameState(pf, name1, name2) # step 3 -> allow for one player or the other to insert coords row = column = None while row == column == None: try: row, column = map(int, input().split()) except ValueError: clearScreen() error = 1 gameState(pf, name1, name2) continue # step 4 -> place an 'o' or an 'x' to the coresponding coords # # only if there isn't another symbol present and the coords are valid # the 'o' or 'x' is determined by the turn variable # - if it is 0, then an 'o' is placed, if it is 1, an 'x' is placed instead # the rows and columns are marked 1, 2 and 3, not 0, 1 and 2 as the indexes # for better user experience if row < 1 or column < 1: error = 2 try: if pf[row-1][column-1] != ' ': error = 3 elif 1 <= row <= len(pf) and 1 <= column <= len(pf) and error == 0: if turn == 0: pf[row-1][column-1] = 'o' turn = 1 elif turn == 1: pf[row-1][column-1] = 'x' turn = 0 except IndexError: error = 2 # step 5 -> check if the game should end (if someone won) won = check(pf) if won == 0: # step 5.1 -> if yes -> end the game clearScreen() print("o won!") gameState(pf, name1, name2) end = 1 # step 5.2 -> if no -> jump to step 1 if won == 1: clearScreen() print("x won!") gameState(pf, name1, name2) end = 1 if won == 2: clearScreen() print("Draw!") gameState(pf, name1, name2) end = 1 if __name__ == "__main__": init()