checking for a down diagonal win in tic tac toe? - python

sorry if this is really basic! i'm in first year computer science.
i am trying to write a function to check if there is a win on a tictactoe board of NxN size (so i can't hardcode any values); the win has to be from the top left, to the bottom right.
i've already written a function for the upwards diagonal, so i'ved based it around that, but with a list like this: [ [ 'X' , ' ' ] , [ ' ' , ' ' ] ] the function returns True - which it definitely should not.
here's what i have right now, but i have tried many things:
#these can be anything but here's just an example of what i'm using to test
cur = [['X',' '],[' ',' ']]
player= 'X'
def check_down_diag(cur, player):
columncount = 0
for row in cur:
if row[columncount] != player:
columncount += 1
return False
else:
return True

The first step to figure out is the logic. You have a player symbol (here 'X') and a Tic-Tac-Toe size ('N', usually 3 for TTT). So to see if there is a diagonal winner, you would check the two diagonals:
(0, 0), (1, 1), (2, 2), ... (N-1, N-1)
and:
(N-1, 0), (N-2, 1), (N-3, 2) ... (0, N-1)
which are the indeces into the fields to check.
So now you know the two sets of locations to check, and you know which symbol to check for. So write a function which accepts an N for size/dimension and a symbol for which player, and you should be good to go. You can check for both diagonals in one loop, or you can check them in separate loops to start. If you do one loop, you must go through the whole loop once until both checks fail. If you do one loop/diagonal at a time, you should break from the loop as soon as you find a single failure condition, to improve performance.

A while back I wrote a function for pattern finding in 2d arrays specifically for something like this:
def find_pattern(array, pattern, value):
for row in range(len(array)):
for column in range(len(array[0])):
try:
for y, x in pattern:
_value = array[y + row][x + column]
if value != _value:
break
else:
return pattern, (pattern[0][0] + row, pattern[0][1] + column)
except IndexError:
break
return None
The patterns are formed like so (these specific ones are for the standard tic tac toe board (all win conditions)):
win_patterns = [
((0, 0), (0, 1), (0, 2)),
((0, 0), (1, 0), (2, 0)),
((0, 0), (1, 1), (2, 2)),
((0, 2), (1, 1), (2, 0)),
]
The way it works is simple, it is just a tuple of (x, y) coordinates in the grid, starting from 0, so the first pattern would search for straight lines horizontally, second for vertical lines, third and fourth for both diagonals.
Then you can loop over the patterns, pass them to the function along with the 2d array of the board and the value that has to be found in this pattern (' ' values don't mean anything they are there so that the array is more readable):
board = [
['x', ' ', 'x', ' ', ' '],
[' ', 'x', ' ', ' ', ' '],
[' ', ' ', 'x', ' ', 'x'],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', 'x', ' ', ' '],
]
for pattern in win_patterns:
found = find_pattern(board, pattern, 'x')
if found:
print(found)
break

For the main diagonal, check that all the values that are at the same row and column (i.e. the main diagonal) are equal to the player's symbol:
def check_down_diag1(cur, player):
return all( cur[i][i]==player for i in range(len(cur)) )
For the other diagonal, simply invert one of the dimensions:
def check_down_diag2(cur, player):
return all( cur[i][-1-i]==player for i in range(len(cur)) )
You could also check both diagonals at the same time:
def check_down_diags(cur, player):
return all( cur[i][i]==player for i in range(len(cur)) ) \
or all( cur[i][-1-i]==player for i in range(len(cur)) )

Related

how can I check a diagonal of my table for repeats?

I want to check if values in my table's diagonal are equal. How can I do that without checking each diagonal cell? I understand that I can use a loop to do that but I just can't figure out what loop to use.
table = [['1', ' ', '1'],
[' ', '1', ' '],
['1', ' ', '1']]
if tb[0][0] == tb[1][1] == tb[2][2] != ' ' or tb[-1][0] == tb[-2][1] == tb[-3][2] != ' ':
print(True)
Working with arrays and matrices is easiest with numpy. So if this is an option for you, this is how you could go about checking the diagonal of your table:
import numpy as np
table = [['1', ' ', '1'],
[' ', '1', ' '],
['1', ' ', '1']]
nptable = np.array(table)
# now we can simply get the unique values in the diagonal:
diag_values = np.unique(nptable.diagonal())
If you have a single value in diag_values then you know that all diagonal values are equal.
Now if you want to also check the other diagonal, you can use np.fliplr and redo the same:
diag_values = np.unique(np.fliplr(nptable).diagonal())
If you want to stick to lists then you could loop over the rows of table until you encounter a change if the value of the diagonal:
diag_val = table[0][0]
for i, row in enumerate(table):
if row[i] != diag_val: # row[i] is basically table[i][i]
print(f'diagonal value changes in row {i=}.')
break # we stop the loop as we encoutered a change
Checking the other diagonal is just as easy, simply access the element -i-1 instead of element i in each row:
diag_val = table[0][-1]
for i, row in enumerate(table):
if row[-i-1] != diag_val:
print(f'diagonal value changes in row {i=}.')
break # we stop the loop as we encoutered a change
Or, if the value in both cases should be the same, say diag_val='1', you can do it in one go:
diag_val = '1'
for i, row in enumerate(table):
if row[i] != diag_val or row[-i-1] != diag_val:
print(f'diagonal value changes in row {i=}.')
break # we stop the loop as we encoutered a change
Hope that helped!
One way is to do this is to extract the values of both diagonals as sets and then check if: a) the sets are equal and b) their size is 1.
main_diag = {row[ i] for i, row in enumerate(tb)}
anti_diag = {row[-i] for i, row in enumerate(tb, start=1)}
if main_diag == anti_diag and len(main_diag) == 1:
print('All values along both diagonals are the same.')
you can use numpy.diagonal() to get all the elements whether on the first or the second diagonal and then compare all the elements to satisfy the condition using numpy.all()
import numpy as np
mtx = np.array([['2', ' ', '1'],
[' ', '1', ' '],
['1', ' ', '3']])
first_diag = mtx.diagonal()
second_diag = (np.fliplr(mtx)).diagonal()
result = np.all(second_diag == '1')
if result:
print("all the elements in the diagonal are equal to one")
else:
print("not all elements in the diagonal are equal")

