```python #Next Steps: # Build & export move log for games # Build a board timeline variable/class - Export this? # Build an analysys board class for bots to use thinking through the next commands. # Look into usin scikit-learn to create a decistion tree model, then have a bot level that loads and uses the model. - See if you could have it programmed itself playing against the other bot levels. Probably need an X model & O model. # Probably need to translate some of the variables as classes -- THIS WILL BE GOOD FOR EDUCATION -- I NEED TO PRACTICE OBJECT-ORIENTED PROGRAMMING AT LEAST ONCE YOU'D THINK. # Probably should export the bot functionality to a separate module import random def prt_brd(brd): print(f""" 3 {brd[0][2]}|{brd[1][2]}|{brd[2][2]} 2 {brd[0][1]}|{brd[1][1]}|{brd[2][1]} 1 {brd[0][0]}|{brd[1][0]}|{brd[2][0]} a b c """) def rnd(i = 1): return random.randint(0,i) def bot_cmd(lvl, trn, brd): if lvl >= 1: #check for potential victory #check files and ranks for r in range(0,3): if brd[r].count(trn) == 2 and brd[r].count(' ') == 1: return file_name[r]+rank_name[brd[r].index(' ')] if (brd[0][r]+brd[1][r]+brd[2][r]).count(trn) == 2 and (brd[0][r]+brd[1][r]+brd[2][r]).count(' ') == 1: return file_name[(brd[0][r]+brd[1][r]+brd[2][r]).index(' ')]+rank_name[r] #check diagonals if (brd[0][0]+brd[1][1]+brd[2][2]).count(trn) == 2 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 1: return file_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')]+rank_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')] if (brd[0][2]+brd[1][1]+brd[2][0]).count(trn) == 2 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 1: return file_name[(brd[0][2]+brd[1][1]+brd[2][0]).index(' ')]+rank_name[(brd[2][0]+brd[1][1]+brd[0][2]).index(' ')] if lvl >= 2: alt_trn = plr_trn[trn == 'X'] #check for potential next-turn loss #check files and ranks for r in range(0,3): if brd[r].count(alt_trn) == 2 and brd[r].count(' ') == 1: return file_name[r]+rank_name[brd[r].index(' ')] if (brd[0][r]+brd[1][r]+brd[2][r]).count(alt_trn) == 2 and (brd[0][r]+brd[1][r]+brd[2][r]).count(' ') == 1: return file_name[(brd[0][r]+brd[1][r]+brd[2][r]).index(' ')]+rank_name[r] #check diagonals if (brd[0][0]+brd[1][1]+brd[2][2]).count(alt_trn) == 2 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 1: return file_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')]+rank_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')] if (brd[0][2]+brd[1][1]+brd[2][0]).count(alt_trn) == 2 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 1: return file_name[(brd[0][2]+brd[1][1]+brd[2][0]).index(' ')]+rank_name[(brd[2][0]+brd[1][1]+brd[0][2]).index(' ')] if lvl >= 3: random.shuffle(vic_rng) rng_ind = [0, 1, 2] #build on existing rows for rng in vic_rng: for d in range(0,3): if rng == file_name[d] and brd[d].count(trn) == 1 and brd[d].count(' ') == 2: rng_ind.remove(brd[d].index(trn)) return file_name[d]+rank_name[rng_ind[rnd()]] elif rng == rank_name[d] and (brd[0][d]+brd[1][d]+brd[2][d]).count(trn) == 1 and (brd[0][d]+brd[1][d]+brd[2][d]).count(' ') == 2: rng_ind.remove((brd[0][d]+brd[1][d]+brd[2][d]).index(trn)) return file_name[rng_ind[rnd()]]+rank_name[d] if rng == 'd1' and (brd[0][0]+brd[1][1]+brd[2][2]).count(trn) == 1 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 2: rng_ind.remove((brd[0][0]+brd[1][1]+brd[2][2]).index(trn)) f = rng_ind[rnd()] return file_name[f]+rank_name[f] elif rng == 'd2' and (brd[0][2]+brd[1][1]+brd[2][0]).count(trn) == 1 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 2: rng_ind.remove((brd[0][2]+brd[1][1]+brd[2][0]).index(trn)) f = rng_ind[rnd()] return file_name[f]+rank_name[2 - f] while True: f = rnd(2) r = rnd(2) if board[f][r] == ' ': return file_name[f]+rank_name[r] rank = [' ', ' ', ' '] file = [' ', ' ', ' '] file_name = ['a', 'b', 'c'] rank_name = ['1', '2', '3'] f = 0 r = 0 d = 0 turn = 'X' vic_chk = False valid_move = False board = [file[:], file[:], file[:]] plrs = -1 plrs_str = '0' plr = [False, False] plr_trn = ('X', 'O') one_plr = 'X' bot_lvl = [-1, -1] lvl_str = '' bot_lvl_name = ['Random', 'Easy', 'Medium', 'Medium_2'] vic_rng = file_name + rank_name + ['d1', 'd2'] rng = '' rng_ind = [0, 1, 2] input("""----- TIC TAC TOE ----- Press Enter to play! """) while plrs > 2 or plrs < 0: plrs_str = input("Enter the number of players: ") if len(plrs_str) > 0: if plrs_str[0].isnumeric(): plrs = int(plrs_str[0]) print() for r in range(0, plrs): plr[r] = True if plrs == 1: while True: one_plr = input("Do you want play as the X's or as the O's? ").upper() if len(one_plr) > 0: if one_plr[0] == 'X' or one_plr[0] == 'O': plr = [one_plr[0] == 'X', one_plr[0] == 'O'] print() break if False in plr: for r in range(0, len(bot_lvl_name)): print(f"Level {r} - {bot_lvl_name[r]}") print() for r in range(0,2): while not plr[r] and bot_lvl[r] == -1: lvl_str = input(f"Please select {plr_trn[r]} bot level number: ") if len(lvl_str) > 0: if lvl_str[0].isnumeric(): bot_lvl[r] = int(lvl_str[0]) prt_brd(board) while True: valid_move = False while not valid_move: #player uses input() #computer uses bot_cmd() if plr[turn == 'O']: cmd = input(f"{turn} to Move: ") else: cmd = bot_cmd(bot_lvl[turn == 'O'], turn, board) print(f"{turn} to Move: {cmd}") if len(cmd) == 2: if file_name.count(cmd[0]) == 1 and rank_name.count(cmd[1]) == 1: f = file_name.index(cmd[0]) r = rank_name.index(cmd[1]) if board[f][r] == ' ': board[f][r] = turn valid_move = True else: print("Illegal move") else: print("Invalid move") else: print("Invalid move") prt_brd(board) #check for victory #check files and ranks for r in range(0,3): if board[r].count(turn) == 3: vic_chk = True if (board[0][r]+board[1][r]+board[2][r]).count(turn) == 3: vic_chk = True #check diagonals if (board[0][0]+board[1][1]+board[2][2]).count(turn) == 3: vic_chk = True if (board[0][2]+board[1][1]+board[2][0]).count(turn) == 3: vic_chk = True if vic_chk: break if board[0].count(' ') + board[1].count(' ') + board[2].count(' ') == 0: break turn = plr_trn[turn == 'X'] if vic_chk: print(f"{turn} Wins!") else: print("Draw") input() input("""----- Thank you for playing! ----- Press Enter to exit. """)