mrnovice - 9 months ago 36

Python Question

So as part of a script I'm writing to play tic tac toe, I have a 'win checker' which takes as its input:

- a list of numbers which denote positions
- who started the game

It's not really important for the problem I'm having, but I thought some background might help. Here is the code:

`import matplotlib.pyplot as plt`

import math

import numpy as np

import random

import pdb

def win_checker(position_list, turn2):

win_list1 = []

win_list2 = []

for bud in xrange(len(position_list)):

if bud % 2 == 0:

win_list1.append(position_list[bud])

print win_list1

if 1 and 2 and 3 in win_list1:

return True

if 4 and 5 and 6 in win_list1:

return True

if 7 and 8 and 9 in win_list1:

return True

if 1 and 4 and 7 in win_list1:

return True

if 2 and 5 and 8 in win_list1:

return True

if 3 and 6 and 9 in win_list1:

return True

if 1 and 5 and 9 in win_list1:

return True

if 3 and 5 and 7 in win_list1:

return True

elif bud % 1 == 0:

win_list2.append(position_list[bud])

print win_list2

if 1 and 2 and 3 in win_list2:

return True

if 4 and 5 and 6 in win_list2:

return True

if 7 and 8 and 9 in win_list2:

return True

if 1 and 4 and 7 in win_list2:

return True

if 2 and 5 and 8 in win_list2:

return True

if 3 and 6 and 9 in win_list2:

return True

if 1 and 5 and 9 in win_list2:

return True

if 3 and 5 and 7 in win_list2:

return True

else:

return False

Then when I try the script for a certain position:

`win_checker([5,1,3,2], 1)`

[5]

[1]

[5, 3]

Out[57]: True

I don't understand why the output is True, if someone could explain what I'm missing that would be very helpful to me

Answer Source

**Detail of the problem:**

The **and** operator works on boolean values only. It does *not* distribute over the **in** operator (remember the distributive law of multiplication over addition?). Your expression

```
1 and 2 and 3 in win_list1
```

becomes

```
bool(1) and bool(2) and bool (3 in win_list1)
```

bool(n) is **False** for n=0, **True** for everything else.

**Immediate fix:**

Alex Hall already gave you that

**Better fix (perhaps):**

Renumber your array of choices to be a magic square:

```
6 7 2
1 5 9
8 3 4
```

Now, all you have to do is check whether you have a sum of 15 for any combination of three chosen positions. You can generate all of those with

```
itertools.combinations(win_list1, 3)
```

This would reduce your checking from 18 lines to 1 (or 2-4, if you prefer that readability).

**Extra issue:**

Your logic on **bud** is a little weird. I do understand the odd/even checking on the turn number:

```
if bud % 2 == 0:
```

However, the second one,

```
elif bud % 1 == 0:
```

is **True** for *any* integer. The percent sign is the modulus operator: divide by the mod and keep the remainder. In short, the second one is always true. Just make it an **else**.

**Another ...**

Why not make **win_list** a 2-D list? Use win_list[0] and win_list[1], so you can fold their code together. You can simply have

```
player = bud % 2
win_list[player].append(position_list[bud])
if any(sum(itertools.combinations(win_list[player], 3)) == 15):
...
```