TransWikia.com

Randomizing list of lists without overlap

Stack Overflow Asked on January 4, 2021

I’m making a function that randomizes a gameboard (represented by a list of ten lists of ten) for the game battleship. what my function does currently is randomly place numbers on the board representing ships. My function also makes sure that the ships don’t loop around the edge of the board and appear on the other side, as well as randomly generating the orientation of the ships. what my function fails to achieve however is making sure that the "ships" don’t overlap onto each other. I’ve been having trouble coming up with a solution, though I’m sure its a pretty simple one. is there a way to achieve my goal?

import random
l = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

for a in range(1, 5):
    p = random.randrange(0, 10, 1)
    o = random.randrange(0, 10, 1)
    #the p and o variables determine the coordinates of the starting point
    r = random.randrange(1, 3)
    #the r variable randomizes orientation of the ship
    if r == 1:
        for n in range(1, 7 - a):
            #the function uses the length of the ship to determine whether or not 
            #the ship will go off the end of the board
            if o < 6 - a:
                l[p][(6 - a) - n] = 6 - a
            else:
                l[p][o-n] = 6 - a
    else:
        for e in range(1, 7 - a):

            if p < 6-a:
                l[(6-a) - e][o] = 6-a
            else:
                l[p - e][o] = 6-a
for v in range(0, len(l)):
    print(l[v])

Output example:

[0, 3, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 3, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 3, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 4, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 4, 0, 0, 5, 5, 5, 5, 5, 0]
[0, 4, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 4, 0, 0, 0, 0, 0, 0, 2, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 2, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Output with overlap (the five ship is covered by the three ship):

[0, 0, 0, 0, 5, 5, 5, 5, 3, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 3, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 3, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[2, 2, 0, 0, 0, 0, 0, 0, 0, 0]
[4, 4, 4, 4, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

One Answer

At the risk of over-complicating things, I suggest an object oriented approach. It is possible to modify your method, but I find it gets messy fast.

In the place function, we assemble a list of locations to place in order to make the ship. We then check if there is any ship already located there grid[y][x] != 0. If so, we need to re-generate random values for the position and rotation, then we can try to place again.

import random

GRID_WIDTH, GRID_HEIGHT = 10, 10  # constants representing width and height of the board
grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]  # generate a 10x10 grid of 0's


class Ship:
    def __init__(self, length):
        self.length = length
        self.x, self.y, self.horizontal = None, None, None
        self.generate()

    def generate(self):  # randomize position and rotation
        self.x = random.randint(0, GRID_WIDTH-self.length)
        self.y = random.randint(0, GRID_HEIGHT-self.length)
        self.horizontal = random.choice([True, False])
        self.place()

    def place(self):  # place ship on the grid
        locations = []
        if self.horizontal:
            for x in range(self.x, self.x+self.length):
                locations.append((x, self.y))
        else:  # if vertical
            for y in range(self.y, self.y+self.length):
                locations.append((self.x, y))
        for x, y in locations:
            if grid[y][x] != 0:  # if occupied, regenerate whole ship
                self.generate()
                return
        for x, y in locations:  # actually place ship now
            grid[y][x] = self.length


ships = []
for ship_length in range(2, 6):
    ships.append(Ship(ship_length))

for row in grid:  # print the board
    print(row)

# for row in grid:  # print the board without 0's
#     print(str(row).replace('0', ' '))

Let me know if you have any questions about the code.

Correct answer by mazore on January 4, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP