Tic tac toe

From Computer Science Wiki
Revision as of 15:43, 21 September 2021 by Mr. MacKenty (talk | contribs) (→‎A possible solution)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
This a problem set for you to work through [1]

This is a problem set. Some of these are easy, others are far more difficult. The purpose of these problems sets are:

  1. to build your skill applying computational thinking to a problem
  2. to assess your knowledge and skills of different programming practices


What is this problem set trying to do[edit]

This problem set is testing your computational thinking, your skill and understanding of lists, and your skill and understanding of loops

The Problem[edit]

Your program must do three things:

  1. it must allow a human to play against a computer a game of tic tac toe
    1. your program must have win and lose conditions
  2. it must draw a tic tac to board, updated with x's and O's as the computer and human play.
  3. It must follow the rules of tic tac toe


Hacker edition[edit]

In the hacker version:

  • Your program should be good at playing tic tac toe

Python Version[edit]

import random

# initialization stuff here: 

board = [1,2,3,4,5,6,7,8,9]
computerSpaces = []
humanSpaces =[1]
game = 0

def drawPieces(position):
    if position in humanSpaces:
        return "X"
    elif position in computerSpaces:
        return "O"
    else:
        return position   



# this function draws the board
def drawBoard():
    print("")
    print("")
    print(" ",drawPieces(1),"  |   (2)    | (3) ")
    print("     |          |     ")
    print("----------------------")
    print(" (4) |   (5)    | (6) ")
    print("     |          |     ")
    print("----------------------")
    print(" (7) |   (8)    | (9) ")
    print("     |          |     ")
    
    return

# this function manages player moves
def playerMove(move):
    return

# this function manages computer moves
def computerMove(computerMove):
    return

while True:
    print(drawBoard())
    move=input("Please choose a move (99 to quit): ")
    if move == "99":
        break
    elif str(move) in computerSpaces or str(move) in humanSpaces:
        print("this is a invalid move")
    else:
        humanSpaces.append(move)
        print(humanSpaces)
   # playerMove(move)

Javascript Version[edit]

File:Javascript tictactoe.zip


How you will be assessed[edit]

Your solution will be graded using the following axis:


Scope

  • To what extent does your code implement the features required by our specification?
  • To what extent is there evidence of effort?

Correctness

  • To what extent did your code meet specifications?
  • To what extent did your code meet unit tests?
  • To what extent is your code free of bugs?

Design

  • To what extent is your code written well (i.e. clearly, efficiently, elegantly, and/or logically)?
  • To what extent is your code eliminating repetition?
  • To what extent is your code using functions appropriately?

Style

  • To what extent is your code readable?
  • To what extent is your code commented?
  • To what extent are your variables well named?
  • To what extent do you adhere to style guide?

References[edit]

A possible solution[edit]

Click the expand link to see one possible solution in Python, but NOT before you have tried and failed!

import PySimpleGUI as sg
import random

from PySimpleGUI.PySimpleGUI import WINDOW_CLOSED
sg.theme('Python')


turn = 1
turn2 = 0
board = [0,1,2,3,4,5,6,7,8]
win_p = [
[0,1,2],
[3,4,5],
[6,7,8],
[0,3,6],
[1,4,7],
[2,5,8],
[0,4,8],
[2,4,6]
]

def draw_board():
    print(board[0],board[1],board[2])
    print(board[3],board[4],board[5])
    print(board[6],board[7],board[8])


computer_first_move = random.choice(board)
board[computer_first_move-1] = "X"

layout = [
[sg.Text('The turn is:',font=("Helevtica", 25), key='D'), sg.Text(turn, key = 'D1',font=("Helevtica", 25))],
[sg.Button(board[0],font=("Helevtica", 50),key = '0'),sg.Button(board[1],font=("Helevtica", 50),key = '1'),sg.Button(board[2],font=("Helevtica", 50),key = '2')],
[sg.Button(board[3],font=("Helevtica", 50),key = '3'),sg.Button(board[4],font=("Helevtica", 50),key = '4'),sg.Button(board[5],font=("Helevtica", 50),key = '5')],
[sg.Button(board[6],font=("Helevtica", 50),key = '6'),sg.Button(board[7],font=("Helevtica", 50),key = '7'),sg.Button(board[8],font=("Helevtica", 50),key = '8')],
]

