battleship/battleship.py

246 lines
6.4 KiB
Python
Raw Normal View History

2015-10-29 16:04:25 +00:00
from enum import Enum
2015-10-30 08:15:53 +00:00
import colorama
from colorama import Fore, Back, Style
2015-10-29 16:04:25 +00:00
class FieldType(Enum):
empty = 1
water = 2
ship = 3
2015-10-30 15:36:06 +00:00
class ShipOrientation(Enum):
unknown = 0
none = 1
north = 2
south = 3
east = 4
west = 5
both = 6
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
class Field(object):
def __init__(self):
self.__fixed = False
self.__type = FieldType.empty
self.__marked_type = FieldType.empty
self.__orientation = ShipOrientation.none
2015-10-29 16:04:25 +00:00
2015-10-30 08:16:24 +00:00
@property
def marked_type(self):
2015-10-30 15:36:06 +00:00
return self.__type if self.__fixed else self.__marked_type
2015-10-30 08:16:24 +00:00
2015-10-30 15:36:06 +00:00
def set_fixed(self, typ=None, orientation=ShipOrientation.unknown):
self.__fixed = True
if typ is not None:
self.__type = typ
self.__marked_type = typ
self.__orientation = orientation
def __str__(self):
typ = self.__type if self.__fixed else self.__marked_type
if typ == FieldType.empty:
return ' '
elif typ == FieldType.water:
return '~~'
elif typ == FieldType.ship:
if self.__orientation == ShipOrientation.unknown:
return '??'
elif self.__orientation == ShipOrientation.none:
return '<>'
elif self.__orientation == ShipOrientation.north:
return '^^'
elif self.__orientation == ShipOrientation.south:
return 'vv'
elif self.__orientation == ShipOrientation.west:
return ' <'
elif self.__orientation == ShipOrientation.east:
return '> '
elif self.__orientation == ShipOrientation.both:
return 'XX'
def set_type(self, typ, orientation=ShipOrientation.unknown):
self.__type = typ
self.__orientation = orientation
2015-10-29 16:04:25 +00:00
class Table(object):
def __init__(self, width, height):
self.__fields = []
2015-10-30 15:36:06 +00:00
self.__width = width
self.__height = height
self.__col_counts = []
self.__row_counts = []
self.__ships = []
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
for count in range(0, height):
2015-10-29 16:04:25 +00:00
self.__fields.append([])
2015-10-30 15:36:06 +00:00
self.__row_counts.append(0)
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
for count in range(0, width):
self.__col_counts.append(0)
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
for row in range(0, height):
self.__fields[row].append(Field())
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
self.clean()
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
@property
def width(self):
return self.__width
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
@property
def height(self):
return self.__height
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
def __check_height(self, row):
if row not in range(0, self.__height):
raise IndexError("Invalid row number")
2015-10-30 08:15:53 +00:00
2015-10-30 15:36:06 +00:00
def __check_width(self, col):
if col not in range(0, self.__width):
raise IndexError("Invalid column number")
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
def row(self, row):
self.__check_height(row)
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
# TODO: This doesnt feel right
return self.__fields[row]
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
def col(self, col):
self.__check_width(col)
2015-10-30 08:15:53 +00:00
2015-10-30 15:36:06 +00:00
# TODO: This doesnt feel right
return [f[col] for f in f.__fields]
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
def clean(self):
for row in self.__fields:
for field in row:
field.hidden_type = FieldType.water
field.player_type = FieldType.empty
field.fixed = False
2015-10-29 16:04:25 +00:00
2015-10-30 15:36:06 +00:00
def __check_collision(self, parts):
pass
2015-10-29 16:04:25 +00:00
def add_ship(self, start_row, start_col, length, vertical):
row, col = start_row - 1, start_col - 1
2015-10-30 15:36:06 +00:00
parts = []
2015-10-29 16:04:25 +00:00
for i in range(0, length):
2015-10-30 15:36:06 +00:00
parts.append((row, col))
2015-10-29 16:04:25 +00:00
if vertical:
row += 1
else:
col += 1
2015-10-30 15:36:06 +00:00
count = 0
for row, col in parts:
count += 1
orientation = ShipOrientation.unknown
if length == 1:
orientation=ShipOrientation.none
else:
if count == 1:
orientation = ShipOrientation.north if vertical \
else ShipOrientation.west
elif count == length:
orientation = ShipOrientation.south if vertical \
else ShipOrientation.east
else:
orientation = ShipOrientation.both
self.__fields[row][col].set_type(FieldType.ship,
orientation=orientation)
2015-10-29 16:04:25 +00:00
def reveal(self, row, col):
2015-10-30 15:36:06 +00:00
self.__fields[row - 1][col - 1].set_fixed()
2015-10-29 16:04:25 +00:00
def reveal_all(self):
for row in self.__fields:
for field in row:
field.fixed = True
@property
def solved(self):
# Check if all fileds have been marked
for row in self.__fields:
for field in row:
if field.player_type == FieldType.empty:
return False
# TODO: Check if marked ships are placed sanely
# TODO: Check if side-numbers equal the number of marked ship-parts
return True
2015-10-30 08:16:24 +00:00
def mark(self, row, col, typ):
2015-10-30 15:36:06 +00:00
field = self.__field(row, col)
if field is not None:
field.player_type = typ
def is_ship(self, row, col):
return self.__fields[row][col].player_type == FieldType.ship
def __str__(self):
def divider():
ret = '+'
for i in range(0, self.__width):
ret += '--+'
ret += "\n"
return ret
ret = divider()
for row in self.__fields:
ret += '|'
for field in row:
ret += '{}|'.format(field)
ret += "\n"
ret += divider()
return ret
2015-10-30 08:16:24 +00:00
class Solver(object):
def __init__(self, table):
self.table = table
def mark_edges(self):
for row in range(0, self.table.height):
for col in range(0, self.table.width):
2015-10-30 15:36:06 +00:00
if self.table.is_ship(row, col):
print("MARK!")
2015-10-30 08:16:24 +00:00
self.table.mark(row - 1, col - 1, FieldType.water)
self.table.mark(row - 1, col + 1, FieldType.water)
self.table.mark(row + 1, col - 1, FieldType.water)
self.table.mark(row + 1, col + 1, FieldType.water)
def show(self):
print(str(self.table))
2015-10-30 08:15:53 +00:00
colorama.init()
2015-10-29 16:04:25 +00:00
t = Table(6, 6)
t.add_ship(1, 3, 1, False)
t.add_ship(2, 5, 2, False)
t.add_ship(3, 1, 3, False)
t.add_ship(5, 1, 1, False)
t.add_ship(5, 3, 2, True)
t.add_ship(6, 5, 1, False)
t.reveal(1, 2)
t.reveal(3, 3)
t.reveal(5, 1)
t.reveal(5, 2)
2015-10-30 08:16:24 +00:00
s = Solver(t)
s.show()
s.mark_edges()
s.show()