简体   繁体   中英

Easier way to check for four in row/column/diagonal in connect four game?

I am making a connect four game with X's and O's. The code for checking for four in a row/column/diagonal works but I have a lot of if statements in my code. The game fully works right now but I'm wondering if there is an easier solution to the checking. Below, I have included all my code for context.

I have tried using coordinates. It seems kind of inefficient though. The function for checking is called check.

namex = input("Player X, enter your name. ") #asks for player 1 name
nameo = input("Player O, enter your name. ") #asks for player 2 name

game = [[".", ".", ".", ".", ".", "."], #gameboard
    [".", ".", ".", ".", ".", "."], 
    [".", ".", ".", ".", ".", "."], 
    [".", ".", ".", ".", ".", "."], 
    [".", ".", ".", ".", ".", "."], 
    [".", ".", ".", ".", ".", "."], 
    [".", ".", ".", ".", ".", "."]]

loop = True
def output(matrix):
    str1 = ""
    str2 = ""
    str3 = ""
    str4 = ""
    str5 = ""
    str6 = ""
    print("0 1 2 3 4 5 6 ") #print labels for columns in gameboard
    for a in matrix:
        row = 0
        for b in a: #"a" is a column and "b" is a ./x/o
            row += 1
            if row == 1:
                str1 += b
                str1 += " "
            if row == 2:
                str2 += b
                str2 += " "
            if row == 3:
                str3 += b
                str3 += " "
            if row == 4:
                str4 += b
                str4 += " "
            if row == 5:
                str5 += b
                str5 += " "
            if row == 6:
                str6 += b
                str6 += " "
    print(str1) #print string for row 1
    print(str2) #print string for row 2
    print(str3) #print string for row 3
    print(str4) #print string for row 4
    print(str5) #print string for row 5
    print(str6) #print string for row 6

def check(matrix): #function to check for four in row/column/diagonal to win
    positionx = []
    positiono = []
    x = 0
    for a in matrix:
        y = 5
        for b in a:
            if b == "X":
                positionx.append([x, y])
            if b == "O":
                positiono.append([x, y])
            y -= 1
        x += 1

    for c1 in positionx: 
        '''check four in row/column/diagonal for x'''
        for c2 in positionx:
            for c3 in positionx:
                for c4 in positionx: 
                    if c4[0]-c3[0] == 1:#check for four in row
                        if c3[0]-c2[0] == 1:
                            if c2[0]-c1[0] == 1:
                                return "xwin"
                    if c4[1]-c3[1] == 1: #check for four in column
                        if c3[1]-c2[1] == 1:
                            if c2[1]-c1[1] == 1:
                                return "xwin"
                    if c4[0]-c3[0] == 1: #check four in diagonal
                        if c4[1]-c3[1] == 1:
                            if c3[0]-c2[0] == 1:
                                if c3[1]-c2[1] == 1:
                                    if c2[0]-c1[0] == 1:
                                        if c2[1]-c1[1] == 1:
                                            return "xwin"                       
    for d1 in positiono:
        '''check four in row/column/diagonal for o'''
        for d2 in positiono:
            for d3 in positiono:
                for d4 in positiono: 
                    if d4[0]-d3[0] == 1: #check for four in row
                        if d3[0]-d2[0] == 1:
                            if d2[0]-d1[0] == 1:
                                return "owin"
                    if d4[1]-d3[1] == 1: #check for four in column
                        if d3[1]-d2[1] == 1:
                            if d2[1]-d1[1] == 1:
                                return "owin"
                    if d4[0]-d3[0] == 1: #check four in diagonal
                        if d4[1]-d3[1] == 1:
                            if d3[0]-d2[0] == 1:
                                if d3[1]-d2[1] == 1:
                                    if d2[0]-d1[0] == 1:
                                        if d2[1]-d1[1] == 1:
                                            return "owin"
while loop == True:

xinput = input(namex + ", you're X. What column do you want to play in? Please enter a number 0-6 ")
xcolumn = int(xinput)
xrow = 5
occupied1 = False
while occupied1 == False:
    if game[xcolumn][xrow] == ".": #if there is a "." change to "X"
        game[xcolumn][xrow] = "X"
        output(game)
        occupied1 = True
    xrow -= 1
if check(game) == "xwin":
    loop = False
    print(namex + " wins!")
    break