window = sg.Window('TicTacToe', layout)

while True:
    event, values = window.read()
    if event == WINDOW_CLOSED:
        break

    print(event)

    for i in range(0,9):
        if str(event) == str(board[i]):
            window[str(i)].update('O')
            board[i] = "O"
            draw_board()

    computer_turn = True
    count2 = 0
    win = 0
    loss = 0


#================================================================

    if(event):
        for x in win_p:
            count = 0
            count1 = 0
            poss = []
            
            for i in x:
                if(board[i]) == "O":
                    count = count +1


            if count == 3:
                win += 1            
                break


        if win == 1:
            draw_board()
            sg.popup('YOU WON!')
            

    # #================================================================

        for x in win_p:
            count = 0
            count1 = 0
            poss = []
            
            for i in x:
                if(board[i]) == "O":
                    count = count +1

            if count == 0:
                for i in x:
                    if(board[i]) == "X":
                        count1 = count1 + 1
                        

                if (count1 == 2) and (computer_turn == True):
                    for i in x:
                        if(board[i]) != "X":
                            window[str(i)].update('X')
                            board[i] = "X"
                            loss = loss + 1
                            break
                    computer_turn == False

        if loss == 1:
            draw_board()
            sg.popup("YOU LOST")
            break
            

    #=============================================================================


        for x in win_p:
            count = 0
            count1 = 0
            poss = []
            
            for i in x:
                if(board[i]) == "O":
                    count = count +1

            if count == 2 and computer_turn == True:
                for i in x:
                    if(board[i]) != "O" and (board[i]) != "X":

                        board[i] = "X"
                        window[str(i)].update('X')

                        computer_turn = False


    # #=============================================================================

        for x in win_p:
            count = 0
            count1 = 0
            poss = []
            
            for i in x:
                if(board[i]) == "O":
                    count = count +1

            if count == 0:
                for i in x:
                    if(board[i]) == "X":
                        count1 =+ 1
                if (count1 == 1) and (computer_turn == True):
                    print(x)
                    for i in x:
                        print(i,board[i])
                        if(board[i]) != "X":
                            poss.append(i)
                        print(poss)
                    q = random.choice(poss)
                    board[q] = "X"
                    window[str(q)].update('X')

                    computer_turn = False




        for i in range(0,9):
            if board[i] != i:
                count2 = count2 + 1
        print("count2:",count2)

        if count2 == 8:
            for i in range(0,9):
                if board[i] == i:
                    board[i] = "X"
                    window[str(i)].update('X')

                    draw_board()
                    sg.popup("Tie")
                    break
        if count2 == 9:
            draw_board()
            sg.popup("Tie")
            break


        print("="*25)
        draw_board()
        turn = turn+1
        window['D1'].update(turn)
        print("loop")




# ====================== another example below ==================================

import os, random, time

#setting
table = ["\033[1;30m1\033[0m","\033[1;30m2\033[0m","\033[1;30m3\033[0m","\033[1;30m4\033[0m","\033[1;30m5\033[0m","\033[1;30m6\033[0m","\033[1;30m7\033[0m","\033[1;30m8\033[0m","\033[1;30m9\033[0m"]
# table1 = ["\033[1;30m1\033[0m","\033[1;30m2\033[0m","\033[1;30m3\033[0m","\033[1;30m4\033[0m","\033[1;30m5\033[0m","\033[1;30m6\033[0m","\033[1;30m7\033[0m","\033[1;30m8\033[0m","\033[1;30m9\033[0m"]
ending = False
def drawing():
    os.system('clear')
    print(f"{table[0]}   {table[1]}   {table[2]}")
    print(f"\n{table[3]}   {table[4]}   {table[5]}")
    print(f"\n{table[6]}   {table[7]}   {table[8]}")

#event loop
while True:
    drawing()
    a=0
    b=0

#win or lose or draw
    # if any(table1) in table:
    #     print("You draw!")
    #     ending = True
    if table[0] == table[4] == table[8]:
        if table[0] == 'O':
            print("You Win!")
            ending = True
        else:
            print("You Lose!")
            ending = True
    elif table[2] == table[4] == table[6]:
        if table[2] == 'O':
            print("You Win!")
            ending = True
        else:
            print("You Lose!")
            ending = True
    for i in range(3):
        if table[a] == table[a+1] == table[a+2]:
            if table[a] == 'O':
                print("You Win!")
                ending = True
            else:
                print("You Lose!")
                ending = True
        elif table[b] == table[b+3] == table[b+6]:
            if table[b] == 'O':
                print("You Win!")
                ending = True
            else:
                print("You Lose!")
                ending = True
        a += 3
        b += 1

    if ending == True:
        break    

#user's turn
    user_move = int(input("\nplace number: "))
    if table[user_move-1] != 'O' and table[user_move-1] != 'X':
        table[user_move-1] = 'O'
    else:
        input("that's not proper place...")
        continue
    drawing()



#computer's turn
    while True:
        a=0
        b=0
## simple UI logic
        # if table[4] == 'X' or 'O':
        #     if table[4] == table[0] or table[4] == table[8]:
        #         if table[0] == 'O' or 'X':
        #             table[8] = 'X'
        #             break
        #         elif table[8] == 'O' or 'X':
        #             table[0] = 'X'
        #             break 
        #     elif table[4] == table[2] or table[4] == table[6]:
        #         if table[2] == 'O' or 'X':
        #             table[6] == 'X'
        #             break
        #         elif table[6] == 'O' or 'X':
        #             table[2] == 'X'
        #             break
        #     else:
        #         pass
        
        # for i in range(3):
        #     if table[a] == table[a+1] or table[a+1] == table[a+2] and table[a+1] == 'X' or 'O':
        #         if table[a] == 'O' or 'X':
        #             table[a] = 'X'
        #             logic_loop = False
        #         if table[a+2] == 'O' or 'X':
        #             table[a+2] = 'X'
        #             break
        #     elif table[b] == table[b+3] or table[b+3] == table[b+6] and table[b+3] == 'X' or 'O':
        #         if table[b] == 'O' or 'X':
        #             table[b] = 'X'
        #             break
        #         if table[b+6] == 'O' or 'X':
        #             table[b+6] = 'X'
        #             break
        #     else: 
        #         pass
        #     a += 3
        #     b += 1
    
        com_move = random.randrange(1,10)
        if table[com_move-1] != 'O' and table[com_move-1] != 'X':
            table[com_move-1] = 'X'
            break
        else:
            continue

    time.sleep(0.7)






# ============================ second example below ====================
import random

# initialization stuff here: 

board = [1,2,3,4,5,6,7,8,9]
computerSpaces = []
humanSpaces =[]
game = 0

# this function draws pieces on the board. 
def drawPieces(position):
    if position in humanSpaces:
        return "X"
    elif position in computerSpaces:
        return "O"
    else:
        return position   


# this function manages player moves
def playerMove(move):
    humanSpaces.append(move)
    humanSpaces.sort()
    board.remove(int(move))
    return

# this function manages computer moves
def computerMove():
    # we choose a possible move from any moves left in the list board
    move=random.choice(board)
    # we append the move we just made into a list
    computerSpaces.append(str(move))
    # we sort the list because our win conditions are in a certain order. 1,2,3 is a win, but 3,2,1 isn't. 
    # sorting is a bit of a hack (there might be a better way to test for membership in a list iregardless of order)
    computerSpaces.sort()
    # finally, we remove the place from our list keeping track of the places. 
    board.remove(move)
    return

