New Version of ShipBattle

This commit is contained in:
danii 2024-06-03 13:20:55 +02:00
parent 001f87b1d2
commit 12cfbc7544
7 changed files with 194 additions and 145 deletions

View File

@ -1,11 +1,11 @@
from enum import Enum from enum import Enum
class ShipDirection(Enum): class ShipDirection(Enum):
VERTICAL = "VERTICAL" VERTICAL = "VERTICAL"
HORIZONTAL = "HORIZONTAL" HORIZONTAL = "HORIZONTAL"
UNKNOWN = "UNKNOWN" UNKNOWN = "UNKNOWN"
@staticmethod @staticmethod
def from_string(raw_value): def from_string(raw_value):
if raw_value: if raw_value:

View File

@ -32,7 +32,6 @@ class ShipField:
self.ship_size = obj['ship_size'] self.ship_size = obj['ship_size']
self.ship_direction = ShipDirection.from_string(obj['ship_direction']) self.ship_direction = ShipDirection.from_string(obj['ship_direction'])
def __getitem__(self, item): def __getitem__(self, item):
if item is None: if item is None:
return None return None
@ -87,7 +86,6 @@ class ShipField:
if "+" in self.field[i]: if "+" in self.field[i]:
self.field[i] = self.field[i].replace("+", "") self.field[i] = self.field[i].replace("+", "")
def set_ship(self, row, col): def set_ship(self, row, col):
if row < 0 or row > self.field_size: if row < 0 or row > self.field_size:
return return
@ -110,7 +108,6 @@ class ShipField:
if self.ship_size in self.ships: if self.ship_size in self.ships:
self.ships.remove(self.ship_size) self.ships.remove(self.ship_size)
def get_ship(self, row, col): def get_ship(self, row, col):
if row < 0 or row > self.field_size: if row < 0 or row > self.field_size:
return return
@ -122,7 +119,6 @@ class ShipField:
ship_size = 1 ship_size = 1
ship_direction = ShipDirection.UNKNOWN ship_direction = ShipDirection.UNKNOWN
# check vertical # check vertical
for r in range(row + 1, self.field_size): for r in range(row + 1, self.field_size):
if self.check_ship(r, col): if self.check_ship(r, col):
@ -140,9 +136,8 @@ class ShipField:
else: else:
break break
if ship_direction == ShipDirection.UNKNOWN: if ship_direction == ShipDirection.UNKNOWN:
# check horizontal # check horizontal
for c in range(col + 1, self.field_size): for c in range(col + 1, self.field_size):
if self.check_ship(row, c): if self.check_ship(row, c):
ship_size += 1 ship_size += 1
@ -160,9 +155,9 @@ class ShipField:
break break
self.set_ship_direction(ship_direction) self.set_ship_direction(ship_direction)
self.set_ship_size(ship_size) self.set_ship_size(self.ship_size)
self.ships.append(ship_size) self.ships.append(self.ship_size)
def shoot(self, row, col): def shoot(self, row, col):
if row < 0 or row > self.field_size - 1: if row < 0 or row > self.field_size - 1:
@ -251,7 +246,6 @@ class ShipField:
print(blocked_string[:-2] + ' ' + ship_string[:-2]) print(blocked_string[:-2] + ' ' + ship_string[:-2])
print("********************************************************************") print("********************************************************************")
@staticmethod @staticmethod
def convert_to_json(obj): def convert_to_json(obj):
if isinstance(obj, ShipField): if isinstance(obj, ShipField):

View File

