-1

I recently started learning programming and I am not really good at it. Today, it tried to program the simple game "TicTacToe". But I got an error in the section where I figure out who winner is and I really don't what I'm doing wrong. Since I'm a beginner, I probably made also lots of mistakes concerning the structure (functions,classes, etc.) and the readability of my code, so feel free to give me valuable feedback :) I hope it's not too messy

The typical error I get is: invalid syntax

Here is the code:

# This is how the board looks like:        
# L1|M1|R1   D1 (Diagonal): L1,M2,R3
# L2|M2|R2   D2 (Diagonal) L3,M2,R1
# L3|M3|R3

data = {}
tiles= ("L1","L2","L3","M1","M2","M3","R1","R2","R3")


print("This is the board:")
print("L1|M1|R1")
print("L2|M2|R2")
print("L3|M3|R3\n")

p1 = str(input("Player 1, please enter your name: "))
p2 = str(input("Player 2, please enter your name: "))


while True:
    if len(data) == 9:   #when all tiles have been chosen but there is no winner
        print("It seems like a draw!")
        break

    while True:    #enter tile player1
        input_p1 = str(input(p1 + ", please choose a tile: "))

        if input_p1 in data or input_p1 not in tiles:
            print("\This tile has already been chosen or does not exist. Try again")
            continue

        data[input_p1] = p1
        break

    while True:   #enter tile player2
        input_p2 = str(input(p2 + ", please choose a tile: "))

        if input_p2 in data or input_p2 not in tiles:
            print("\nThis tile has already been chosen or does not exist. Try again")
            continue

        data[input_p2] = p2
        break


    #Check, if Player1 has won:
    if (data["L1"] == p1 and data["L2"] == p1 and data["L3"] == p1) or (data["M1"] == p1 and data["M2"] == p1 and data["M3"] == p1) or (data["R1"] == p1 and data["R2"] == p1 and data["R3"] == p1) or (data["L1"] == p1 and data["M2"] == p1 and data["R3"] == p1) or (data["L3"] == p1 and data["M2"] == p1 and data["R1"] == p1): 
        print("We have a winner: " + p1)

    #Check, if Player2 has won:
    elif (data["L1"] == p2 and data["L2"] == p2 and data["L3"] == p2) or (data["M1"] == p2 and data["M2"] == p2 and data["M3"] == p2) or (data["R1"] == p2 and data["R2"] == p2 and data["R3"] == p2) or (data["L1"] == p2 and data["M2"] == p2 and data["R3"] == p2) or (data["L3"] == p2 and data["M2"] == p2 and data["R1"] == p2):
        print("We have a winner: " + p2)

Also: I don't know how to better phrase the part below ^^

error:

This is the board:
L1|M1|R1
L2|M2|R2
L3|M3|R3

Player 1, please enter your name: Player1
Player 2, please enter your name: Player2
Player1, please choose a tile: M1
Player2, please choose a tile: L2
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-8-9e2fcd740bfb> in <module>
     44 
     45     #Check, if Player1 has won:
---> 46     if (data["L1"] == p1 and data["L2"] == p1 and data["L3"] == p1) or (data["M1"] == p1 and data["M2"] == p1 and data["M3"] == p1) or (data["R1"] == p1 and data["R2"] == p1 and data["R3"] == p1) or (data["L1"] == p1 and data["M2"] == p1 and data["R3"] == p1) or (data["L3"] == p1 and data["M2"] == p1 and data["R1"] == p1):
     47         print("We have a winner: " + p1)
     48 