Can someone explain how this loop is printing this tuple?

I'm trying to understand the solutions to question 5 from pythonchallenge, but I don't understand how the for loop is printing that data from the tuple. The solution is from here
Data contains a list of tuples, eg. data = [[(' ', 95)], [(' ', 14), ('#', 5), (' ', 70), ('#', 5), (' ', 1) ...]]
for line in data:
print("".join([k * v for k, v in line]))
What should be printed out is an ASCII graphic made up of '#'.
This one is sneaky. It's a list of lists of tuples. The inner list is a row on the terminal, and each tuple is a character followed by the number of times that
character should be printed.
It looks like it's iterating through the list, and for each tuple,
printing out tuple[0] tuple[1]-times.
It prints '' 95 times, then '' 14 times, then '#' 5 times, etc, inserting newlines
inbetween each inner list.
Consider:
>>> line = [(' ', 3), ('#', 5), (' ', 3), ('#', 5)]
>>> strs = [k * v for k, v in line]
Then:
>>> strs
[' ', '#####', ' ', '#####']
Furthermore:
>>> ''.join(strs)
' ##### #####'

Python Programming 3.4.2, Naughts and Crosses. Best way to check how to see if game is won?

#!/usr/bin/python3.4
import tkinter as tk
import time
import os
root = tk.Tk()
label = tk.Label(root)
root.configure(background='#0C142E')
ButtonTable=[]
Turn = 0 # 0(x) 1(O)
XO=["X","O"]
wins = [
'111 000 000', '000 111 000', '000 000 111', # Across
'100 100 100', '010 010 010', '001 001 001', # Down
'100 010 001', '001 010 100', # Diagonal
]
GridArray=["","","","","","","","","",] # Gets replaced with x,o to record progress
def CheckWin():
#something goes here?
def CreateButtonmid(Text,side, Return):
return CreateButton
def ChooseButton(xx,b):
global Turn
b.configure(state = "disabled")
print(xx)
b.config(text=XO[Turn])
GridArray[int(xx)]=XO[Turn]
CheckWon()
if Turn == 0:
Turn = 1
else:
Turn=0
label.configure(text="Turn: "+XO[Turn])
print(GridArray)
def CreateButton(Text,side,Return):
b = tk.Button(side,text=Text)
b.pack(side="left")
b.config(command=lambda: ChooseButton(Return,b))
ButtonTable.append(b)
b.configure(background='#323642',bd=0,fg="white",height=5,width=10)
return b
label.pack(side = "top")
label.config(bg="#0C142E",fg="#fff",text="(STARTING:X)")
topframe = tk.Frame(root)
topframe.pack( side = "top" )
CreateButton("[]",topframe,("0"))
CreateButton("[]",topframe,("1"))
CreateButton("[]",topframe,("2"))
midframe = tk.Frame(root)
midframe.pack( side = "top" )
CreateButton("[]",midframe,("3"))
CreateButton("[]",midframe,("4"))
CreateButton("[]",midframe,("5"))
bottomframe = tk.Frame(root)
bottomframe.pack( side = "top" )
CreateButton("[]",bottomframe,("6"))
CreateButton("[]",bottomframe,("7"))
CreateButton("[]",bottomframe,("8"))
root.mainloop()
Basically it is a multiplayer game that will require two people to play. What would be the best way to check to see if someone has won. I have no idea and I'm new to programming, any resources to help with this or my coding are always welcome
def get_winner(grid):
'''returns 'X', 'O', or None'''
line_dxs = [
# rows
(0,1,2),
(3,4,5),
(6,7,8),
# cols
(0,3,6),
(1,4,7),
(2,5,8),
# diags
(0,4,8),
(2,4,6)
]
for dxs in line_dxs:
line = [grid[dx] for dx in dxs]
if line == ['X', 'X', 'X']:
return 'X'
elif line == ['O', 'O', 'O']:
return 'O'
In action:
>>> get_winner(['X', 'O', 'X',
... 'O', 'O', 'X',
... 'X', 'O', '' ])
'O'
>>> get_winner(['X', 'O', 'X',
... 'O', 'O', 'X',
... 'X', '' , 'O' ])
>>> get_winner(['X', 'O', 'X',
... 'O', 'O', 'X',
... 'X', '' , 'X' ])
'X'
Your data representation makes this harder than it needs to be. Presently, you store a grid as a list of the 9 squares, starting at the upper left and proceeding by rows, across and then down. Just to access the square in (row 1, column 2), for example, you have to do arithmetic.
Better representations let you address squares directly by their row and column indexes. In Python, counting starts at 0, so let's say that the rows are 0, 1, 2, and likewise the columns. Two alternatives to consider:
a 3-element list of the rows, each row a 3-element list for the values in the squares at the corresponding columns:
grid = [["", "", ""], ["", "", ""], ["", "", ""]]
With this grid, the square in row i, column j is just grid[i][j].
A dict:
dgrid = {(i,j): "" for i in range(3) for j in range(3)}
With this representation, the square in row i, column j is just dgrid[i,j]. I'll use this in the code that follows.
Checking the grid for a winning state is now much simpler. Here's a function to check whether row i has a win for player (equal to 'X' or 'O', let's say):
def winning_row(i, player):
'''Return True if all entries in row i are equal to player.
player is either 'X' or 'O'.
'''
return all(dgrid[i,j] == player for j in range(3))
You can define the function winning_column(j, player) similarly. Checking the diagonals is a little different. We can use two functions, winning_main_diagonal(player) and winning_other_diagonal(player). Here's the latter:
def winning_other_diagonal(player):
return all(dgrid[i,2-i] for i in range(3))
These functions all take a player parameter because you only need to check for a winning configuration after a particular player has moved. You don't need to check the entire grid to see whether some player won, and if so which one.
This function reports whether the player who just moved by marking square (i,j) has just won:
def just_won(i, j, player):
if winning_row(i, player):
return True
if winning_column(j, player):
return True
if i == j and winning_diagonal(player):
return True
if I + j == 2 and winning_other_diagonal(player):
return True
return False

Python, counting from an inputted string. Needs to be returned in a specific order?

So i am typing a code where a user will need to input >>Count('bla bla bla') and the program needs to count the in the bla bla bla phrase and return the word with its count in this SPECIFIC order.
Any Help?
Your count function is not used correctly. You want text.search(vowel), not vowel.search(text)
>>> s = 'this is some string with a lot of vowels'
>>> vowels = 'aeiou'
>>> {i : s.count(i) for i in vowels}
{'a': 1, 'i': 4, 'e': 2, 'u': 0, 'o': 4}
Dictionaries have no order, so if you want the count in vowel order:
>>> [(i,s.count(i)) for i in vowels]
[('a', 1), ('e', 2), ('i', 4), ('o', 4), ('u', 0)]
def vowelCount(text):
vowels = 'aeiou'
return ("a, e, i, o, and u appear, respectively, %s times." %", ".join([ str(text.count(x)) for x in vowels]))
print vowelCount('bla bla bla')
Hope this helps.
The code as written doesn't even examine the input text at all. You're counting the number of times each vowel appears in vowels.
Replace with text.count(i) instead of vowels.count(i).
You made a typo:
def vowelCount(text):
vowels = 'aeiou'
counts = {x:text.count(x) for x in vowels}
keys = counts.keys()
values = counts.values()
return ','.join(keys[:-1]) + ' and '+ keys[-1] +' appear, respectively, '+ ','.join(str(v) for v in values)+' times.'

