Рандомизирующий список списков без перекрытия

#python #2d-games

#python #2d-игры

Вопрос:

Я создаю функцию, которая рандомизирует игровое поле (представленное списком из десяти списков по десять) для игры battleship. в настоящее время моя функция выполняет случайное размещение чисел на доске, представляющих корабли. Моя функция также гарантирует, что корабли не зацикливаются на краю доски и не появляются на другой стороне, а также случайным образом генерирует ориентацию кораблей. однако моей функции не удается добиться того, чтобы «корабли» не накладывались друг на друга. У меня возникли проблемы с поиском решения, хотя я уверен, что оно довольно простое. есть ли способ достичь моей цели?

 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])
  

Пример вывода:

 [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]
  

Вывод с перекрытием (пять кораблей покрываются тремя кораблями):

 [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]
  

Комментарии:

1. можете ли вы привести пример вывода для платы размером 4 * 4?

2. Возможно, включите комментарии в свой код, чтобы люди могли лучше его понять. По крайней мере, объясните, что такое a, p, o и r. Или еще лучше — используйте описательные имена переменных

3. Что вы подразумеваете под «перекрывающимися» кораблями?

4. Перед размещением корабля проверьте каждое целевое поле, есть ли уже корабль. Если это так, повторите попытку с новой случайной позицией.

Ответ №1:

Рискуя чрезмерно усложнить ситуацию, я предлагаю объектно-ориентированный подход. Можно изменить ваш метод, но я нахожу, что он быстро запутывается.

В place функции мы собираем список locations для размещения, чтобы сделать корабль. Затем мы проверяем, есть ли там уже какой-либо корабль grid[y][x] != 0 . Если это так, нам нужно повторно generate использовать случайные значения для положения и поворота, тогда мы можем попробовать place еще раз.

 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', ' '))

  

Дайте мне знать, если у вас возникнут какие-либо вопросы о коде.