From 86c35b3d027df806160493fa288e47bbb2c6f21b Mon Sep 17 00:00:00 2001 From: Alexander-D-Karpov Date: Sun, 10 Jul 2022 00:06:48 +0300 Subject: [PATCH] updated movement logic and validation --- game/models.py | 2 +- room/consumers.py | 47 ++++++++++++--- room/services/game_logic.py | 112 +++++++++++++++++++++++++++++++---- room/services/room_create.py | 18 ++++-- 4 files changed, 153 insertions(+), 26 deletions(-) diff --git a/game/models.py b/game/models.py index 48dd8a1..d6bf2e4 100644 --- a/game/models.py +++ b/game/models.py @@ -129,7 +129,7 @@ class Deck(models.Model): return self.get_heroes() def score(self): - return sum([x.attack + x.health + x.speed for x in self.get_heroes()]) + return sum([x.hero.attack + x.hero.health + x.hero.speed for x in self.get_heroes()]) class Meta: db_table = "deck" diff --git a/room/consumers.py b/room/consumers.py index df43f2b..b20aee4 100644 --- a/room/consumers.py +++ b/room/consumers.py @@ -5,6 +5,8 @@ import django from asgiref.sync import sync_to_async from channels.generic.websocket import AsyncWebsocketConsumer +from room.services.game_logic import move_handler + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "chess_backend.settings") django.setup() @@ -286,9 +288,16 @@ class RoomConsumer(BaseConsumer): await self.send_message("ERROR", message="data is not JSON serializable") if data: - if data["type"] == "start": + if "type" not in data: + await self.send_message("ERROR", message="incorrect data typing") + elif data["type"] == "start": if not await self.start(data): await self.send_message("ERROR", message="opponent is offline") + elif data["type"] == "move": + if all(x in data for x in ["x", "y", "px", "py"]): + await self.perform_move(data) + else: + await self.send_message("ERROR", message="incorrect data typing") async def start(self, data): if self.scope["opponent_channel"] and self.scope["opponent_online"]: @@ -302,6 +311,22 @@ class RoomConsumer(BaseConsumer): return True return False + async def perform_move(self, data): + await move_handler(data["px"], data["py"], data["x"], data["y"], self.room_name, self.scope["player_in_room"]) + if self.scope["opponent_channel"] and self.scope["opponent_online"]: + await self.channel_layer.send( + self.scope["opponent_channel"], + { + "type": "move", + "x": data["x"], + "y": data["y"], + "px": data["px"], + "py": data["py"], + }, + ) + return True + return False + # info type group message handler async def info(self, event): message = event["message"] @@ -327,13 +352,6 @@ class RoomConsumer(BaseConsumer): await self.send(text_data=json.dumps(msg)) - # Receive message from room group - async def chat_message(self, event): - message = event["message"] - - # Send message to WebSocket - await self.send(text_data=json.dumps({"lot": message})) - async def channel(self, event): channel = event["channel"] self.scope["opponent_channel"] = channel @@ -352,6 +370,19 @@ class RoomConsumer(BaseConsumer): ) self.scope["opponent_online"] = status + async def move(self, event): + await self.send( + text_data=json.dumps( + { + "type": "MOVE", + "x": event["x"], + "y": event["y"], + "px": event["px"], + "py": event["py"] + } + ) + ) + async def check_origin(self): if not self.scope["player"]: await self.send( diff --git a/room/services/game_logic.py b/room/services/game_logic.py index f0439e3..f00e02d 100644 --- a/room/services/game_logic.py +++ b/room/services/game_logic.py @@ -1,25 +1,111 @@ +from asgiref.sync import sync_to_async + from room.models import HeroInGame, Room, PlayerInRoom -def _check_move_position(x: int, y: int, room: Room, p_first: bool): - hero = HeroInGame.objects.filter(x=x, y=y, room=room) - if not hero.exists(): +def _check_path(f_x: int, f_y: int, x: int, y: int, room: Room, move_type: str): + if move_type == "DIAGONAL": + return HeroInGame.objects.filter(room=room, x__range=(f_x, x), y__range=(f_y, y)).count() == 0 + elif move_type == "HORIZONTAL": + return HeroInGame.objects.filter(room=room, x=x, y__range=(f_y, y)).count() == 0 + elif move_type == "VERTICAL": + return HeroInGame.objects.filter(room=room, x__range=(f_x, x), y=y).count() == 0 + return False + + +def _validate_hero_movement( + hero_type: str, + prev_x: int, + prev_y: int, + x: int, + y: int, + room: Room, + first: bool = False, # needed for warrior +): + if hero_type == "KING": + if abs(x - prev_x) > 1 or abs(y - prev_y) > 1: + return False + elif hero_type == "WIZARD": + if abs(x - prev_x) == abs(y - prev_y): + return _check_path(prev_x, prev_y, x, y, room, "DIAGONAL") + elif x == prev_x and y != prev_y: + return _check_path(prev_x, prev_y, x, y, room, "HORIZONTAL") + elif x != prev_x and y == prev_y: + return _check_path(prev_x, prev_y, x, y, room, "VERTICAL") return False - elif hero.first() + elif hero_type == "ARCHER": + if abs(x - prev_x) == abs(y - prev_y): + return _check_path(prev_x, prev_y, x, y, room, "DIAGONAL") + return False + elif hero_type == "WARRIOR": + if first: + if x == prev_x and y - prev_y == 1: + return True + elif abs(x - prev_x) == 1 and y - prev_y == 1: + return True + else: + if x == prev_x and prev_y - y == 1: + return True + return False -def move_handler(prev_x: int, prev_y: int, x: int, y: int, room: Room, player: PlayerInRoom): +def _print_board(room: Room): + class color: + PURPLE = '\033[95m' + CYAN = '\033[96m' + DARKCYAN = '\033[36m' + BLUE = '\033[94m' + GREEN = '\033[92m' + YELLOW = '\033[93m' + RED = '\033[91m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + END = '\033[0m' + + for y in range(1, 8): + for x in range(1, 9): + try: + hero = HeroInGame.objects.get(x=x, y=y, room=room) + if hero.hero.type == "KING": + if hero.player.first: + print("♔", end="") + else: + print("♚", end="") + elif hero.hero.type == "WIZARD": + if hero.player.first: + print("♕", end="") + else: + print("♛", end="") + elif hero.hero.type == "ARCHER": + if hero.player.first: + print("♗", end="") + else: + print("♝", end="") + else: + if hero.player.first: + print("♙", end="") + else: + print("♟", end="") + except HeroInGame.DoesNotExist: + print("*", end="") + print() + + +@sync_to_async +def move_handler( + prev_x: int, prev_y: int, x: int, y: int, room_slug: str, player: PlayerInRoom +): + room = Room.objects.get(slug=room_slug) + _print_board(room) # TODO: Remove in production try: hero = HeroInGame.objects.get(x=prev_x, y=prev_y, room=room, player=player) except HeroInGame.DoesNotExist: return False - h_t = hero.hero.type - if h_t == "KING": - if abs(prev_x - x) != 1 or abs(prev_y - y) != 1: - return False - elif h_t == "WARRIOR": - if player.first: - if x - prev_x == 1 and y - prev_y == 0: - _check_move_position(x, y, room, True) + if x == prev_x and y == prev_y: + return False + + h_t = hero.hero.type + + _print_board(room) # TODO: Remove in production diff --git a/room/services/room_create.py b/room/services/room_create.py index 9922d43..561d43a 100644 --- a/room/services/room_create.py +++ b/room/services/room_create.py @@ -37,14 +37,24 @@ def create_room( first=first_player == 2, ) for p, d_id in [(p1, deck_id_1), (p2, deck_id_2)]: - GameState.objects.create(room=room, player=p, round=0, message="Game started") - for hero in Deck.objects.get(id=d_id).heroes.all(): + GameState.objects.create( + room=room, player=p.player, round=0, message="Game started" + ) + for hero_in_deck in Deck.objects.get(id=d_id).heroes(): if p.first: HeroInGame.objects.create( - hero=hero, player=p, room=room, x=hero.x, y=hero.y + hero=hero_in_deck.hero, + player=p, + room=room, + x=hero_in_deck.x, + y=hero_in_deck.y, ) else: HeroInGame.objects.create( - hero=hero, player=p, room=room, x=hero.x, y=8 - hero.y + hero=hero_in_deck.hero, + player=p, + room=room, + x=hero_in_deck.x, + y=8 - hero_in_deck.y, ) return room.slug