Find consecutive combinations [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Rolling or sliding window iterator in Python
I'm new to programming and am learning Python. I'm looking for an efficient/pythonic way to solve a problem.
I'd like a function that returns a list of iterables containing the combinations of a parent iterable as long as the elements in the combination appear the same same consecutive order as the original parent iterable.
I'm not sure if "consecutive" if the right word to describe this concept as 'consecutive' typically means, 'the same element repeated.' e.g. [1,1,1], 'aaa', etc...
I mean that given the list [1,2,3,4,5]:
[1,2,3] is consecutive but [1,2,4] is not. (Is there a word for this?)
Here's a function consecutive_combinations() I created and the expected behavior:
def consecutive_combinations(iterable, consec):
begin = 0
chunks = len(iterable) + 1 - consec
return [iterable[x + begin: x + consec] for x in xrange(chunks)]
def test():
t = (1,2,3,4,5)
s = "The quick brown fox jumps over the lazy dog."
CC = consecutive_combinations
assert CC(t, 2) == [(1, 2), (2, 3), (3, 4), (4, 5)]
assert CC(t, 3) == [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
assert CC(t, 4) == [(1, 2, 3, 4), (2, 3, 4, 5)]
assert CC(t, 5) == [(1, 2, 3, 4, 5)]
assert CC(s, 3) == ['The', 'he ', 'e q', ' qu', 'qui', 'uic', 'ick', 'ck ', 'k b', ' br', 'bro', 'row', 'own', 'wn ', 'n f', ' fo', 'fox', 'ox ', 'x j', ' ju', 'jum', 'ump', 'mps', 'ps ', 's o', ' ov', 'ove', 'ver', 'er ', 'r t', ' th', 'the', 'he ', 'e l', ' la', 'laz', 'azy', 'zy ', 'y d', ' do', 'dog', 'og. ']
assert CC('', 3) == []
print "All tests passed!"
test()
Is this an efficient solution? Is there something in itertools or some other pre-built module that would do this sort of thing?
I like the pragmatic zip approach:
n = 3
s = "The quick brown fox jumps over the lazy dog."
zip(*(s[i:] for i in xrange(n)))
It's not super-efficient and it only works for sequences, but often enough it does the job.
The corresponding itertools solution is a pretty straightforward transformation of the above:
from itertools import izip, islice, tee
def slices(iterable, n):
return izip(*(islice(it, i, None) for i, it in enumerate(tee(iterable, n))))
Soo many is...
Nevertheless, this one should work for any iterable (but may be slower for plain sequences like lists or strings).
Your solution is fine. You could however shorten it a little bit. For example:
def subsequences(iterable, length):
return [iterable[i: i + length] for i in xrange(len(iterable) - length + 1)]

Categories