@ -1,14 +1,14 @@
from unittest import TestCase from unittest import TestCase
from ShipField import ShipField from ShipField import ShipField
from ShootResult import ShootResult from ShootResult import ShootResult
from ShipMode import ShipMode
from ShipDirection import ShipDirection from ShipDirection import ShipDirection
from ShipMode import ShipMode
class TestShipField(TestCase): class TestShipField(TestCase):
def test_set_ship_size(self): def test_set_ship_size(self):
ship_field = ShipField() # Заводим объект типа ShipField ship_field = ShipField() # Заводим объект типа ShipField
ship_field.set_ship_size(1) ship_field.set_ship_size(1)
self.assertEqual(ship_field.ship_size, 1) self.assertEqual(ship_field.ship_size, 1)
@ -20,7 +20,7 @@ class TestShipField(TestCase):
self.assertEqual(ship_field.ship_size, 4) self.assertEqual(ship_field.ship_size, 4)
def test_set_ship_size_outofrange(self): def test_set_ship_size_outofrange(self):
ship_field = ShipField() # Заводим объект типа ShipField ship_field = ShipField() # Заводим объект типа ShipField
ship_field.set_ship_size(1) ship_field.set_ship_size(1)
ship_field.set_ship_size(-1) ship_field.set_ship_size(-1)
@ -33,7 +33,7 @@ class TestShipField(TestCase):
self.assertEqual(ship_field.ship_size, 1) self.assertEqual(ship_field.ship_size, 1)
def test_set_ship_size_wrongtype(self): def test_set_ship_size_wrongtype(self):
ship_field = ShipField() # Заводим объект типа ShipField ship_field = ShipField() # Заводим объект типа ShipField
ship_field.set_ship_size(1) ship_field.set_ship_size(1)
ship_field.set_ship_size([]) ship_field.set_ship_size([])
@ -46,14 +46,14 @@ class TestShipField(TestCase):
self.assertEqual(ship_field.ship_size, 1) self.assertEqual(ship_field.ship_size, 1)
def test_toggle_field_mode(self): def test_toggle_field_mode(self):
ship_field = ShipField() # Заводим объект типа ShipField ship_field = ShipField() # Заводим объект типа ShipField
self.assertEqual(ship_field.field_mode, ShipMode.PUT) # Проверяем, что изначальное значение field_mode равно 0 self.assertEqual(ship_field.field_mode, ShipMode.PUT) # Проверяем, что изначальное значение field_mode равно 0
ship_field.toggle_field_mode() # Вызываем метод, который тестируем ship_field.toggle_field_mode() # Вызываем метод, который тестируем
self.assertEqual(ship_field.field_mode, ShipMode.SHOOT) # Проверяем, что field_mode принял желаемое значение self.assertEqual(ship_field.field_mode, ShipMode.SHOOT) # Проверяем, что field_mode принял желаемое значение
ship_field.toggle_field_mode() # Вызываем метод, который тестируем ship_field.toggle_field_mode() # Вызываем метод, который тестируем
self.assertEqual(ship_field.field_mode, ShipMode.PUT) # Проверяем, что field_mode принял желаемое значение self.assertEqual(ship_field.field_mode, ShipMode.PUT) # Проверяем, что field_mode принял желаемое значение
def test_action(self): def test_action(self):
self.fail() self.fail()
@ -66,7 +66,6 @@ class TestShipField(TestCase):
ship_field.field[0] = 'p' ship_field.field[0] = 'p'
ship_field.field[ship_field.field_size - 1] = 'p' ship_field.field[ship_field.field_size - 1] = 'p'
ship_field.field[ship_field.field_size - 4] = 'r' ship_field.field[ship_field.field_size - 4] = 'r'
ship_field.clear_marker() ship_field.clear_marker()
self.assertNotIn('p', ship_field.field) self.assertNotIn('p', ship_field.field)
@ -118,102 +117,135 @@ class TestShipField(TestCase):
new_field_string = str.join(' ', ship_field.field) new_field_string = str.join(' ', ship_field.field)
self.assertEqual(new_field_string, old_field_string) self.assertEqual(new_field_string, old_field_string)
def test_set_ship_size4_vertical_direction(self): def test_check_possible_false(self):
ship_field = ShipField() # arrangement установка
ship_field.set_ship_size(4)
ship_field.set_ship_direction(0) #vertikal
ship_field.set_ship(6, 3)
self.assertEqual(ship_field.field[63].strip(), '1')
self.assertEqual(ship_field.field[73].strip(), '1')
self.assertEqual(ship_field.field[83].strip(), '1')
self.assertEqual(ship_field.field[93].strip(), '1')
def test_set_ship_size4_horizontal_direction(self):
ship_field = ShipField()
ship_field.set_ship_size(4)
ship_field.set_ship_direction(ShipDirection.HORIZONTAL)
ship_field.set_ship(6, 3)
self.assertEqual(ship_field.field[63].strip(), '1')
self.assertEqual(ship_field.field[64].strip(), '1')
self.assertEqual(ship_field.field[65].strip(), '1')
self.assertEqual(ship_field.field[66].strip(), '1')
def test_set_ship_size4_vertical_direction_outofrange(self):
ship_field = ShipField()
ship_field.set_ship_size(4)
ship_field.set_ship_direction(0)
old_field_string = str.join(' ', ship_field.field)
ship_field.set_ship(7, 3)
new_field_string = str.join(' ', ship_field.field)
self.assertEqual(new_field_string, old_field_string)
def test_check_possible(self):
ship_field = ShipField() ship_field = ShipField()
ship_field.set_ship_size(4) ship_field.set_ship_size(4)
ship_field.set_ship_direction(ShipDirection.HORIZONTAL) ship_field.set_ship_direction(ShipDirection.HORIZONTAL)
# action действие
ship_field.set_ship(5, 3) ship_field.set_ship(5, 3)
# assertion проверка занятых
self.assertEqual(ship_field.check_possible(5, 3), False) self.assertEqual(ship_field.check_possible(5, 3), False)
self.assertEqual(ship_field.check_possible(5, 4), False) self.assertEqual(ship_field.check_possible(5, 4), False)
self.assertEqual(ship_field.check_possible(5, 5), False) self.assertEqual(ship_field.check_possible(5, 5), False)
self.assertEqual(ship_field.check_possible(5, 6), False) self.assertEqual(ship_field.check_possible(5, 6), False)
# проверка строки ниже
self.assertEqual(ship_field.check_possible(6, 3), False) self.assertEqual(ship_field.check_possible(6, 3), False)
self.assertEqual(ship_field.check_possible(6, 4), False) self.assertEqual(ship_field.check_possible(6, 4), False)
self.assertEqual(ship_field.check_possible(6, 5), False) self.assertEqual(ship_field.check_possible(6, 5), False)
self.assertEqual(ship_field.check_possible(6, 6), False) self.assertEqual(ship_field.check_possible(6, 6), False)
# проверка строки выше
self.assertEqual(ship_field.check_possible(4, 3), False)
self.assertEqual(ship_field.check_possible(4, 4), False)
self.assertEqual(ship_field.check_possible(4, 5), False)
self.assertEqual(ship_field.check_possible(4, 6), False)
def test_check_possible_true(self):
# arrangement установка
ship_field = ShipField()
ship_field.set_ship_size(4)
ship_field.set_ship_direction(ShipDirection.HORIZONTAL)
# action действие
ship_field.set_ship(5, 3)
# проверка свободных ниже на 2 строки
self.assertEqual(ship_field.check_possible(7, 3), True) self.assertEqual(ship_field.check_possible(7, 3), True)
self.assertEqual(ship_field.check_possible(7, 4), True) self.assertEqual(ship_field.check_possible(7, 4), True)
self.assertEqual(ship_field.check_possible(7, 5), True) self.assertEqual(ship_field.check_possible(7, 5), True)
self.assertEqual(ship_field.check_possible(7, 6), True) self.assertEqual(ship_field.check_possible(7, 6), True)
# проверка свободных выше на 2 строки
self.assertEqual(ship_field.check_possible(3, 3), True)
self.assertEqual(ship_field.check_possible(3, 4), True)
self.assertEqual(ship_field.check_possible(3, 5), True)
self.assertEqual(ship_field.check_possible(3, 6), True)
def test_check_blocked(self): def test_check_blocked(self):
# arrangement установка
ship_field = ShipField() ship_field = ShipField()
ship_field.set_ship_size(4) ship_field.set_ship_size(4)
ship_field.set_ship_direction(ShipDirection.HORIZONTAL) ship_field.set_ship_direction(ShipDirection.HORIZONTAL)
# action действие
ship_field.set_ship(5, 3) ship_field.set_ship(5, 3)
# assertion проверка занятых
self.assertEqual(ship_field.check_possible(5, 3), False) self.assertEqual(ship_field.check_blocked(5, 3), False)
self.assertEqual(ship_field.check_possible(5, 4), False) self.assertEqual(ship_field.check_blocked(5, 4), False)
self.assertEqual(ship_field.check_possible(5, 5), False) self.assertEqual(ship_field.check_blocked(5, 5), False)
self.assertEqual(ship_field.check_possible(5, 6), False) self.assertEqual(ship_field.check_blocked(5, 6), False)
#проверка строки ниже
self.assertEqual(ship_field.check_possible(6, 3), False) self.assertEqual(ship_field.check_blocked(6, 3), False)
self.assertEqual(ship_field.check_possible(6, 4), False) self.assertEqual(ship_field.check_blocked(6, 4), False)
self.assertEqual(ship_field.check_possible(6, 5), False) self.assertEqual(ship_field.check_blocked(6, 5), False)
self.assertEqual(ship_field.check_possible(6, 6), False) self.assertEqual(ship_field.check_blocked(6, 7), False)
#проверка свободных ниже на 2 строки
self.assertEqual(ship_field.check_possible(7, 3), True) self.assertEqual(ship_field.check_blocked(7, 3), True)
self.assertEqual(ship_field.check_possible(7, 4), True) self.assertEqual(ship_field.check_blocked(7, 4), True)
self.assertEqual(ship_field.check_possible(7, 5), True) self.assertEqual(ship_field.check_blocked(7, 5), True)
self.assertEqual(ship_field.check_possible(7, 6), True) self.assertEqual(ship_field.check_blocked(7, 6), True)
def test_set_ship_direction(self): def test_set_ship_direction(self):
ship_field = ShipField() ship_field = ShipField() # Заводим объект типа ShipField
ship_field.set_ship_direction(ShipDirection.HORIZONTAL)
self.assertEqual(ship_field.ship_direction, ShipDirection.HORIZONTAL)
ship_field.set_ship_direction(ShipDirection.VERTICAL) ship_field.set_ship_direction(ShipDirection.VERTICAL)
self.assertEqual(ship_field.ship_direction, ShipDirection.VERTICAL) self.assertEqual(ship_field.ship_direction, ShipDirection.VERTICAL)
ship_field.set_ship_direction(ShipDirection.HORIZONTAL)
def test_toggle_ship_direction(self):
ship_field = ShipField()
ship_field.toggle_ship_direction()
self.assertEqual(ship_field.ship_direction, ShipDirection.HORIZONTAL) self.assertEqual(ship_field.ship_direction, ShipDirection.HORIZONTAL)
ship_field.toggle_ship_direction() def test_set_ship_direction_outofrange(self):
ship_field = ShipField() # Заводим объект типа ShipField
ship_field.set_ship_direction(1)
ship_field.set_ship_direction(-1)
ship_field.set_ship_direction(2)
self.assertEqual(ship_field.ship_direction, ShipDirection.VERTICAL) self.assertEqual(ship_field.ship_direction, ShipDirection.VERTICAL)
def test_set_ship_direction_wrongtype(self):
ship_field = ShipField() # Заводим объект типа ShipField
ship_field.set_ship_direction(1)
ship_field.set_ship_direction(None)
ship_field.set_ship_direction([2])
ship_field.set_ship_direction({})
self.assertEqual(ship_field.ship_direction, ShipDirection.VERTICAL)
def test_toggle_ship_direction(self):
# arrangement установка
ship_field = ShipField()
ship_field.set_ship_direction(ShipDirection.HORIZONTAL)
# action действие
ship_field.toggle_ship_direction()
# assertion проверка
self.assertEqual(ship_field.ship_direction, ShipDirection.VERTICAL)
ship_field.toggle_ship_direction()
self.assertEqual(ship_field.ship_direction, ShipDirection.HORIZONTAL)
def test_set_ship(self):
# arrangement установка
ship_field = ShipField()
ship_field.set_ship_size(4)
ship_field.set_ship_direction(ShipDirection.HORIZONTAL)
# action действие
ship_field.set_ship(5, 3)
# assertion проверка
self.assertEqual(ship_field.field[53].strip(), '1')
self.assertEqual(ship_field.field[54].strip(), '1')
self.assertEqual(ship_field.field[55].strip(), '1')
self.assertEqual(ship_field.field[56].strip(), '1')
def test_set_ship_size4_vertical_outofrange(self):
# arrangement установка
ship_field = ShipField()
ship_field.set_ship_size(4)
ship_field.set_ship_direction(ShipDirection.VERTICAL)
old_field_string = str.join(" ", ship_field.field)
# action действие
ship_field.set_ship(7, 3)
# assertion проверка
new_field_string = str.join(" ", ship_field.field)
self.assertEqual(new_field_string, old_field_string)

