updated movement logic and validation

This commit is contained in:
Alexander Karpov 2022-07-10 00:06:48 +03:00
parent 79a4d75730
commit 86c35b3d02
4 changed files with 153 additions and 26 deletions

View File

@ -129,7 +129,7 @@ class Deck(models.Model):
return self.get_heroes() return self.get_heroes()
def score(self): 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: class Meta:
db_table = "deck" db_table = "deck"

View File

@ -5,6 +5,8 @@ import django
from asgiref.sync import sync_to_async from asgiref.sync import sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer from channels.generic.websocket import AsyncWebsocketConsumer
from room.services.game_logic import move_handler
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "chess_backend.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "chess_backend.settings")
django.setup() django.setup()
@ -286,9 +288,16 @@ class RoomConsumer(BaseConsumer):
await self.send_message("ERROR", message="data is not JSON serializable") await self.send_message("ERROR", message="data is not JSON serializable")
if data: 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): if not await self.start(data):
await self.send_message("ERROR", message="opponent is offline") 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): async def start(self, data):
if self.scope["opponent_channel"] and self.scope["opponent_online"]: if self.scope["opponent_channel"] and self.scope["opponent_online"]:
@ -302,6 +311,22 @@ class RoomConsumer(BaseConsumer):
return True return True
return False 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 # info type group message handler
async def info(self, event): async def info(self, event):
message = event["message"] message = event["message"]
@ -327,13 +352,6 @@ class RoomConsumer(BaseConsumer):
await self.send(text_data=json.dumps(msg)) 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): async def channel(self, event):
channel = event["channel"] channel = event["channel"]
self.scope["opponent_channel"] = channel self.scope["opponent_channel"] = channel
@ -352,6 +370,19 @@ class RoomConsumer(BaseConsumer):
) )
self.scope["opponent_online"] = status 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): async def check_origin(self):
if not self.scope["player"]: if not self.scope["player"]:
await self.send( await self.send(

View File

@ -1,25 +1,111 @@
from asgiref.sync import sync_to_async
from room.models import HeroInGame, Room, PlayerInRoom from room.models import HeroInGame, Room, PlayerInRoom
def _check_move_position(x: int, y: int, room: Room, p_first: bool): def _check_path(f_x: int, f_y: int, x: int, y: int, room: Room, move_type: str):
hero = HeroInGame.objects.filter(x=x, y=y, room=room) if move_type == "DIAGONAL":
if not hero.exists(): 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 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: try:
hero = HeroInGame.objects.get(x=prev_x, y=prev_y, room=room, player=player) hero = HeroInGame.objects.get(x=prev_x, y=prev_y, room=room, player=player)
except HeroInGame.DoesNotExist: except HeroInGame.DoesNotExist:
return False return False
h_t = hero.hero.type if x == prev_x and y == prev_y:
if h_t == "KING": return False
if abs(prev_x - x) != 1 or abs(prev_y - y) != 1:
return False h_t = hero.hero.type
elif h_t == "WARRIOR":
if player.first: _print_board(room) # TODO: Remove in production
if x - prev_x == 1 and y - prev_y == 0:
_check_move_position(x, y, room, True)

View File

@ -37,14 +37,24 @@ def create_room(
first=first_player == 2, first=first_player == 2,
) )
for p, d_id in [(p1, deck_id_1), (p2, deck_id_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") GameState.objects.create(
for hero in Deck.objects.get(id=d_id).heroes.all(): 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: if p.first:
HeroInGame.objects.create( 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: else:
HeroInGame.objects.create( 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 return room.slug