Iiro Soikkeli
Iiro Soikkeli

Reputation: 21

Is there a neater way to build this list? Python 3

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

Answers (3)

Amit
Amit

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

Kalma
Kalma

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

Yacine Mahdid
Yacine Mahdid

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

Related Questions