'more concise way to make this?

I'm unsure of how to create a certain section of my code without it being excessively long and tedious. Is there perhaps a way of utilizing a range function where I need my elif statements? Any help shortening this would be more than appreciated!

#just some sample lists
Player.PlayerList[1].carrier_row = [0,1,2,3,4]
Player.PlayerList[1].carrier_col = [5,5,5,5,5]

Player.PlayerList[1].battleship_row = [10,11,12,13]
Player.PlayerList[1].battleship_col = [15,15,15,15]

if Player.PlayerList[1].carrier_row[0] == column:
    if Player.PlayerList[1].carrier_col[0] == row:
        print('hit')
elif Player.PlayerList[1].carrier_row[1] == column:
    if Player.PlayerList[1].carrier_col[1] == row:
        print('hit')
elif Player.PlayerList[1].carrier_row[2] == column:
    if Player.PlayerList[1].carrier_col[2] == row:
        print('hit')
elif Player.PlayerList[1].carrier_row[3] == column:
    if Player.PlayerList[1].carrier_col[3] == row:
        print('hit')
elif Player.PlayerList[1].carrier_row[4] == column:
    if Player.PlayerList[1].carrier_col[4] == row:
        print('hit')

elif Player.PlayerList[1].battleship_row[0] == column:
    if Player.PlayerList[1].battleship_col[0] == row:
        print('hit')
elif Player.PlayerList[1].battleship_row[1] == column:
    if Player.PlayerList[1].battleship_col[1] == row:
        print('hit')
elif Player.PlayerList[1].battleship_row[2] == column:
    if Player.PlayerList[1].battleship_col[2] == row:
        print('hit')
elif Player.PlayerList[1].battleship_row[3] == column:
    if Player.PlayerList[1].battleship_col[3] == row:
        print('hit')

else:
print('miss')


Solution 1:[1]

To be honest, I think the data format is inappropriate. If you have the ability to change it, I would suggest redesigning your data model to deal with points instead of individual point coordinates (x, y), e.g.:

Player.PlayerList[1].carrier = [(0, 5), (1, 5), (2, 5), (3, 5), (4,5)]

Then your check on a hit can be as simple as:

def is_hit(row: int, column: int) -> bool:
    point = (row, column)
    return (point in Player.PlayerList[1].carrier 
            or point in Player.PlayerList[1].battleship)

EDIT: Assuming you're trying to build a battleship game, I would probably write a class Ship which manages one ship, and then use multiple of these, so something like:

class Point(NamedTuple):
    x: int
    y: int

class Ship(object):
    def __init__(self, points: List[Point]):
        self.points = points

    def check_hit(self, point: Point) -> bool:
        return point in self.points

The benefit of that is that you can now start adding logic to the Ship easily, for example by adding a .hits attribute as well that allows you to keep track of the ship health.

A player could then simply have a list of ships:

Player.PlayerList[1].ships = [
    Ship([Point(0, 5), Point(1, 5), Point(2, 5), Point(3, 5), Point(4,5)],
    Ship(...),
    ...
]

Solution 2:[2]

You can do this in a loop to look all the possibility without having to write them all:

Player.PlayerList[1].carrier_row = [0,1,2,3,4]
Player.PlayerList[1].carrier_col = [5,5,5,5,5]

Player.PlayerList[1].battleship_row = [10,11,12,13]
Player.PlayerList[1].battleship_col = [15,15,15,15]

hit = False 

for i in range(len(Player.PlayerList[1].carrier_row)):
    if Player.PlayerList[1].carrier_row[i] == row and Player.PlayerList[1].carrier_col == column:
        print("hit")
        hit = True

for i in range(len(Player.PlayerList[1].battleship_row)):
    if Player.PlayerList[1].battleship_row[i] == row and Player.PlayerList[1].battleship_col == column:
        print("hit")
        hit = True

if not hit:
    print("miss")

Solution 3:[3]

This is more concise but untested as the values for row and column and the class definitions are unknown :

Player.PlayerList[1].carrier_row = [0,1,2,3,4]
Player.PlayerList[1].carrier_col = [5,5,5,5,5]

Player.PlayerList[1].battleship_row = [10,11,12,13]
Player.PlayerList[1].battleship_col = [15,15,15,15]

pli = Player.PlayerList[1]

for cr, cc, br, bc in zip(pli.carrier_row, pli.carrier_col, pli.battleship_row, pli.battleship_col):
    if row in (cr, br) or column in (cc, bc):
        hit = True
        break
else:
    hit = False

print('hit' if hit else 'miss')

Solution 4:[4]

Each check is done against a fix value, column & row, so one can compare them individually and them zip them. The nested condition is performed with an and. Used itertools to keep the code compact

import itertools as it

column = # some number
row = #    some number


cc_cols = map(column.__eq__, Player.PlayerList[1].carrier_row)
cc_rows = map(row.__eq__, Player.PlayerList[1].carrier_row)

bship_cols = map(column.__eq__, Player.PlayerList[1].battleship_row)
bship_rows = map(row.__eq__, Player.PlayerList[1].battleship_row)

if any(it.starmap(bool.__and__, it.chain(zip(cc_cols, cc_rows), zip(bship_cols, bship_rows)))):
    print('hit')
else:
    print('miss')

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Xiidref
Solution 3 Albert Winestein
Solution 4 cards