if check(game) == "owin":
    loop = False
    print(nameo + " wins!")
    break
oinput = input(nameo + ", you're O. What column do you want to play in? Please enter number 0-6 ")
ocolumn = int(oinput)
orow = 5
occupied2 = False
while occupied2 == False:
    if game[ocolumn][orow] == ".": #if there is a "." change to "O"
        game[ocolumn][orow] = "O"
        output(game)
        occupied2 = True
    orow -= 1
if check(game) == "xwin":
    loop = False
    print(namex + " wins!")
    break
if check(game) == "owin":
    loop = False
    print(nameo + " wins!")
    break

I'm also open to any other suggestions to make my code for this game better. Thanks!

A good start would be to write a generalized function that checks for a diagonal at an arbitrary location:

def diagonal(grid, x, y, piece):
    '''
    Return True if grid contains a four-in-a-row diagonal starting at coordinates
    (x, y) and traveling downwards and to the right.  Otherwise return False.
    '''

    for i in range(x, x+4):
        # if this square does not contain the desired piece, return False
        if grid[x+i][y+i] != piece
            return False
    # if we got all the way through the loop, this must be a diagonal
    return True

Then you would call this function for every possible starting coordinate of a four square diagonal, for each player X and O.

To improve this function, you could add a way to check for diagonals that travel the other direction (up and to the right).

I had some spare time, so I rewrote your program. It's much more efficient now. Read the comments to understand how it works

cols = [[] for x in range(6)]
# I opted to have a matrix of COLUMNS rather than rows because you can easily
# append items to the end of the list to simulate a real tile being placed there
# it's more intuitive and saves us time, as you'll see


def checkWin(cols):
    for i in range(6): # Each column
        for j in range(6): # Each row
            try: #check if the element at these coordinates exists yet
                cols[i][j]
            except IndexError:
                break
                # go back to next i - impossible that there's anything with a higher
                # j because if a list is n items long, and we go to j (which is one
                # higher than n and doesn't exist) then there can't be an element at
                # index j + someNumber.
            ret = False
            try: #vertical: j is the index in each column, so this goes up the column
                if cols[i][j] == cols[i][j+1] == cols[i][j+2] == cols[i][j+3] is not None:
                    ret = True
            except IndexError: #one of the elements of the comparison doesn't exist
                pass #We can't be sure that none of the other trials will return True
            try: #horizontal
                if cols[i][j] == cols[i+1][j] == cols[i+2][j] == cols[i+3][j] is not None:
                    ret = True
            except IndexError:
                pass
            try: #diagonal
                if cols[i][j] == cols[i+1][j+1] == cols[i+2][j+2] == cols[i+3][j+3] is not None:
                    ret = True
            except IndexError:
                pass
            try: #other diagonal
                if cols[i][j] == cols[i-1][j+1] == cols[i-2][j+2] == cols[i-3][j+3] is not None:
                    ret = True
            except IndexError:
                pass
            if ret:
                return cols[i][j]
    return None # We've gone through every single possible element and there are NO matches
def printBoard(cols):
    # Pretty intuitive function IMO - we swap i and j to go through rows.
    returnstr = '\n1 2 3 4 5 6\n'
    for i in range(6):
        for j in range(6):
            try:
                cols[j][5-i]
            except IndexError:
                returnstr += '_ '
                continue
            returnstr += cols[j][5-i]+' '
        returnstr += '\n'
    print(returnstr)
playerX = input('Player X, input your name: ')
playerO = input('Player O, input your name: ')
if playerX == playerO:
    print("Cannot have the same name!")
    exit()
count = 0
while not checkWin(cols):
    printBoard(cols)
    i = input('{}, input your column (1-6): '.format(playerO if count else playerX))
    try:
        target = cols[int(i)-1]
        if len(target) == 6:
            print("Column {} is already full! Please pick another.".format(i))
            continue
        target.append('O' if count else 'X')
    except ValueError:
        print("'{}' is not a number! Try again.".format(i))
        continue
    except IndexError:
        print("{} is not a valid column number! Please pick another.".format(i))
        continue
    count = (count+1) % 2
printBoard(cols)
if checkWin(cols) == 'X':
    print('{} (Player X), you win!'.format(playerX))
else:
    print('{} (Player O), you win!'.format(playerO))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM