4
\$\begingroup\$

The goal of the code below is limited to the creation of the initial map only and not to the whole game mechanics itself.

The rules are that there are 4 ships of length {2,3,4,5} and no ship may be placed adjacent or diagonally adjacent to another ship.

For now I plan to stay with the 10x10 grid with 4 ships. In my implementation, a 1 means that there is ship in that cell, and 0 otherwise.

I am not a Python developer, but since I am interested in learning it I decided to program this project using this language. Please scrutinize, nitpick my code. I want to get into the so called pythonic way.

This is the code for now (According to my tests, I think it is working as intended):

import numpy as np
import random

grid_x = 10
grid_y = 10
number_of_ships = 4

class Ship:
    def __init__(self, x, y, direction, length):
        self.x = x
        self.y = y
        self.direction = direction
        self.length = length
    def generate_random_ship(self, rows, columns, length):
        self.x = random.randrange(rows)
        self.y = random.randrange(columns)
        self.direction = random.randrange(4)
        self.length = length
    def print_ship(self):
        print('x: %d, y: %d, direction: %d, length: %d' %(self.x,self.y,self.direction,self.length))

class Grid:
    def __init__(self, rows, columns):
        self.rows = rows
        self.columns = columns
        self.grid = np.zeros((rows, columns))

    #Assume ship is already valid
    def place_ship(self,ship):
        for i in range(ship.length):
            if ship.direction == 0: #up
                self.grid[ship.x - i][ship.y] = 1
            elif ship.direction == 1: #right
                self.grid[ship.x][ship.y + i] = 1
            elif ship.direction == 2: #down
                self.grid[ship.x + i][ship.y] = 1
            elif ship.direction == 3: #left
                self.grid[ship.x][ship.y - i] = 1
    def check_for_ship(self, x, y):
        if x >= self.rows or x < 0 or y >= self.columns or y < 0:
            return False
        elif self.grid[x][y] == 1:
            return True
        else:
            return False
    def is_ship_valid(self, ship):
        #up
        if ship.direction == 0:
            #if the ship won't fit
            if ship.length > (ship.x + 1):
                return False
            else:
                #Check for ships in the neighborhood
                for i in range(ship.x, ship.x-ship.length, -1):
                    if (self.check_for_ship(i+1, ship.y-1) or self.check_for_ship(i+1, ship.y)
                                or self.check_for_ship(i+1, ship.y+1) or self.check_for_ship(i, ship.y-1)
                                or self.check_for_ship(i, ship.y) or self.check_for_ship(i, ship.y+1)
                                or self.check_for_ship(i-1, ship.y-1) or self.check_for_ship(i-1, ship.y)
                                or self.check_for_ship(i-1, ship.y+1)):
                                    return False
        #right
        elif ship.direction == 1:
            #if the ship won't fit
            if ship.length > (self.columns - ship.y):
                    return False
            else:
                #Check for ships in the neighborhood
                for i in range(ship.y, ship.y+ship.length):
                    if (self.check_for_ship(ship.x-1, i-1) or self.check_for_ship(ship.x, i-1)
                                or self.check_for_ship(ship.x+1, i-1) or self.check_for_ship(ship.x-1, i)
                                or self.check_for_ship(ship.x, i) or self.check_for_ship(ship.x+1, i)
                                or self.check_for_ship(ship.x-1, i+1) or self.check_for_ship(ship.x, i+1)
                                or self.check_for_ship(ship.x+1, i+1)):
                                    return False
        #down
        elif ship.direction == 2:
            if ship.length > (self.rows - ship.x):
                return False
            else:
                #Check for ships in the neighborhood
                for i in range(ship.x, ship.length+ship.x):
                    if (self.check_for_ship(i+1, ship.y-1) or self.check_for_ship(i+1, ship.y)
                                or self.check_for_ship(i+1, ship.y+1) or self.check_for_ship(i, ship.y-1)
                                or self.check_for_ship(i, ship.y) or self.check_for_ship(i, ship.y+1)
                                or self.check_for_ship(i-1, ship.y-1) or self.check_for_ship(i-1, ship.y)
                                or self.check_for_ship(i-1, ship.y+1)):
                                    return False
        #left
        elif ship.direction == 3:
            if ship.length > (ship.y+1):
                return False
            else:
                #Check for ships in the neighborhood
                for i in range(ship.y, ship.y-ship.length, -1):
                    if (self.check_for_ship(ship.x-1, i-1) or self.check_for_ship(ship.x, i-1)
                                or self.check_for_ship(ship.x+1, i-1) or self.check_for_ship(ship.x-1, i)
                                or self.check_for_ship(ship.x, i) or self.check_for_ship(ship.x+1, i)
                                or self.check_for_ship(ship.x-1, i+1) or self.check_for_ship(ship.x, i+1)
                                or self.check_for_ship(ship.x+1, i+1)):
                                    return False
        return True

battlefield = Grid(grid_x, grid_y)

ships = []
ship_length = 2
for _ in range(number_of_ships):
    ship = Ship(random.randrange(grid_x), random.randrange(grid_y),
                random.randrange(4), ship_length)
    ships.append(ship)
    ship_length += 1
for ship in ships:
    valid_ship = battlefield.is_ship_valid(ship)
    if valid_ship:
        battlefield.place_ship(ship)
    else:
        while valid_ship == False:
            ship.generate_random_ship(grid_x, grid_y, ship.length)
            valid_ship = battlefield.is_ship_valid(ship)
        battlefield.place_ship(ship)
print(battlefield.grid)
print()
for ship in ships:
    ship.print_ship()
\$\endgroup\$
  • 2
    \$\begingroup\$ @close-voter stating future plans doesn't make something 'not working as intended'. Given that they've tested the code too, it's harder to make a case that this is broken, as you've likely found an edgecase. \$\endgroup\$ – Peilonrayz May 15 at 21:03
  • \$\begingroup\$ Edited the post a little bit to explicit my intentions with the given code. \$\endgroup\$ – ihavenoidea May 15 at 21:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.