Home > Blockchain >  Python: How can I reduce the number of 'if' statements down to a reasonable amount for my
Python: How can I reduce the number of 'if' statements down to a reasonable amount for my

Time:11-28

Im making a chess game in python and was trying to generate the legal moves of each piece using 'if' statements to see if the space the player wants to move to is free and if the move is actually within the borders of the board. The problem is that there are too many 'if' statements as well as nested 'if' statements. This really makes my file look like spaghetti code and over-complicates the process.

Here is an example:

def valid_moves(self, board):
    i = self.row
    j = self.col

    moves = []

    if i > 0:
        # TOP LEFT
        if j > 0:
            p = board[i - 1][j - 1]
            if p == 0: # checks if space empty
                moves.append((j - 1, i - 1,))
            elif p.color != self.color:
                moves.append((j - 1, i - 1,))

        # TOP MIDDLE
        p = board[i - 1][j]
        if p == 0: # checks if space empty
            moves.append((j, i - 1))
        elif p.color != self.color:
            moves.append((j, i - 1))

        # TOP RIGHT
        if j < 7:
            p = board[i - 1][j   1]
            if p == 0: # checks if space empty
                moves.append((j   1, i - 1,))
            elif p.color != self.color:
                moves.append((j   1, i - 1,))

    if i < 7:
        # BOTTOM LEFT
        if j > 0:
            p = board[i   1][j - 1]
            if p == 0: # checks if space empty
                moves.append((j - 1, i   1,))
            elif p.color != self.color:
                moves.append((j - 1, i   1,))

        # BOTTOM MIDDLE
        p = board[i   1][j]
        if p == 0: # checks if space empty
            moves.append((j, i   1))
        elif p.color != self.color:
            moves.append((j, i   1))

        # BOTTOM RIGHT
        if j < 7:
            p = board[i   1][j   1]
            if p == 0: # checks if space empty
                moves.append((j   1, i   1))
            elif p.color != self.color:
                moves.append((j   1, i   1))

    # MIDDLE LEFT
    if j > 0:
        p = board[i][j - 1]
        if p == 0: # checks if space empty
            moves.append((j - 1, i))
        elif p.color != self.color:
            moves.append((j - 1, i))

    # MIDDLE RIGHT
    if j < 7:
        p = board[i][j   1]
        if p == 0: # checks if space empty
            moves.append((j   1, i))
        elif p.color != self.color:
            moves.append((j   1, i))

    return moves

This example is for just 1 piece out of 6 and so there is a lot of occurring 'if' statements. How can I refractor this to where I don't need to use as many 'if' statements?

CodePudding user response:

A local function helps to avoid code duplicates:

def valid_moves(self, board):
    i = self.row
    j = self.col

    moves = []

    def move(a: int, b: int) -> None:
        p = board[a][b]
        if p == 0 or p.color != self.color:
            moves.append((b, a))

    if i > 0:
        # TOP LEFT
        if j > 0:
            move(i - 1, j - 1)

        # TOP MIDDLE
        move(i - 1, j)

        # TOP RIGHT
        if j < 7:
            move(i - 1, j   1)

    if i < 7:
        # BOTTOM LEFT
        if j > 0:
            move(i   1, j - 1)

        # BOTTOM MIDDLE
        move(i   1, j)

        # BOTTOM RIGHT
        if j < 7:
            move(i   1, j   1)

    # MIDDLE LEFT
    if j > 0:
        move(i, j - 1)

    # MIDDLE RIGHT
    if j < 7:
        move(i, j   1)

    return moves

CodePudding user response:

First generate all possible moves, including illegal ones. Then filter the illegal ones. Also you check whether i > 0 or i < 7, I think you meant i >= 0 and i < 8 if you're using zero-based indexing for an 8x8 chess board.

def valid_moves(self, board):
    i = self.row
    j = self.col

    destinations = [
        (j   dj, i   di)
        for di [-1, 0, 1] for dj in [-1, 0, 1]
        # Disallow staying in place - not a move.
        if not (di == 0 and dj == 0)
    ]

    legal_moves = [
        (mj, mi)
        for mj, mi in destinations
        # In bounds.
        if 0 <= mi < 8 and 0 <= mj < 8
        # And empty or enemy occupied.
        and (board[mi][mj] == 0 or board[mi][mj].color != self.color)
    ]

    return legal_moves

CodePudding user response:

You seem to only be looking for a one space move so it could be simplified by looping on the vertical and horizontal deltas of each direction:

def valid_moves(self, board):
    moves = []
    for v,h in [(-1,-1),(0,-1),(0,1),(-1,0),(1,0),(1,1)]: # directions
        r,c = self.row v,self.col h       # advance by 1
        if r not in range(8): continue    # vertical bounds
        if c not in range(8): continue    # horizontal bounds
        p = board[r][c]
        if p==0 or p.color != self.color:  # playable position
            moves.append((r,c))
    return moves

This isn't going to cover multi-step moves and non-linear moves. There is a strategy for all types of moves here.

  • Related