> 5.6_01 WIP checkpoint

This commit is contained in:
Dmitry Belyaev 2024-04-27 13:54:33 +03:00
parent 8c5cd8e3e9
commit c38575df6e

View File

@ -86,11 +86,35 @@ True
>>> s[0] = 2 >>> s[0] = 2
>>> s._is_move >>> s._is_move
False False
>>> s = Ship(1)
>>> s.get_start_coords() >>> s.get_start_coords()
(None, None) (0, 0)
>>> s.set_start_coords(2, 3) >>> s.set_start_coords(2, 3)
>>> s.get_start_coords() >>> s.get_start_coords()
(2, 3) (2, 3)
>>> s.move(1)
>>> s.get_start_coords()
(3, 3)
>>> s.move(-1)
>>> s.get_start_coords()
(2, 3)
>>> s[0] = 2
>>> s.move(2)
>>> s.get_start_coords()
(2, 3)
>>> Ship(1).is_collide(Ship(2, 1, 2, 3))
False
>>> Ship(2, 1, 2, 3).is_collide(Ship(3, 2, 3, 2))
True
>>> Ship(2, 1, 0, 0).is_collide(Ship(1, 2, 2, 2))
True
>>> Ship(1).is_out_pole(10)
False
>>> Ship(3, 1, 8, 1).is_out_pole(10)
True
>>> Ship(3, 2, 1, 8).is_out_pole(10)
True
# --- # ---
@ -167,9 +191,11 @@ P.S. Для самых преданных поклонников програм
Сыграйте в эту игру и выиграйте у компьютера. Сыграйте в эту игру и выиграйте у компьютера.
""" """
from typing import Optional from typing import List, Optional
from enum import Enum from enum import Enum
from functools import total_ordering from functools import total_ordering
from collections import namedtuple
@total_ordering @total_ordering
class EnumOrdering(Enum): class EnumOrdering(Enum):
@ -183,6 +209,7 @@ class EnumOrdering(Enum):
return self.value < other.value return self.value < other.value
return self.value < other return self.value < other
class IntEnumField: class IntEnumField:
def __init__(self, enum_cls: Enum): def __init__(self, enum_cls: Enum):
self.enum_cls = enum_cls self.enum_cls = enum_cls
@ -229,6 +256,24 @@ class ListEnumField:
raise ValueError(f"{self.name} must be {length} elements long") raise ValueError(f"{self.name} must be {length} elements long")
setattr(instance, self.name, new_value) setattr(instance, self.name, new_value)
class NonNegativeIntField:
def __set_name__(self, owner, name):
self.name = name + "_"
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self.name)
def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError(f"{self.name} must be an integer")
if value < 0:
raise ValueError(f"{self.name} must be non-negative")
setattr(instance, self.name, value)
class Ship: class Ship:
class ShipSize(EnumOrdering): class ShipSize(EnumOrdering):
ONE_DECK = 1 ONE_DECK = 1
@ -246,11 +291,22 @@ class Ship:
pole_size: int = 10 pole_size: int = 10
_length = IntEnumField(ShipSize) _length: int = IntEnumField(ShipSize)
_tp = IntEnumField(ShipOrientation) _tp: int = IntEnumField(ShipOrientation)
_cells = ListEnumField(DeckStatus, _length) _cells: List[int] = ListEnumField(DeckStatus, _length)
_x: int = NonNegativeIntField()
_y: int = NonNegativeIntField()
def __init__(self, length: int, tp: int = 1, x: Optional[int] = None, y: Optional[int] = None, cells: Optional[list[DeckStatus]] = None): Rect = namedtuple("Rect", ["left", "top", "right", "bottom"])
def __init__(
self,
length: int,
tp: int = 1,
x: int = 0,
y: int = 0,
cells: Optional[list[DeckStatus]] = None,
):
self._length, self._tp, self._x, self._y = length, tp, x, y self._length, self._tp, self._x, self._y = length, tp, x, y
self._cells = cells or [self.DeckStatus.OK] * self._length self._cells = cells or [self.DeckStatus.OK] * self._length
@ -270,19 +326,58 @@ class Ship:
def _is_move(self) -> bool: def _is_move(self) -> bool:
return all(cell == self.DeckStatus.OK for cell in self) return all(cell == self.DeckStatus.OK for cell in self)
@property
def is_alive(self) -> bool:
return any(cell == self.DeckStatus.OK for cell in self)
def set_start_coords(self, x: int, y: int): def set_start_coords(self, x: int, y: int):
self._x, self._y = x, y self._x, self._y = x, y
def get_start_coords(self): def get_start_coords(self):
return self._x, self._y return self._x, self._y
def move(self, go: int):
if self._is_move:
if self._tp == self.ShipOrientation.HORIZONTAL:
self._x += go
else:
self._y += go
@property
def rect(self):
x, y = self.get_start_coords()
if self._tp == self.ShipOrientation.HORIZONTAL:
return self.Rect(x, y, x + self._length, y + 1)
else:
return self.Rect(x, y, x + 1, y + self._length)
def is_collide(self, other: "Ship") -> bool:
return (
self.rect.left <= other.rect.right
and self.rect.right >= other.rect.left
and self.rect.top <= other.rect.bottom
and self.rect.bottom >= other.rect.top
or any(
abs(getattr(a.rect, x) - getattr(b.rect, y)) == 0
for a, b in ((self, other), (other, self))
for x, y in (("left", "right"), ("top", "bottom"))
)
)
def is_out_pole(self, size: int) -> bool:
return (
self.rect.left < 0
or self.rect.top < 0
or self.rect.right > size
or self.rect.bottom > size
)
class GamePole: class GamePole:
def __init__(self, size: int = 10): def __init__(self, size: int = 10):
... ...
def tests(): def tests():
code = ( code = (
b"b7*OBAUz;cXlZaLGARmkXlZaDJs?wPX>ceqEFdu{3Ug>_a3DP(Q)p>$C^IY|GAtl4EFdr`3JPI" b"b7*OBAUz;cXlZaLGARmkXlZaDJs?wPX>ceqEFdu{3Ug>_a3DP(Q)p>$C^IY|GAtl4EFdr`3JPI"