# this function draws the board
def drawBoard():
    print("")
    print("")
    print(" ",drawPieces('1'),"  |   ",drawPieces('2'),"    | ",drawPieces('3'), "  ")
    print("      |          |     ")
    print("----------------------")
    print(" ",drawPieces('4'),"  |   ",drawPieces('5'),"    | ",drawPieces('6'), "  ")
    print("      |          |     ")
    print("----------------------")
    print(" ",drawPieces('7'),"  |   ",drawPieces('8'),"    | ",drawPieces('9'), "  ")
    print("      |          |     ")
    return

# this functions looks for win win conditions
def winConditions():
    winConditions = [['1','2','3'],['4','5','6'],['7','8','9'],['1','5','9'],['3','5','7'],['1','4','7'],['2','5','8'],['3','6','9']]
    if any(humanSpaces) in winConditions:
        print("human won")
        raise SystemExit
    elif any(computerSpaces) in winConditions:
        print("commputer won")
        raise SystemExit
    return


# main game loop
while True:
    print(board)
    print(drawBoard())
    move=input("Please choose a move (99 to quit): ")
    if move == "99":
        break
    elif str(move) in computerSpaces or str(move) in humanSpaces:
        print("this is a invalid move")
    else:
        playerMove(move)
        computerMove()
        winConditions()
        print(humanSpaces)
        print(computerSpaces)
        # playerMove(move)


#
# ==========================.  example three below ==================
#

import itertools
import random
import os

def check_win(board):
    for j in [0,3,6]:
        if board[j] == board[j+1] and board[j] == board[j+2] and board[j] != "-":
            return board[j]
    for j in [0,1,2]:
        if board[j] == board[j+3] and board[j] == board[j+6] and board[j] != "-":
            return board[j]
    if board[0] == board[4] and board[0] == board[8] and board[0] != "-":
        return board[0]
    if board[2] == board[4] and board[2] == board[6] and board[2] != "-":
        return board[2]
    return "draw"

def calculate(stones):
    table = ["-", "-", "-", "-", "-", "-", "-", "-", "-"]
    pl_1 = [stones[0],stones[2],stones[4],stones[6],stones[8]]
    for j in range(9):
        k = stones[j]
        if k in pl_1:
            table[k-1] = "1"
        else:
            table[k-1] = "2"
        result = check_win(table)
        if result == "1":
            return "player 1"
        elif result == "2":
            return "player 2"
        else:
            pass
    return "draw"

def find_ans(log,turn):
    INF = 10**10
    rates = []
    left = [1,2,3,4,5,6,7,8,9]
    for i in log:
        left.remove(i)

    left_clone = []
    for i in left:
        left_clone.append(i)

    for k in left_clone:
        t_logs = []
        left.remove(k)
        for i in itertools.permutations(left,len(left)):
            b = list(i)
            t_logs.append(log +[k]+ b)
            
        left = [1,2,3,4,5,6,7,8,9]
        for i in log:
            left.remove(i)
        
        count = 0
        wincount = 0
        losecount = 0
        for i in t_logs:
            count += 1
            result = calculate(i)
            if turn == 0:
                if result == "player 1":
                    losecount += 1
                if result == "player 2":
                    wincount += 1
            elif turn == 1:
                if result == "player 2":
                    losecount += 1
                if result == "player 1":
                    wincount += 1


        winrate = wincount/count
        loserate = losecount/count
        rates.append([k,winrate, loserate])

    g_lose = INF
    for i in rates:
        if i[2] < g_lose:
            decision = i[0]
            g_win = i[1]
            g_lose = i[2]
        elif i[2] == g_lose and i[1] > g_win:
            decision = i[0]
            g_win = i[1]
            g_lose = i[2]
        elif i[2] == g_lose and i[1] == g_win:
            if random.choice([True, False]):
                decision = i[0]
                g_win = i[1]
                g_lose = i[2]
                
        if i[1] >= 0.95:
            decision = i[0]
            g_win = i[1]
            g_lose = i[2]
            break

    return decision

# tic-tac-toe
table = ["-","-","-","-","-","-","-","-","-"]
log = []
first = random.choice(['your',"opponent's"])
if first == 'your':
    now = True