KeyError: 'L1'

  • 1
    Can you post the entire error as that tells us exactly what the problem is. – MyNameIsCaleb Sep 17 '19 at 18:58
  • `elif (p2_Ls = data["L1"] == p2 and ...` There's a syntax error on this line. Remove the `p2_Ls = `. You want `elif (data["L1"] == p2 and ...` – Paul M. Sep 17 '19 at 19:03
  • @MyNameIsCaleb here's the full error: File "", line 48 p1_Ls = data["L1"] == p1 and data["L2"] == p1 and data["L3"] == p1 ^ SyntaxError: invalid syntax – PythonBeginner1 Sep 17 '19 at 19:05
  • 1
    What are you expecting `p2_Ls = data["LX"] == p2` to return? You can't assign in an if, else statement – Nouman Sep 17 '19 at 19:06
  • @user10987432 thanks, but unfortunately that's not it – PythonBeginner1 Sep 17 '19 at 19:08
  • Check your if statements and make sure all are `==` and not `=` like @BlackThunder is saying – MyNameIsCaleb Sep 17 '19 at 19:09
  • And most importantly, what is p2_XX? – Nouman Sep 17 '19 at 19:09
  • You can also shorten that statement by doing something like `data["L1"] == data["L2"] == data["L3"]` and then if so, return the value for one of those. Then you don't have to check p1 vs p2. – MyNameIsCaleb Sep 17 '19 at 19:14
  • @MyNameIsCaleb oh I didn't notice it.^^ But still, whenever I run the program, it stops after typing in the second tile... – PythonBeginner1 Sep 17 '19 at 19:14
  • So that is a different error than what you posted above, you'll have to post that error too if you want help with that. – MyNameIsCaleb Sep 17 '19 at 19:15
  • @MyNamelsCaleb yeah it changed now that I fixed the first mistake. The thing is, python always complains about one of the keys that has not been used, even though I used "or" in the if-statement – PythonBeginner1 Sep 17 '19 at 19:17
  • Your new error is because you are checking keys that don't have a value since each loop it checks to see if there is a winner. Instead of direct access, you can use `.get` like in [this question/answer](https://stackoverflow.com/questions/11041405/why-dict-getkey-instead-of-dictkey) – MyNameIsCaleb Sep 17 '19 at 19:18
  • What do you mean by direct access? Use .get instead of ... data["L1"] == p1 and ... I am sorry I'm not good at programming :( – PythonBeginner1 Sep 17 '19 at 19:24

1 Answers1

0

Glad to see you were able to resolve your first issue.

The most recent error you are experiencing is due to the fact that your long if-statements query the data dictionary using keys which don't necessarily exist. To be precise, the data dictionary is empty initially, and new key-value pairs are added anytime a player selects a tile. Your if-statements, however, ask the dictionary to return the associated value for keys which cannot exist yet in the dictionary (you'll run into this error after the very first time both players have selected tiles when only two key-value pairs are in the dictionary).

I'm assuming you are attached to the way you've structured the code and the decisions you've made, so I won't try to convince you to do it very differently.

The way the code is written now, one fix could look like this: Instead of doing data['key'] == ..., use data.get('key') == .... The get method behaves almost exactly like the square bracket syntax []. You give it a key, and it returns the associated value. The only difference is that if the key does not exist in the dictionary, the square bracket syntax will throw a KeyError exception, but the .get() method will return None by default. This is what @MyNameIsCaleb meant when referring to "direct access" - using the square bracket syntax is considered to be direct access.

The advantage of using .get() in this case is that you have an opportunity to handle the case where a key doesn't exist, unlike with an unhandled exception, where the program just terminates. This is the part where I would recommend you read up on try and catch statements, but I promised I wouldn't introduce anything crazy new.

Literally transcribing your long if-statements using this new approach, I came up with:

if (data.get("L1") == data.get("L2") == data.get("L3") == p1) or ...

or

if all(value == p1 for value in [data.get(key) for key in "L1", "L2", "L3"]]) or \
   all(value == p1 for value in [data.get(key) for key in "M1", "M2", "M3"]]) or \
   all(value == p1 for value in [data.get(key) for key in "R1", "R2", "R3"]]) or \
   all(value == p1 for value in [data.get(key) for key in "L1", "M2", "R3"]]) or \
   all(value == p1 for value in [data.get(key) for key in "L3", "M2", "l3"]])

Which is not great, but it should work. I'm not a fan of long if-statements and repeating myself, so if I were not allowed to change any other parts of your code, I would do something like this:

winning_patterns = [
    ["L1", "L2", "L3"],
    ["M1", "M2", "M3"],
    ["R1", "R2", "R3"],
    ["L1", "M1", "R1"],
    ["L2", "M2", "R2"],
    ["L3", "M3", "R3"],
    ["L1", "M2", "R3"],
    ["L3", "M2", "R1"],
]

if any(all(value == p1 for value in [data.get(key) for key in [pattern for pattern in winning_patterns]])):
    print("player 1 wins")

Notice, you were missing some "winning patterns" in your if-statements. I've added them here for you in the winning_patterns list. It's still a long if-statement, though. Things could get even cuter if you encapsulated this whole thing in a function, which you could call for every player in the game.

Paul M.
  • 10,481
  • 2
  • 9
  • 15