View File

@ -1,11 +1,11 @@
from enum import Enum from enum import Enum
class ShipMode(Enum): class ShipMode(Enum):
PUT = "PUT" PUT = "PUT"
SHOOT = "SHOOT" SHOOT = "SHOOT"
UNKNOWN = "UNKNOWN" UNKNOWN = "UNKNOWN"
@staticmethod @staticmethod
def from_string(raw_value): def from_string(raw_value):
if raw_value: if raw_value:

View File

@ -9,14 +9,15 @@ my_field = ShipField()
enemy_field = ShipField() enemy_field = ShipField()
active_field = my_field active_field = my_field
active_text = {}
def draw_field(window, field, col_offset): def draw_field(window, field, col_offset=0, row_offset=0):
buttons = [] buttons = []
for r in range(0, field.field_size): for r in range(0, field.field_size):
for c in range(0, field.field_size): for c in range(0, field.field_size):
btn = Button(window, text='', width=5, height=2) btn = Button(window, text='', width=5, height=2)
btn.grid(column=c + col_offset, row=r) btn.grid(column=c + col_offset, row=r + row_offset)
btn.bind('<Button-1>', lambda e, x=r, y=c: left_button_click(buttons, x, y)) btn.bind('<Button-1>', lambda e, x=r, y=c: left_button_click(buttons, x, y))
btn.bind('<Button-3>', right_button_click) btn.bind('<Button-3>', right_button_click)
btn.bind('<Enter>', lambda e, x=r, y=c: button_enter(buttons, x, y)) btn.bind('<Enter>', lambda e, x=r, y=c: button_enter(buttons, x, y))
@ -54,10 +55,13 @@ def keypress_handler(e):
def left_button_click(buttons, row, col): def left_button_click(buttons, row, col):
global active_field global active_field
global active_text
active_field.action(row, col) active_field.action(row, col)
colorize(active_field, buttons) colorize(active_field, buttons)
refresh_remaining_ships_label(active_field, active_text)
def right_button_click(d): def right_button_click(d):
global active_field global active_field
@ -66,14 +70,17 @@ def right_button_click(d):
def button_enter(buttons, row, col): def button_enter(buttons, row, col):
global active_field global active_field
global active_text
if buttons == my_buttons: if buttons == my_buttons:
active_field = my_field active_field = my_field
active_text = my_remainingShipsText
enemy_field.clear_marker() enemy_field.clear_marker()
my_field.target(row, col) my_field.target(row, col)
elif buttons == enemy_buttons: elif buttons == enemy_buttons:
active_field = enemy_field active_field = enemy_field
active_text = enemy_remainingShipsText
my_field.clear_marker() my_field.clear_marker()
enemy_field.target(row, col) enemy_field.target(row, col)
@ -81,68 +88,84 @@ def button_enter(buttons, row, col):
colorize(enemy_field, enemy_buttons) colorize(enemy_field, enemy_buttons)
def savebutton_click(): def savebutton_click(field):
file_path = filedialog.asksaveasfilename(filetypes=[("JSON files", "*.json")]) file_path = filedialog.asksaveasfilename(filetypes=[("JSON files", "*.json")])
if file_path: if file_path:
with open(file_path, 'w') as f: with open(file_path, 'w') as f:
json.dump({'my_field': my_field}, f, default=ShipField.convert_to_json) json.dump({'shipField': field}, f, default=ShipField.convert_to_json)
def loadbutton_click(): def loadbutton_click(field, buttons):
global my_field
file_path = filedialog.askopenfilename(filetypes=[("JSON files", "*.json")]) file_path = filedialog.askopenfilename(filetypes=[("JSON files", "*.json")])
if os.path.isfile(file_path): if os.path.isfile(file_path):
with open(file_path) as lines: with open(file_path) as lines:
my_field.from_json(json.load(lines)["my_field"]) field.from_json(json.load(lines)["shipField"])
colorize(my_field, my_buttons) colorize(field, buttons)
def savebutton_click_enemy(): def refresh_remaining_ships_label(field, stringvar):
file_path = filedialog.asksaveasfilename(filetypes=[("JSON files", "*.json")]) text = ''
for i in range(1, 5):
count = field.ships.count(i)
if count > 0:
text += f'{"[]" * i}: {count}, '
if file_path: stringvar.set(text[:-2])
with open(file_path, 'w') as f:
json.dump({'enemy_field': enemy_field}, f, default=ShipField.convert_to_json)
def loadbutton_click_enemy():
global enemy_field
file_path = filedialog.askopenfilename(filetypes=[("JSON files", "*.json")])
if os.path.isfile(file_path):
with open(file_path) as lines:
enemy_field.from_json(json.load(lines)["enemy_field"])
colorize(enemy_field, enemy_buttons)
window = Tk() window = Tk()
window.title("Ship Craft!") window.title("Ship Craft!")
window.geometry('940x510') window.geometry('1020x540')
window.bind_all('<KeyPress>', keypress_handler) window.bind_all('<KeyPress>', keypress_handler)
my_buttons = draw_field(window, my_field, 0) my_remainingShipsText = StringVar()
enemy_buttons = draw_field(window, enemy_field, 11) enemy_remainingShipsText = StringVar()
lbl = Label(window, text='', width=5, height=2) start_column_my_field = 1
lbl.grid(column=10, row=0) start_row_my_field = 1
savebutton = Button(window, text='Save', width=20, height=2, command=savebutton_click) start_column_enemy_field = start_column_my_field + my_field.field_size + 1
savebutton.grid(column=0, row=11, columnspan=4) start_row_enemy_field = start_row_my_field
loadbutton = Button(window, text='Load', width=20, height=2, command=loadbutton_click) col_vertical_separator = start_column_my_field + my_field.field_size
loadbutton.grid(column=5, row=11, columnspan=4) row_horizontal_separator = start_row_my_field + my_field.field_size
savebutton_enemy = Button(window, text='Save_enemy', width=20, height=2, command=savebutton_click_enemy) load_button_row = start_row_my_field + my_field.field_size + 1
savebutton_enemy.grid(column=11, row=11, columnspan=4)
loadbutton_enemy = Button(window, text='Load_enemy', width=20, height=2, command=loadbutton_click_enemy) my_buttons = draw_field(window, my_field, start_column_my_field, start_row_my_field)
loadbutton_enemy.grid(column=16, row=11, columnspan=4) enemy_buttons = draw_field(window, enemy_field, start_column_enemy_field, start_row_enemy_field)
if start_column_my_field > 0:
lbl_left_vertical = Label(window, text='', width=5, height=2)
lbl_left_vertical.grid(column=start_column_my_field - 1, row=start_row_my_field)
lbl_center_vertical = Label(window, text='', width=5, height=2)
lbl_center_vertical.grid(column=col_vertical_separator, row=start_row_my_field)
if start_row_my_field > 0:
lbl_upper_horizontal = Label(window, text='', width=5, height=2)
lbl_upper_horizontal.grid(column=start_column_my_field, row=start_row_my_field - 1)
lbl_lower_horizontal = Label(window, text='', width=50, height=2, textvariable=my_remainingShipsText)
lbl_lower_horizontal.grid(column=start_column_my_field, row=row_horizontal_separator, columnspan=10)
lbl_lower_enemy_horizontal = Label(window, text='', width=50, height=2, textvariable=enemy_remainingShipsText)
lbl_lower_enemy_horizontal.grid(column=start_column_enemy_field, row=row_horizontal_separator, columnspan=10)
savebutton = Button(window, text='Save', width=20, height=2, command=lambda: savebutton_click(my_field))
savebutton.grid(column=start_column_my_field, row=load_button_row, columnspan=4)
loadbutton = Button(window, text='Load', width=20, height=2, command=lambda: loadbutton_click(my_field, my_buttons))
loadbutton.grid(column=start_column_my_field + 6, row=load_button_row, columnspan=4)
savebutton_enemy = Button(window, text='Save', width=20, height=2, command=lambda: savebutton_click(enemy_field))
savebutton_enemy.grid(column=start_column_enemy_field, row=load_button_row, columnspan=4)
loadbutton_enemy = Button(window, text='Load', width=20, height=2, command=lambda: loadbutton_click(enemy_field, enemy_buttons))
loadbutton_enemy.grid(column=start_column_enemy_field + 6, row=load_button_row, columnspan=4)
window.mainloop() window.mainloop()