Reputation: 21
I'm wondering if there is a neater way of doing part 3 of my code? I am building a tic-tac-toe game for an assigment and this is the function for checking if there is a line of 3 of X's or O's. So I'm splitting the "board" list which represents the 3x3 gameboard into three lists that represent rows, columns and "corner to corner" lines.
def check_forwin(board,split_list):
#part 1 splice a single list into 3 lists
check_list1 = [tuple(board[i:j]) for i, j in zip([1]+ split_list, split_list)]
#part 2"invert" the list, as in choosing columns
check_list2 = list(zip(check_list1[0],check_list1[1],check_list1[2]))
#part 3 make 2 lists from "corner to corner"
check_list3 = [[],[]]
check_list3[0] = tuple([check_list1[0][0],check_list1[1][1],check_list1[2][2]])
check_list3[1] = tuple([check_list1[0][2],check_list1[1][1],check_list1[2][0]])
return
board = ["#","a","b","c","d","e","f","g","h","i"]
split_list1 = [4, 7, 10]
check_forwin(board,split_list1)
[('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i')]
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')]
[('a', 'e', 'i'), ('c', 'e', 'g')]
Upvotes: 2
Views: 205
Reputation: 2098
If all you want is convert a single list into list of lists, then you can use either of the methods below. However I read the instructions wrong and thought you wanted an entire game checker to be implemented. That is the answer I had posted earlier. Below dashed lines is an implementation of that. I have kept it but you may ignore the lines below "=====" if you are not interested.
Method 1 using base python
import math
def Convert_Into_SquareBoard_UsingBasePython(List):
List = List[1:]
return [ [List[i*int(math.sqrt(len(List)))+j] for j in range(3)] for i in range(0,int(math.sqrt(len(List))),1)]
This gives the following output.
[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
Method 2 using Numpy
def Convert_Into_SquareBoard_UsingNumpy(List):
return np.array(List[1:]).reshape(int(np.sqrt(len(List[1:]))),int(np.sqrt(len(List[1:])))).tolist()
This gives the same output as above
[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
======================================================================
Nice answers have already been posted. However, if numpy is allowed you can do it in another way. Basically you cast the list of lists in a numpy array and then check for Row, Column and Diagonal wins. As far as elegancy is concerned, I am not sure about that. Despite that I am still posting it to add another method for the solution.
import numpy as np
def Check_Win(a):
a = np.array(a)
##Get both diagonals
Diag_Array = np.array([a.diagonal(),np.flip(a,1).diagonal()])
##Check 1 for row win
if np.any(np.apply_along_axis(lambda x: len(set(x))==1, 1, a)):
return True
##Check 2 for column win
elif np.any(np.apply_along_axis(lambda x: len(set(x))==1, 0, a)):
return True
##Check 3 along diagonals
elif np.any(np.apply_along_axis(lambda x: len(set(x))==1, 1, Diag_Array)):
return True
return False
a_No_Win = [('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i')]
a_Row_Win = [('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'g', 'g')]
a_Column_Win = [('h', 'b', 'c'), ('h', 'e', 'f'), ('h', 'h', 'i')]
a_Diag_1_Win = [('a', 'b', 'c'), ('d', 'a', 'f'), ('g', 'h', 'a')]
a_Diag_2_Win = [('a', 'b', 'h'), ('d', 'h', 'f'), ('h', 'h', 'i')]
print(Check_Win(a_No_Win))
print(Check_Win(a_Row_Win))
print(Check_Win(a_Column_Win))
print(Check_Win(a_Diag_1_Win))
print(Check_Win(a_Diag_2_Win))
This gives the outputs as expected below.
False
True
True
True
True
Added lines below after realising that the input is a flat list and not a list of lists and the first element is the character to look out for
For above method to work you will have to first get the list of lists. Also it does not look for a specific character. As long as any character is present in a consecutive manner it will register a win. I think you are not looking for that.
I think you have a single list and the first element of the list is the character that you are looking for the win. All other characters you are ignoring. Below is the modified version of the above function. It has been changed slightly to "perhaps" suit your needs.
import numpy as np
def Check_Win(a):
CheckSymbol = a[0]
a = np.array(a[1:]).reshape(int(np.sqrt(len(a[1:]))),int(np.sqrt(len(a[1:]))))
##Get both diagonals
Diag_Array = np.array([a.diagonal(),np.flip(a,1).diagonal()])
##Check 1 for row win
if np.any(np.apply_along_axis(lambda x: list(x).count(CheckSymbol)==int(np.sqrt(len(a[1:]))), 1, a)):
return True
##Check 2 for column win
elif np.any(np.apply_along_axis(lambda x: list(x).count(CheckSymbol)==int(np.sqrt(len(a[1:]))), 0, a)):
return True
##Check 3 along diagonals
elif np.any(np.apply_along_axis(lambda x: list(x).count(CheckSymbol)==int(np.sqrt(len(a[1:]))), 1, Diag_Array)):
return True
return False
a_No_Win = ["#","a","b","c","d","e","f","g","h","i"]
a_Row_Win = ["#","a","b","c","d","e","f","#","#","#"]
a_Column_Win = ["#","#","b","c","#","e","f","#","h","i"]
a_Diag_1_Win = ["#","#","b","c","d","#","f","g","h","#"]
a_Diag_2_Win = ["#","a","b","#","d","#","f","#","h","i"]
print(Check_Win(a_No_Win))
print(Check_Win(a_Row_Win))
print(Check_Win(a_Column_Win))
print(Check_Win(a_Diag_1_Win))
print(Check_Win(a_Diag_2_Win))
The modified output is as below and is as expected.
False
True
True
True
True
Please let me know if this was of help.
Upvotes: 0
Reputation: 147
Interesting question, though "neat" is a very subjective concept... What you think about this?
def check_forwin(board, board_size):
#part 1 splice a single list into 3 lists
check_list1 = [tuple(board[i + j] for i in range(board_size)) for j in range(1, len(board), board_size)]
#part 2"invert" the list, as in choosing columns
check_list2 = [tuple(check_list1[i][j] for i in range(board_size)) for j in range(board_size)]
#part 3 make 2 lists from "corner to corner"
check_list3 = [tuple(check_list1[i][i] for i in range(board_size)), tuple(check_list2[i][board_size - 1 - i] for i in range(board_size - 1, -1, -1))]
return
board = ["#","a","b","c","d","e","f","g","h","i"]
check_forwin(board, 3)
Upvotes: 1
Reputation: 731
Using list comprehension makes it a bit neater, however, as Kalma, said "neat" is very subjective.
def check_forwin(board,split_list):
#part 1 splice a single list into 3 lists
check_list1 = [tuple(board[i:j]) for i, j in zip([1]+ split_list, split_list)]
#part 2"invert" the list, as in choosing columns
check_list2 = list(zip(check_list1[0],check_list1[1],check_list1[2]))
#part 3 make 2 lists from "corner to corner"
check_list3 = [[],[]]
# Number of element in row or column
n = len(check_list1)
check_list3[0] = tuple([check_list1[i][i] for i in range(n)])
check_list3[1] = tuple([check_list1[i][n-i-1] for i in range(n)])
return
Upvotes: 1