mrnovice mrnovice - 20 days ago 6
Python Question

Python debugging simple script

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


  1. a list of numbers which denote positions

  2. 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

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):
    ...