#๐Ÿ”’ Tic Tac Toe not Tic Tac Toe-ing

153 messages ยท Page 1 of 1 (latest)

river spireBOT
#

@devout sierra

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

devout sierra
#

no matter what i try, i can't seem to get it to recognise a draw

#

please help :((

manic ivy
#

what is happening, and what do you expect to happen

devout sierra
#

i'm expecting line 109's condition to evaluate to True when all cells are filled and set outcome to 'Draw' and then loop back and reach line 99's elif to print out that it's been a draw and stop asking the user for any more input

#

it's a tic tac toe game where user's input goes against random input from the computer to fill up gameBoard 's nested arrays [[U0,U1,U2], [M0,M1,M2]...]

#

i'm sorry if it's a bit of a mess and painful to read. i'm a beginner

jovial wind
#

why did you use UMD?

manic ivy
#

does it print "Oh no, it's a draw!"?

devout sierra
#

yup

#

supposed to

fallow canyon
#

but it doesn't

devout sierra
#

it dont :((

fallow canyon
#

but why? lemon_thinking

#

probably that means, the outcome isn't draw.

devout sierra
#

i tried popping it into win_listener() but that was making things worse

#

i tested a bunch, whenever i run into a draw it's stuck on an infinite loop

devout sierra
manic ivy
#

your win_listener seems to update outcome, and it doesn't know about draws

devout sierra
#

def win_listener():
global matchfin
matchfin = False

#diagonals
if gameBoard[0][0] == gameBoard[1][1] == gameBoard[2][2] != ' ':
matchfin = True
return [True, matchfin] if gameBoard[1][1] == 'X' else [False, matchfin]
elif gameBoard[0][2] == gameBoard[1][1] == gameBoard[2][0] != ' ':
matchfin = True
return [True, matchfin] if gameBoard[1][1] == 'X' else [False, matchfin]
for index, i in enumerate(gameBoard):
#row
if i.count(i[0]) == 3 and i[0] != ' ':
matchfin = True
return [True, matchfin] if i[0] == 'X' else [False, matchfin]
#columns
if gameBoard[0][index] == gameBoard[1][index] == gameBoard[2][index] != ' ':
matchfin = True
return [True, matchfin] if gameBoard[0][index] == 'X' else [False, matchfin]
if not any(cell == ' ' for row in gameBoard for cell in row): #since user plays last, check if all cells used up to avoid infinite robot loop
return 'Draw'

river spireBOT
#

Hey @devout sierra!

It looks like you're trying to paste code into this channel.

Discord has support for Markdown, which allows you to post code with full syntax highlighting. Please use these whenever you paste code, as this helps improve the legibility and makes it easier for us to help you.

To do this, use the following method:
```py
print('Hello, world!')
```

This will result in the following:

print('Hello, world!')```
You can **edit your original message** to correct your code block.
devout sierra
#

tried popping the condition into win_listener(), it's still stuck in an infinite loop when we draw

#

i've updated the code in the link

manic ivy
#

could you make your snippet a code block

#

(like the bot suggests)

devout sierra
#
  global matchfin
  matchfin = False

  #diagonals
  if gameBoard[0][0] == gameBoard[1][1] == gameBoard[2][2] != ' ':
    matchfin = True
    return [True, matchfin] if gameBoard[1][1] == 'X' else [False, matchfin]
  elif gameBoard[0][2] == gameBoard[1][1] == gameBoard[2][0] != ' ':
    matchfin = True
    return [True, matchfin] if gameBoard[1][1] == 'X' else [False, matchfin]
  for index, i in enumerate(gameBoard):
    #row
    if i.count(i[0]) == 3 and i[0] != ' ': 
      matchfin = True
      return [True, matchfin] if i[0] == 'X' else [False, matchfin]
    #columns
    if gameBoard[0][index] == gameBoard[1][index] == gameBoard[2][index] != ' ':
        matchfin = True
        return [True, matchfin] if gameBoard[0][index] == 'X' else [False, matchfin]
  if not any(cell == ' ' for row in gameBoard for cell in row): #since user plays last, check if all cells used up to avoid infinite robot loop
    return 'Draw'
#

sorry

#

this is win_listener() after putting the Draw condition in

manic ivy
#

that's surprising to me. i made the same change and it seems to work

devout sierra
#

that's odd. i'm using vs in case that's relevant

manic ivy
#

that wouldn't change things

#

oh, that is not the kind of infinite loop i see

#

did you change anything else after sending your original code snippet

devout sierra
#

should i revert the code in the link to what it was previously?

manic ivy
#

if you want

devout sierra
#

i only removed the condition that was under handle_input() for user at line 111

#

and placed it into win_listener()

#

okay i'll do that now

manic ivy
#

ah, you'd want to keep that presumably

#

the condition that is

devout sierra
#

reverted it

#

the one outside of the win_listener() you mean?

manic ivy
#

yeah

#

only add the condition to win_listener

#

that should be the only change necessary

#

otherwise your bot will loop forever

#

because there are no moves for it to make

devout sierra
#

yea i thought so, which was why i popped it right before so it'd continue and go back up

#
  handle_input(user_input, 'User') #user sends choice
  if not any(cell == ' ' for row in gameBoard for cell in row): #since user plays last, check if all cells used up to avoid infinite robot loop
    outcome = 'Draw'
    continue
  get_n_check_robot_input()
  handle_input(robot_input, 'Robot')  #robot sends choice
``` could it be a scope issue with outcome being assigned 'Draw' and trying to catch the value on the next iteration?
river spireBOT
#

Hey @devout sierra!

It looks like you pasted Python code without syntax highlighting.

Please use syntax highlighting to improve the legibility of your code and make it easier for us to help you.

To do this, use the following method:
```py
print('Hello, world!')
```

This will result in the following:

print('Hello, world!')```
You can **edit your original message** to correct your code block.
devout sierra
#
  handle_input(user_input, 'User') #user sends choice
  if not any(cell == ' ' for row in gameBoard for cell in row): #since user plays last, check if all cells used up to avoid infinite robot loop
    outcome = 'Draw'
    continue
  get_n_check_robot_input()
  handle_input(robot_input, 'Robot')  #robot sends choice
manic ivy
#

did you make the change to win_listener?

devout sierra
#

could it be a scope issue on the outcome being assigned 'Draw' and trying to fetch it later on the next iteration?

manic ivy
#

no, you are overwriting that value

#

outcome = win_listener()

devout sierra
#

oh shoot yeah

#

crap

manic ivy
#

did you make the change to win_listener, as suggested?

devout sierra
#

i'm not sure what to put in win_listener.

devout sierra
#

so the condition should be in both the win_listener() func and above the robot's get_input right?

manic ivy
#

yes -- the only change is to add the condition to win_listener

#

the reason is that you're overwriting the value of outcome with the return value of win_listener, but you don't check for draws inside of win_listener

fallow canyon
#

checking for draw doesn't suffice though.

devout sierra
#

oh shoot that did it!

#

it works!

manic ivy
#

in what way

manic ivy
fallow canyon
#

now the robot can still win when the player did.

devout sierra
#

i could just switch out the condition above the function getting robot's input to something that 'continue's if the list is full yes?

devout sierra
manic ivy
#

yeah now that you've fixed the bug, you'd probably want to refactor your code so you're not checking the same condition in two places

fallow canyon
#

you're only checking for a winner after the robot did its move.

devout sierra
#

but the robot can't do it's move

#

there's a continue under the condition

#

so if the list is full, i am reiterating

fallow canyon
#

the robot can't do a move when the list is full.

#

but it can do a move when the player has 3 in a row.

devout sierra
#

from what i've tested i haven't come across that issue.. let me try a few more real quick

#

no it seems to work just fine

manic ivy
#

ideally instead of if not any(cell == ' ' for row in gameBoard for cell in row), you would check win_listener()

#

inside your main while loop

devout sierra
#

yea was thinking of doing something like that but my brain is short circuiting

fallow canyon
#

yes, you need to call win_listener after every move, not only after the robot's move.

manic ivy
#

fwiw jenna, i don't see this scenario happening

#

ah nevermind

#

the bot overwrote the value at the top

devout sierra
#

i think jenna's scenario would happen only if user scores a XXX and on the exact next move so does the bot?

manic ivy
#

here i got it to happen

devout sierra
#

ah shitsticks

#

i'll rewrite this whole bugger tomorrow. i think my brain is just on power saving mode today

#

@manic ivy i really appreciate you, if possible could you give me a little feedback on how my code looks?

#

readability wise

manic ivy
#

how long have you been learning python

devout sierra
#

about 2 months

fallow canyon
#

tictactoe is one really difficult problem readability wise

manic ivy
#

if you're in vscode, you should install the "ruff" extension

#

it'll help with formatting, and a bunch of lints

#

then also enable format on save

devout sierra
manic ivy
#

ctrl+, > text editor > formatting > format on save

devout sierra
manic ivy
#

are you familiar with classes?

devout sierra
#

i do have prettier though, could the formatting of the two clash somehow?

devout sierra
manic ivy
#

you'd want to avoid the global keyword basically always

#

instead, you can have your state stored in an instance of a class

manic ivy
devout sierra
#

also i confuse python classes with javascript's so that's gonna take a bit of getting used to ;((

manic ivy
#

your win_listener function is pretty complex. it's actually kinda hard for me to see at a glance what you're trying to do

#

the names of the variables ("matchfin", for index, i) make it kinda hard

devout sierra
#

yea i'm sorry for putting you through that. it even takes me a minute of reading to realise what i was doing

manic ivy
#

it's not really something to apologize for

#

it's just code

#

the return value could be made simpler

#

i'm kinda confused why it returns an array of booleans

#

why not return a string that is either "draw", "user", "robot", or "none"

#

also it abuses ternaries. you don't need ternaries here -- you can just use an if statement

#

matchfin is a global, so no need to return it

devout sierra
#

i'm not sure what i was thinking but i guess it was supposed to be [whether the user won, whether the match had ended], not sure why i wanted 'whether the match had ended' but by the time i noticed it was redundant my brain was a bit fried and i based too many things around it

devout sierra
manic ivy
#

more nitpicky, but get_n_check_robot_input shouldn't be able to get into an infinite loop

devout sierra
manic ivy
#

instead of a while loop that randomly picks any position, you could just have it random.choice(filtered list of keys where positions[robot_input] == " ")

fallow canyon
#

maybe remove positions or gameBoard. you only need one.

manic ivy
#

that would crash if the array were empty, rather than get into an infinite loop. which is 10x easier to debug

devout sierra
#

gotcha

#

this has been so helpful, i can't thank you two enough @fallow canyon @manic ivy

#

i'll remake this soon, fingers crossed i don't have to induce any more headaches because of this :'))

manic ivy
#

the other big thing would be, you don't need to check the entire board after a user makes a play

#

you only need to check the row and column (and potentially diagonal) in which the move was played

#

ehh nevermind. i was looking at some old code and thought that would actually be easier to implement

fallow canyon
#

but you would need to pass the position then.

manic ivy
#

sure, that's just a part of making the change

#

but actually that optimization is probably more annoying to implement

devout sierra
#

but if im doing this again from scratch i'd imagine it shouldn't be too hard to do

#

also is this chat going to stick around or will it get automatically deleted?

#

actually i'll just screenshot it all just in case lol

fallow canyon
#

i think this chat will exist as long as the server.

devout sierra
#

got iti

manic ivy
#

and do definitely install ruff. it resolved a bunch of style nits i had

manic ivy
#

other style nits, instead of (choice[0] == "U" or choice[0] == "M" or choice[0] == "D") you can just do choice[0] in "UMD". int(choice[1]) in list(range(3)) => int(choice[1]) in range(3)

devout sierra
fallow canyon
#

currently you could even do choice in positions.

devout sierra
#

no idea why i didn't think of that

fallow canyon
#

that comes with time. finding all the ways to make things easier.

devout sierra
river spireBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.