else:
    now = False

def turn(choice,sign):
    table[choice-1] = sign
    log.append(choice)
    update_color('grid1',table[0])
    update_color('grid2',table[1])
    update_color('grid3',table[2])
    update_color('grid4',table[3])
    update_color('grid5',table[4])
    update_color('grid6',table[5])
    update_color('grid7',table[6])
    update_color('grid8',table[7])
    update_color('grid9',table[8])
    end = check_win(table)
    if end == "draw":
        pass
    elif end == "x":
        sg.popup("Blue win!")
        return 'break'
    elif end == "o":
        sg.popup("Red win!")
        return 'break'
    if '-' not in table:
        return 'break'


import PySimpleGUI as sg
colors = [None, 'red','blue']

def update_color(grid,mark):
    if mark == '-':
        window[grid].update(background_color='white')
    elif mark == 'o':
        window[grid].update(background_color='red')
    elif mark == 'x':
        window[grid].update(background_color='blue')

sg.theme('DarkAmber')
layout = [
    [sg.Text(f"{first} turn", key='Turn')],
    [sg.Text(key='grid1',size=(5,3),background_color='white',text_color='black'),sg.Text(key='grid2',size=(5,3),background_color='white',text_color='black'),sg.Text(key='grid3',size=(5,3),background_color='white',text_color='black')],
    [sg.Text(key='grid4',size=(5,3),background_color='white',text_color='black'),sg.Text(key='grid5',size=(5,3),background_color='white',text_color='black'),sg.Text(key='grid6',size=(5,3),background_color='white',text_color='black')],
    [sg.Text(key='grid7',size=(5,3),background_color='white',text_color='black'),sg.Text(key='grid8',size=(5,3),background_color='white',text_color='black'),sg.Text(key='grid9',size=(5,3),background_color='white',text_color='black')],
    [sg.Button('1',size=(1.5,1.5)),sg.Button('2',size=(1.5,1.5)),sg.Button('3',size=(1.5,1.5))],
    [sg.Button('4',size=(1.5,1.5)),sg.Button('5',size=(1.5,1.5)),sg.Button('6',size=(1.5,1.5))],
    [sg.Button('7',size=(1.5,1.5)),sg.Button('8',size=(1.5,1.5)),sg.Button('9',size=(1.5,1.5))],
    [sg.Button('pass turn',)]
]

window = sg.Window('IMPOSIBLE TIC_TAC_TOE',layout)

while True:
    p1_choice = '$$'
    event, value = window.read()
    if event == sg.WINDOW_CLOSED:
        break
    if True:
        if event == '1':
            if table[0] == '-':
                p1_choice = 1
        if event == '2':
            if table[1] == '-':
                p1_choice = 2
        if event == '3':
            if table[2] == '-':
                p1_choice = 3
        if event == '4':
            if table[3] == '-':
                p1_choice = 4
        if event == '5':
            if table[4] == '-':
                p1_choice = 5
        if event == '6':
            if table[5] == '-':
                p1_choice = 6
        if event == '7':
            if table[6] == '-':
                p1_choice = 7
        if event == '8':
            if table[7] == '-':
                p1_choice = 8
        if event == '9':
            if table[8] == '-':
                p1_choice = 9
        if not now:
            p1_choice = -1
        if p1_choice == '$$':
            continue

    if first == 'your':
        if now:
            if turn(p1_choice,'x') == 'break':
                break
        else:
            p2_choice = find_ans(log,0)
            if turn(p2_choice,'o') == 'break':
                break
    
    if first == "opponent's":
        if now:
            if turn(p1_choice,'o') == 'break':
                break
        else:
            p2_choice = find_ans(log,1)
            if turn(p2_choice,'x') == 'break':
                break
    
    if now:
        window['Turn'].update("opponent's turn")
    else:
        window['Turn'].update("your turn")
    now = not now

end = check_win(table)
    
if end == "draw":
    sg.popup("draw")
    
window.close()


Click the expand link to see one possible solution in Javascript, but NOT before you have tried and failed!