Лучшее размещение элементов в массиве - PullRequest
0 голосов
/ 27 октября 2019

Я создаю игрового бота для линкора для сервера Discord. Я еще не выполнил часть разногласий, но я закончил вводную часть человека здесь .

Теперь я делаю бота, который поместит каждый корабль на воду, который представляет собой массив кусков. ,

Это код для бота.

import re
import numpy as np
import random

water_text = 'WW'

waters = np.full((10, 10), water_text, 'U2')
headers = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']

ship_type = [
    ["CV", "Carrier", 5],
    ["BB", "Battleship", 4],
    ["CA", "Cruiser", 3],
    ["SS", "Submarine", 3],
    ["DD", "Destroyer", 2],
]

board_x_coord = {
    "a": 0,
    "b": 1,
    "c": 2,
    "d": 3,
    "e": 4,
    "f": 5,
    "g": 6,
    "h": 7,
    "i": 8,
    "j": 9
}

possible_neighbor_count = 1


def printBoard():
    for i, header in enumerate(headers):
        if i == 0:
            print('    ', end='')
        print(header + '  ', end='')
        if i == len(headers)-1:
            print()

    for x, line in enumerate(waters):
        print('%2d' % (x), end='')
        [print(' '+pos, end='') for pos in line]
        print()


def collision_detect(selected_waters):
    if any(water != water_text for water in selected_waters):
        return True
    return False


def neighbor_counter(a, b):
    dist = 1
    return sum([y != water_text for w in [row[max(0, a-dist):a+dist+1] for row in waters[max(0, b-1):b+dist+1]] for y in w])-1


def neighbor_test(x, y, size, orientation):
    if orientation == 'H':
        neighbor_count = 0
        for i in range(size):
            x += i
            neighbor_count += neighbor_counter(x, y)
        return neighbor_count

    elif orientation == 'V':
        neighbor_count = 0
        for i in range(size):
            y += i
            neighbor_count += neighbor_counter(x, y)
        return neighbor_count


def no_neighbors(possible, size, orientation):
    neighbor_grades = []
    for nx,ny in possible:
        grade = neighbor_test(nx, ny, size, orientation)
        neighbor_grades.append((grade, (nx,ny)))
    return [y for x, y in neighbor_grades if x < possible_neighbor_count]


def get_available_waters():
    availables = []
    for y_pos, row in enumerate(waters):
        for x_pos, water in enumerate(row):
            if water == water_text:
                availables.append((x_pos, y_pos))
    return availables


def place_ship(ship):
    size = ship[2]
    orientation = random.choice(['H', 'V'])
    if orientation == 'H':
        possible = []
        for x, y in get_available_waters():
            selected_waters = waters[y, x:size+x]
            if len(selected_waters) == size:
                if not collision_detect(selected_waters):
                    possible.append((x, y))
        result = random.choice(no_neighbors(possible, size, orientation))
        px, py = result
        waters[py, px:size+px] = ship[0]

    elif orientation == 'V':
        possible = []
        for x, y in get_available_waters():
            selected_waters = waters[y:size+y:, x]
            if len(selected_waters) == size:
                if not collision_detect(selected_waters):
                    possible.append((x, y))
        result = random.choice(no_neighbors(possible, size, orientation))
        px, py = result
        waters[py:size+py:, px] = ship[0]


for ship in ship_type:
    place_ship(ship)

printBoard()
#print(waters)

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

    A  B  C  D  E  F  G  H  I  J
 0 WW WW WW WW WW WW WW WW WW WW
 1 WW WW CA CA CA WW WW WW WW WW
 2 WW WW WW WW WW WW WW WW WW WW
 3 WW WW WW WW WW WW WW WW WW WW
 4 WW WW WW CV WW WW WW SS WW WW
 5 WW WW BB CV WW WW WW SS WW WW
 6 WW WW BB CV WW WW WW SS WW WW
 7 WW WW BB CV WW WW WW WW WW WW
 8 WW WW BB CV WW DD DD WW WW WW
 9 WW WW WW WW WW WW WW WW WW WW

Приведенный выше код будет:

  1. Получить корабль из списка.
  2. Выбрать ориентацию
  3. Получить неиспользуемые позиции.
  4. Проверьте, возможна ли каждая неиспользованная позиция для размещения корабля.
  5. Разместите корабль.

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

Редактировать: Добавлена ​​сырая проверка соседей.
Теперь я проверяю каждую возможную позицию для соседей enter image description here

1 Ответ

1 голос
/ 27 октября 2019

Вы можете посмотреть на подраздел доски и сосчитать соседей, вместо того чтобы проверять каждый квадрат отдельно.

Вот более короткий способ проверить количество соседей:

def neighbor_counter(a, b):
    x1, x2 = max(a-1, 0), min(a+2, 10)
    y1, y2 = max(b-1, 0), min(b+2, 10)
    return len([i for i in waters[y1:y2,x1:x2].flatten() if i != water_text])

Однако,Вы можете реализовать функцию neighbor_test без использования neighbor_counter:

def neighbor_test(x, y, size, orientation):
    x1, y1 = max(x-1, 0), max(y-1, 0)
    x2, y2 = (min(x+size+1, 10), min(y+2, 10)) if orientation == "h" else (min(x+2, 10), min(y+size+1, 10))
    return len([i for i in waters[y1:y2,x1:x2].flatten() if i != water_text])

Или даже лучше, вы можете реализовать функцию no_neighbors без использования neighbor_test:

def no_neighbors(possible,size,orientation):
    empty_spots=[]
    for x, y in possible:
        x1, y1 = max(x-1, 0), max(y-1, 0)
        x2, y2 = (min(x+size+1, 10), min(y+2, 10)) if orientation == "h" else (min(x+2, 10), min(y+size+1, 10))
        if all([i==water_text for i in waters[y1:y2,x1:x2].flatten()]):
            empty_spots.append(nei)
    return empty_spots

Обратите внимание, что в вашей функции корабли в верхнем ряду могут быть соседями с кораблями в нижнем ряду. То же самое верно для левого и правого столбцов. Я предполагаю, что это не предназначено, и моя функция не рассматривает эти местоположения как соседей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...