> 5.6_01 WIP checkpoint
This commit is contained in:
parent
8c5cd8e3e9
commit
c38575df6e
@ -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):
|
||||||
@ -177,12 +203,13 @@ class EnumOrdering(Enum):
|
|||||||
if isinstance(other, self.__class__):
|
if isinstance(other, self.__class__):
|
||||||
return self.value == other.value
|
return self.value == other.value
|
||||||
return self.value == other
|
return self.value == other
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, self.__class__):
|
||||||
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
|
||||||
@ -207,82 +234,150 @@ class ListEnumField:
|
|||||||
def __init__(self, enum_cls: Enum, length_key):
|
def __init__(self, enum_cls: Enum, length_key):
|
||||||
self.enum_cls = enum_cls
|
self.enum_cls = enum_cls
|
||||||
self.length_key = length_key
|
self.length_key = length_key
|
||||||
|
|
||||||
def __set_name__(self, owner, name):
|
def __set_name__(self, owner, name):
|
||||||
self.name = name + "_"
|
self.name = name + "_"
|
||||||
|
|
||||||
def __get__(self, instance, owner):
|
def __get__(self, instance, owner):
|
||||||
if instance is None:
|
if instance is None:
|
||||||
return self
|
return self
|
||||||
return [x.value for x in getattr(instance, self.name)]
|
return [x.value for x in getattr(instance, self.name)]
|
||||||
|
|
||||||
def get_item(self, instance, index):
|
def get_item(self, instance, index):
|
||||||
return getattr(instance, self.name)[index]
|
return getattr(instance, self.name)[index]
|
||||||
|
|
||||||
def set_item(self, instance, index, value):
|
def set_item(self, instance, index, value):
|
||||||
getattr(instance, self.name)[index] = self.enum_cls(value)
|
getattr(instance, self.name)[index] = self.enum_cls(value)
|
||||||
|
|
||||||
def __set__(self, instance, value):
|
def __set__(self, instance, value):
|
||||||
length = getattr(instance, str(self.length_key))
|
length = getattr(instance, str(self.length_key))
|
||||||
new_value = list(map(self.enum_cls, value))
|
new_value = list(map(self.enum_cls, value))
|
||||||
if len(new_value) != length:
|
if len(new_value) != length:
|
||||||
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
|
||||||
TWO_DECKS = 2
|
TWO_DECKS = 2
|
||||||
THREE_DECKS = 3
|
THREE_DECKS = 3
|
||||||
FOUR_DECKS = 4
|
FOUR_DECKS = 4
|
||||||
|
|
||||||
class ShipOrientation(EnumOrdering):
|
class ShipOrientation(EnumOrdering):
|
||||||
HORIZONTAL = 1
|
HORIZONTAL = 1
|
||||||
VERTICAL = 2
|
VERTICAL = 2
|
||||||
|
|
||||||
class DeckStatus(EnumOrdering):
|
class DeckStatus(EnumOrdering):
|
||||||
OK = 1
|
OK = 1
|
||||||
DAMAGED = 2
|
DAMAGED = 2
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self.__class__.__name__}{(self._length, self._tp, self._x, self._y, self._cells)!r}"
|
return f"{self.__class__.__name__}{(self._length, self._tp, self._x, self._y, self._cells)!r}"
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return self._length
|
return self._length
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.__class__._cells.get_item(self, key).value
|
return self.__class__._cells.get_item(self, key).value
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
return self.__class__._cells.set_item(self, key, value)
|
return self.__class__._cells.set_item(self, key, value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
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"
|
||||||
|
Loading…
Reference in New Issue
Block a user