Sets the spawn in the backend when player is created, and other fixes :p
This commit is contained in:
parent
63502405e1
commit
47196161ac
BackendTests/Services
pac-man-board-game
ClientApp
src
components
game
types
utils
tests/game
Controllers
Game
Interfaces
Services
@ -11,27 +11,49 @@ namespace BackendTests.Services;
|
|||||||
|
|
||||||
public class ActionServiceTests
|
public class ActionServiceTests
|
||||||
{
|
{
|
||||||
private readonly IPlayer _blackPlayer = Players.Create("black");
|
private readonly Player _blackPlayer = (Player)Players.Create("black");
|
||||||
private readonly IPlayer _redPlayer = Players.Create("red");
|
private readonly Player _redPlayer = (Player)Players.Create("red");
|
||||||
private readonly IPlayer _whitePlayer = Players.Create("white");
|
|
||||||
|
private readonly Player _whitePlayer = (Player)Players.Create("white");
|
||||||
private ActionMessage _blackMessage = null!;
|
private ActionMessage _blackMessage = null!;
|
||||||
private ActionMessage _redMessage = null!;
|
private ActionMessage _redMessage = null!;
|
||||||
private IActionService _service = null!;
|
private IActionService _service = null!;
|
||||||
|
|
||||||
|
private Queue<DirectionalPosition> _spawns = null!;
|
||||||
|
|
||||||
private ActionMessage _whiteMessage = null!;
|
private ActionMessage _whiteMessage = null!;
|
||||||
private IWebSocketService _wssSub = null!;
|
private IWebSocketService _wssSub = null!;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
|
_spawns = CreateQueue();
|
||||||
_whiteMessage = new ActionMessage
|
_whiteMessage = new ActionMessage
|
||||||
{ Action = GameAction.PlayerInfo, Data = JsonSerializer.Serialize(_whitePlayer) };
|
{
|
||||||
|
Action = GameAction.PlayerInfo,
|
||||||
|
Data = JsonSerializer.Serialize(new { Player = _whitePlayer, Spawns = CreateQueue() })
|
||||||
|
};
|
||||||
_blackMessage = new ActionMessage
|
_blackMessage = new ActionMessage
|
||||||
{ Action = GameAction.PlayerInfo, Data = JsonSerializer.Serialize(_blackPlayer) };
|
{
|
||||||
_redMessage = new ActionMessage { Action = GameAction.PlayerInfo, Data = JsonSerializer.Serialize(_redPlayer) };
|
Action = GameAction.PlayerInfo,
|
||||||
|
Data = JsonSerializer.Serialize(new { Player = _blackPlayer, Spawns = CreateQueue() })
|
||||||
|
};
|
||||||
|
_redMessage = new ActionMessage
|
||||||
|
{
|
||||||
|
Action = GameAction.PlayerInfo,
|
||||||
|
Data = JsonSerializer.Serialize(new { Player = _redPlayer, Spawns = CreateQueue() })
|
||||||
|
};
|
||||||
_wssSub = Substitute.For<WebSocketService>(Substitute.For<ILogger<WebSocketService>>());
|
_wssSub = Substitute.For<WebSocketService>(Substitute.For<ILogger<WebSocketService>>());
|
||||||
_service = new ActionService(Substitute.For<ILogger<ActionService>>(), _wssSub);
|
_service = new ActionService(Substitute.For<ILogger<ActionService>>(), _wssSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Queue<DirectionalPosition> CreateQueue() =>
|
||||||
|
new(new[]
|
||||||
|
{
|
||||||
|
new DirectionalPosition { At = new Position { X = 3, Y = 3 }, Direction = Direction.Up },
|
||||||
|
new() { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down }
|
||||||
|
});
|
||||||
|
|
||||||
#region RollDice()
|
#region RollDice()
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -74,6 +96,9 @@ public class ActionServiceTests
|
|||||||
{
|
{
|
||||||
var players = _service.SetPlayerInfo(_whiteMessage);
|
var players = _service.SetPlayerInfo(_whiteMessage);
|
||||||
|
|
||||||
|
var pos = _spawns.Dequeue();
|
||||||
|
_whitePlayer.PacMan.Position = pos;
|
||||||
|
_whitePlayer.PacMan.SpawnPosition = pos;
|
||||||
Assert.That(new List<IPlayer> { _whitePlayer }, Is.EqualTo(players));
|
Assert.That(new List<IPlayer> { _whitePlayer }, Is.EqualTo(players));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +165,7 @@ public class ActionServiceTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void Ready_TwoReady()
|
public void Ready_TwoReady()
|
||||||
{
|
{
|
||||||
var group = new GameGroup { Players = { _blackPlayer, _whitePlayer } };
|
var group = new GameGroup(new Queue<DirectionalPosition>()) { Players = { _blackPlayer, _whitePlayer } };
|
||||||
_service.Group = group;
|
_service.Group = group;
|
||||||
_service.Player = _blackPlayer;
|
_service.Player = _blackPlayer;
|
||||||
|
|
||||||
|
@ -9,17 +9,34 @@ namespace BackendTests.Services;
|
|||||||
|
|
||||||
public class GameGroupTests
|
public class GameGroupTests
|
||||||
{
|
{
|
||||||
|
private readonly DirectionalPosition _spawn3By3Up = new()
|
||||||
|
{ At = new Position { X = 3, Y = 3 }, Direction = Direction.Up };
|
||||||
|
|
||||||
|
private readonly DirectionalPosition _spawn7By7Down = new()
|
||||||
|
{ At = new Position { X = 7, Y = 7 }, Direction = Direction.Down };
|
||||||
|
|
||||||
|
private readonly DirectionalPosition _spawn7By7Left = new()
|
||||||
|
{ At = new Position { X = 7, Y = 7 }, Direction = Direction.Left };
|
||||||
|
|
||||||
|
private readonly DirectionalPosition _spawn7By7Right = new()
|
||||||
|
{ At = new Position { X = 7, Y = 7 }, Direction = Direction.Right };
|
||||||
|
|
||||||
private IPlayer _bluePlayer = null!;
|
private IPlayer _bluePlayer = null!;
|
||||||
private GameGroup _gameGroup = null!;
|
private GameGroup _gameGroup = null!;
|
||||||
private IPlayer _greenPlayer = null!;
|
private IPlayer _greenPlayer = null!;
|
||||||
private IPlayer _purplePlayer = null!;
|
private IPlayer _purplePlayer = null!;
|
||||||
private IPlayer _redPlayer = null!;
|
private IPlayer _redPlayer = null!;
|
||||||
|
|
||||||
|
private Queue<DirectionalPosition> _spawns = null!;
|
||||||
private IPlayer _yellowPlayer = null!;
|
private IPlayer _yellowPlayer = null!;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
_gameGroup = new GameGroup();
|
_spawns = new Queue<DirectionalPosition>(
|
||||||
|
new[] { _spawn3By3Up, _spawn7By7Left, _spawn7By7Down, _spawn7By7Right });
|
||||||
|
|
||||||
|
_gameGroup = new GameGroup(_spawns);
|
||||||
_redPlayer = Players.Create("red");
|
_redPlayer = Players.Create("red");
|
||||||
_bluePlayer = Players.Create("blue");
|
_bluePlayer = Players.Create("blue");
|
||||||
_yellowPlayer = Players.Create("yellow");
|
_yellowPlayer = Players.Create("yellow");
|
||||||
@ -70,6 +87,14 @@ public class GameGroupTests
|
|||||||
Assert.That(_redPlayer.State, Is.EqualTo(State.WaitingForPlayers));
|
Assert.That(_redPlayer.State, Is.EqualTo(State.WaitingForPlayers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddPlayer_AddSpawnPosition()
|
||||||
|
{
|
||||||
|
_gameGroup.AddPlayer(_redPlayer);
|
||||||
|
Assert.That(_redPlayer.PacMan.SpawnPosition, Is.Not.Null);
|
||||||
|
Assert.That(_redPlayer.PacMan.SpawnPosition, Is.EqualTo(_spawn3By3Up));
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Sendtoall(ArraySegment<byte> segment)
|
#region Sendtoall(ArraySegment<byte> segment)
|
||||||
|
@ -11,12 +11,25 @@ namespace BackendTests.Services;
|
|||||||
|
|
||||||
public class WebSocketServiceTests
|
public class WebSocketServiceTests
|
||||||
{
|
{
|
||||||
|
private readonly DirectionalPosition _spawn3By3Up = new()
|
||||||
|
{ At = new Position { X = 3, Y = 3 }, Direction = Direction.Up };
|
||||||
|
|
||||||
private IWebSocketService _service = null!;
|
private IWebSocketService _service = null!;
|
||||||
|
|
||||||
|
private Queue<DirectionalPosition> _spawns = null!;
|
||||||
|
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
_service = new WebSocketService(Substitute.For<ILogger<WebSocketService>>());
|
_service = new WebSocketService(Substitute.For<ILogger<WebSocketService>>());
|
||||||
|
_spawns = new Queue<DirectionalPosition>(new[]
|
||||||
|
{
|
||||||
|
_spawn3By3Up,
|
||||||
|
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down },
|
||||||
|
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down },
|
||||||
|
new DirectionalPosition { At = new Position { X = 7, Y = 7 }, Direction = Direction.Down }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Send(Websocket, ArraySegment<byte>)
|
#region Send(Websocket, ArraySegment<byte>)
|
||||||
@ -135,7 +148,7 @@ public class WebSocketServiceTests
|
|||||||
public void AddPlayer_ToEmptyGroup()
|
public void AddPlayer_ToEmptyGroup()
|
||||||
{
|
{
|
||||||
var player = Players.Create("white");
|
var player = Players.Create("white");
|
||||||
var group = _service.AddPlayer(player);
|
var group = _service.AddPlayer(player, _spawns);
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
@ -151,12 +164,12 @@ public class WebSocketServiceTests
|
|||||||
for (var i = 0; i < 4; i++)
|
for (var i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
var player = Players.Create(i.ToString());
|
var player = Players.Create(i.ToString());
|
||||||
_service.AddPlayer(player);
|
_service.AddPlayer(player, _spawns);
|
||||||
}
|
}
|
||||||
|
|
||||||
var player5 = Players.Create("white");
|
var player5 = Players.Create("white");
|
||||||
|
|
||||||
var group = _service.AddPlayer(player5);
|
var group = _service.AddPlayer(player5, new Queue<DirectionalPosition>(new[] { _spawn3By3Up }));
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
|
@ -4,10 +4,9 @@ import findPossiblePositions from "../game/possibleMovesAlgorithm";
|
|||||||
import {GameTile} from "./gameTile";
|
import {GameTile} from "./gameTile";
|
||||||
import {TileType} from "../game/tileType";
|
import {TileType} from "../game/tileType";
|
||||||
import {useAtomValue} from "jotai";
|
import {useAtomValue} from "jotai";
|
||||||
import {allCharactersAtom} from "../utils/state";
|
import {allCharactersAtom, selectedDiceAtom} from "../utils/state";
|
||||||
|
|
||||||
interface BoardProps extends ComponentProps {
|
interface BoardProps extends ComponentProps {
|
||||||
selectedDice?: SelectedDice,
|
|
||||||
onMove?: Action<Position[]>,
|
onMove?: Action<Position[]>,
|
||||||
map: GameMap
|
map: GameMap
|
||||||
}
|
}
|
||||||
@ -15,12 +14,12 @@ interface BoardProps extends ComponentProps {
|
|||||||
const Board: Component<BoardProps> = (
|
const Board: Component<BoardProps> = (
|
||||||
{
|
{
|
||||||
className,
|
className,
|
||||||
selectedDice,
|
|
||||||
onMove,
|
onMove,
|
||||||
map
|
map
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const characters = useAtomValue(allCharactersAtom);
|
const characters = useAtomValue(allCharactersAtom);
|
||||||
|
const selectedDice = useAtomValue(selectedDiceAtom);
|
||||||
const [selectedCharacter, setSelectedCharacter] = useState<Character>();
|
const [selectedCharacter, setSelectedCharacter] = useState<Character>();
|
||||||
const [possiblePositions, setPossiblePositions] = useState<Path[]>([]); // TODO reset when other client moves a character
|
const [possiblePositions, setPossiblePositions] = useState<Path[]>([]); // TODO reset when other client moves a character
|
||||||
const [hoveredPosition, setHoveredPosition] = useState<Path>();
|
const [hoveredPosition, setHoveredPosition] = useState<Path>();
|
||||||
@ -63,15 +62,15 @@ const Board: Component<BoardProps> = (
|
|||||||
const pacMan = selectedCharacter as PacMan;
|
const pacMan = selectedCharacter as PacMan;
|
||||||
|
|
||||||
for (const tile of [...destination.Path ?? [], destination.End]) {
|
for (const tile of [...destination.Path ?? [], destination.End]) {
|
||||||
const currentTile = map[tile.y][tile.x];
|
const currentTile = map[tile.Y][tile.X];
|
||||||
|
|
||||||
if (currentTile === TileType.pellet) {
|
if (currentTile === TileType.pellet) {
|
||||||
// pacMan.box.addPellet(new Pellet()); // TODO update to current player
|
// pacMan.box.addPellet(new Pellet()); // TODO update to current player
|
||||||
map[tile.y][tile.x] = TileType.empty;
|
map[tile.Y][tile.X] = TileType.empty;
|
||||||
positions.push(tile);
|
positions.push(tile);
|
||||||
} else if (currentTile === TileType.powerPellet) {
|
} else if (currentTile === TileType.powerPellet) {
|
||||||
// pacMan.box.addPellet(new Pellet(true));
|
// pacMan.box.addPellet(new Pellet(true));
|
||||||
map[tile.y][tile.x] = TileType.empty;
|
map[tile.Y][tile.X] = TileType.empty;
|
||||||
positions.push(tile);
|
positions.push(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,9 +97,9 @@ const Board: Component<BoardProps> = (
|
|||||||
<GameTile
|
<GameTile
|
||||||
key={colIndex + rowIndex * colIndex}
|
key={colIndex + rowIndex * colIndex}
|
||||||
type={tile}
|
type={tile}
|
||||||
possiblePath={possiblePositions.find(p => p.End.x === colIndex && p.End.y === rowIndex)}
|
possiblePath={possiblePositions.find(p => p.End.X === colIndex && p.End.Y === rowIndex)}
|
||||||
character={characters.find(c => c.isAt({x: colIndex, y: rowIndex}))}
|
character={characters.find(c => c.isAt({X: colIndex, Y: rowIndex}))}
|
||||||
isSelected={selectedCharacter?.isAt({x: colIndex, y: rowIndex})}
|
isSelected={selectedCharacter?.isAt({X: colIndex, Y: rowIndex})}
|
||||||
showPath={hoveredPosition?.Path?.find(pos => pos.x === colIndex && pos.y === rowIndex) !== undefined}
|
showPath={hoveredPosition?.Path?.find(pos => pos.x === colIndex && pos.y === rowIndex) !== undefined}
|
||||||
handleMoveCharacter={handleMoveCharacter}
|
handleMoveCharacter={handleMoveCharacter}
|
||||||
handleSelectCharacter={handleSelectCharacter}
|
handleSelectCharacter={handleSelectCharacter}
|
||||||
|
@ -3,11 +3,12 @@ import {AllDice} from "./dice";
|
|||||||
import {doAction, GameAction} from "../utils/actions";
|
import {doAction, GameAction} from "../utils/actions";
|
||||||
import GameBoard from "./gameBoard";
|
import GameBoard from "./gameBoard";
|
||||||
import WebSocketService from "../websockets/WebSocketService";
|
import WebSocketService from "../websockets/WebSocketService";
|
||||||
import {testMap} from "../game/map";
|
import {getCharacterSpawns, testMap} from "../game/map";
|
||||||
import Player, {State} from "../game/player";
|
import Player, {State} from "../game/player";
|
||||||
import PlayerStats from "../components/playerStats";
|
import PlayerStats from "../components/playerStats";
|
||||||
import {getDefaultStore, useAtom, useAtomValue} from "jotai";
|
import {getDefaultStore, useAtom, useAtomValue} from "jotai";
|
||||||
import {currentPlayerAtom, diceAtom, ghostsAtom, playersAtom, selectedDiceAtom} from "../utils/state";
|
import {currentPlayerAtom, diceAtom, ghostsAtom, playersAtom, selectedDiceAtom} from "../utils/state";
|
||||||
|
import {CharacterType} from "../game/character";
|
||||||
|
|
||||||
const wsService = new WebSocketService(import.meta.env.VITE_API);
|
const wsService = new WebSocketService(import.meta.env.VITE_API);
|
||||||
|
|
||||||
@ -43,7 +44,19 @@ export const GameComponent: Component<{ player: Player }> = ({player}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function sendPlayer(): Promise<void> {
|
async function sendPlayer(): Promise<void> {
|
||||||
wsService.send({Action: GameAction.playerInfo, Data: player});
|
// TODO set spawn position and position
|
||||||
|
wsService.send({
|
||||||
|
Action: GameAction.playerInfo,
|
||||||
|
Data: {
|
||||||
|
Player: player, Spawns: getCharacterSpawns(testMap)
|
||||||
|
.filter(s => s.type === CharacterType.pacMan)
|
||||||
|
.map(s => s.position)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendReady(): void {
|
||||||
|
wsService.send({Action: GameAction.ready});
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -55,10 +68,6 @@ export const GameComponent: Component<{ player: Player }> = ({player}) => {
|
|||||||
return () => wsService.close();
|
return () => wsService.close();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function sendReady(): void {
|
|
||||||
wsService.send({Action: GameAction.ready});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={"flex-center"}>
|
<div className={"flex-center"}>
|
||||||
@ -70,9 +79,7 @@ export const GameComponent: Component<{ player: Player }> = ({player}) => {
|
|||||||
</div>
|
</div>
|
||||||
<AllDice values={dice} selectedDiceIndex={selectedDice?.index}/>
|
<AllDice values={dice} selectedDiceIndex={selectedDice?.index}/>
|
||||||
{players?.map(p => <PlayerStats key={p.Name} player={p} isCurrentPlayer={currentPlayer?.Name === p.Name}/>)}
|
{players?.map(p => <PlayerStats key={p.Name} player={p} isCurrentPlayer={currentPlayer?.Name === p.Name}/>)}
|
||||||
<GameBoard className={"mx-auto my-2"}
|
<GameBoard className={"mx-auto my-2"} onMove={onCharacterMove} map={testMap}/>
|
||||||
selectedDice={selectedDice}
|
|
||||||
onMove={onCharacterMove} map={testMap}/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@ import {TileType} from "../game/tileType";
|
|||||||
import {Character, Dummy} from "../game/character";
|
import {Character, Dummy} from "../game/character";
|
||||||
import {Direction} from "../game/direction";
|
import {Direction} from "../game/direction";
|
||||||
import {getCSSColour} from "../utils/colours";
|
import {getCSSColour} from "../utils/colours";
|
||||||
|
import {Colour} from "../game/colour";
|
||||||
|
|
||||||
interface TileWithCharacterProps extends ComponentProps {
|
interface TileWithCharacterProps extends ComponentProps {
|
||||||
possiblePath?: Path,
|
possiblePath?: Path,
|
||||||
@ -113,8 +114,8 @@ const Tile: Component<TileProps> = (
|
|||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}>
|
onMouseLeave={onMouseLeave}>
|
||||||
{children}
|
{children}
|
||||||
{type === TileType.pellet && <Circle colour={"yellow"}/>}
|
{type === TileType.pellet && <Circle colour={Colour.Yellow}/>}
|
||||||
{type === TileType.powerPellet && <Circle colour={"red"}/>}
|
{type === TileType.powerPellet && <Circle colour={Colour.Red}/>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -146,7 +147,7 @@ const CharacterComponent: Component<CharacterComponentProps> = (
|
|||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
function getSide() {
|
function getSide() {
|
||||||
switch (character?.Position.Direction) {
|
switch (character?.Position?.Direction) {
|
||||||
case Direction.up:
|
case Direction.up:
|
||||||
return "right-1/4 top-0";
|
return "right-1/4 top-0";
|
||||||
case Direction.down:
|
case Direction.down:
|
||||||
|
@ -57,7 +57,7 @@ export class Character {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isAt(position: Position): boolean {
|
public isAt(position: Position): boolean {
|
||||||
return this.Position !== null && this.Position.End.x === position.x && this.Position.End.y === position.y;
|
return this.Position !== null && this.Position.End.X === position.X && this.Position.End.Y === position.Y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ export class Dummy extends Character {
|
|||||||
Colour: Colour.Grey,
|
Colour: Colour.Grey,
|
||||||
Position: position,
|
Position: position,
|
||||||
IsEatable: false,
|
IsEatable: false,
|
||||||
SpawnPosition: {At: {x: 0, y: 0}, Direction: Direction.up},
|
SpawnPosition: {At: {X: 0, Y: 0}, Direction: Direction.up},
|
||||||
Type: CharacterType.dummy,
|
Type: CharacterType.dummy,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,10 @@ export function getCharacterSpawns(map: GameMap): { type: CharacterType, positio
|
|||||||
for (let col = 0; col < map.length; col++) {
|
for (let col = 0; col < map.length; col++) {
|
||||||
// TODO find direction
|
// TODO find direction
|
||||||
if (map[row][col] === 4) {
|
if (map[row][col] === 4) {
|
||||||
result.push({type: CharacterType.ghost, position: {At: {x: col, y: row}, Direction: Direction.up}});
|
result.push({type: CharacterType.ghost, position: {At: {X: col, Y: row}, Direction: Direction.up}});
|
||||||
} else if (map[row][col] === 5) {
|
} else if (map[row][col] === 5) {
|
||||||
result.push({
|
result.push({
|
||||||
type: CharacterType.pacMan, position: {At: {x: col, y: row}, Direction: Direction.up}
|
type: CharacterType.pacMan, position: {At: {X: col, Y: row}, Direction: Direction.up}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,23 +108,23 @@ function tryMove(board: GameMap, path: Path, direction: Direction, steps: number
|
|||||||
switch (direction) {
|
switch (direction) {
|
||||||
case Direction.left:
|
case Direction.left:
|
||||||
return {
|
return {
|
||||||
x: path.End.x - 1,
|
X: path.End.X - 1,
|
||||||
y: path.End.y
|
Y: path.End.Y
|
||||||
};
|
};
|
||||||
case Direction.up:
|
case Direction.up:
|
||||||
return {
|
return {
|
||||||
x: path.End.x,
|
X: path.End.X,
|
||||||
y: path.End.y - 1
|
Y: path.End.Y - 1
|
||||||
};
|
};
|
||||||
case Direction.right:
|
case Direction.right:
|
||||||
return {
|
return {
|
||||||
x: path.End.x + 1,
|
X: path.End.X + 1,
|
||||||
y: path.End.y
|
Y: path.End.Y
|
||||||
};
|
};
|
||||||
case Direction.down:
|
case Direction.down:
|
||||||
return {
|
return {
|
||||||
x: path.End.x,
|
X: path.End.X,
|
||||||
y: path.End.y + 1
|
Y: path.End.Y + 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,8 +150,8 @@ function addTeleportationTiles(board: GameMap, currentPath: Path, steps: number,
|
|||||||
const possiblePositions = findTeleportationTiles(board);
|
const possiblePositions = findTeleportationTiles(board);
|
||||||
const paths: Path[] = [];
|
const paths: Path[] = [];
|
||||||
for (const pos of possiblePositions) {
|
for (const pos of possiblePositions) {
|
||||||
if (pos.End.x !== interval(0, board.length - 1, currentPath.End.x) ||
|
if (pos.End.X !== interval(0, board.length - 1, currentPath.End.X) ||
|
||||||
pos.End.y !== interval(0, board.length - 1, currentPath.End.y)) {
|
pos.End.Y !== interval(0, board.length - 1, currentPath.End.Y)) {
|
||||||
|
|
||||||
pos.Path = currentPath.Path;
|
pos.Path = currentPath.Path;
|
||||||
paths.push(...findPossibleRecursive(board, pos, steps, character, characters));
|
paths.push(...findPossibleRecursive(board, pos, steps, character, characters));
|
||||||
@ -193,7 +193,7 @@ function findTeleportationTiles(board: GameMap): Path[] {
|
|||||||
*/
|
*/
|
||||||
function pushPath(board: GameMap, possiblePositions: Path[], x: number, y: number): void {
|
function pushPath(board: GameMap, possiblePositions: Path[], x: number, y: number): void {
|
||||||
if (board[x][y] !== TileType.wall) {
|
if (board[x][y] !== TileType.wall) {
|
||||||
possiblePositions.push({End: {x, y}, Direction: findDirection(x, y, board.length)});
|
possiblePositions.push({End: {X: x, Y: y}, Direction: findDirection(x, y, board.length)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +224,7 @@ function findDirection(x: number, y: number, boardSize: number): Direction {
|
|||||||
*/
|
*/
|
||||||
function isOutsideBoard(currentPos: Path, boardSize: number): boolean {
|
function isOutsideBoard(currentPos: Path, boardSize: number): boolean {
|
||||||
const pos = currentPos.End;
|
const pos = currentPos.End;
|
||||||
return pos.x < 0 || pos.x >= boardSize || pos.y < 0 || pos.y >= boardSize;
|
return pos.X < 0 || pos.X >= boardSize || pos.Y < 0 || pos.Y >= boardSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -234,7 +234,7 @@ function isOutsideBoard(currentPos: Path, boardSize: number): boolean {
|
|||||||
*/
|
*/
|
||||||
function isWall(board: GameMap, currentPos: Path): boolean {
|
function isWall(board: GameMap, currentPos: Path): boolean {
|
||||||
const pos = currentPos.End;
|
const pos = currentPos.End;
|
||||||
return board[pos.y][pos.x] === TileType.wall; // Shouldn't work, but it does
|
return board[pos.Y][pos.X] === TileType.wall; // Shouldn't work, but it does
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,7 +244,7 @@ function isWall(board: GameMap, currentPos: Path): boolean {
|
|||||||
*/
|
*/
|
||||||
function isSpawn(board: GameMap, currentPos: Path) {
|
function isSpawn(board: GameMap, currentPos: Path) {
|
||||||
const pos = currentPos.End;
|
const pos = currentPos.End;
|
||||||
return board[pos.y][pos.x] === TileType.pacmanSpawn || board[pos.y][pos.x] === TileType.ghostSpawn;
|
return board[pos.Y][pos.X] === TileType.pacmanSpawn || board[pos.Y][pos.X] === TileType.ghostSpawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -255,6 +255,6 @@ function isSpawn(board: GameMap, currentPos: Path) {
|
|||||||
function isOwnSpawn(currentPos: Path, character: Character): boolean {
|
function isOwnSpawn(currentPos: Path, character: Character): boolean {
|
||||||
const pos = currentPos.End;
|
const pos = currentPos.End;
|
||||||
const charPos = character.SpawnPosition!.At;
|
const charPos = character.SpawnPosition!.At;
|
||||||
return charPos.x === pos.x && charPos.y === pos.y;
|
return charPos.X === pos.X && charPos.Y === pos.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ type SelectedDice = {
|
|||||||
index: number
|
index: number
|
||||||
};
|
};
|
||||||
|
|
||||||
type Position = { x: number, y: number };
|
type Position = { X: number, Y: number };
|
||||||
|
|
||||||
type GameMap = number[][];
|
type GameMap = number[][];
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ function removeEatenPellets(data?: MoveCharacterData): void {
|
|||||||
const pellets = data?.EatenPellets;
|
const pellets = data?.EatenPellets;
|
||||||
|
|
||||||
for (const pellet of pellets ?? []) {
|
for (const pellet of pellets ?? []) {
|
||||||
testMap[pellet.y][pellet.x] = TileType.empty;
|
testMap[pellet.Y][pellet.X] = TileType.empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ let pacMan: Character;
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
pacMan = new PacMan({
|
pacMan = new PacMan({
|
||||||
Colour: "yellow", SpawnPosition: {At: {x: 3, y: 3}, Direction: Direction.up}
|
Colour: "yellow", SpawnPosition: {At: {X: 3, Y: 3}, Direction: Direction.up}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -29,21 +29,21 @@ test("Pac-Man rolls two from start, should return one position", () => {
|
|||||||
test("Pac-Man rolls three from start, should return two positions", () => {
|
test("Pac-Man rolls three from start, should return two positions", () => {
|
||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 3, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 3, []);
|
||||||
expect(result.length).toBe(2);
|
expect(result.length).toBe(2);
|
||||||
arrayEquals(result, [{End: {x: 2, y: 1}, Direction: Direction.left, Path: [{x: 3, y: 2}, {x: 3, y: 1}]},
|
arrayEquals(result, [{End: {X: 2, Y: 1}, Direction: Direction.left, Path: [{X: 3, Y: 2}, {X: 3, Y: 1}]},
|
||||||
{End: {x: 4, y: 1}, Direction: Direction.right, Path: [{x: 3, y: 2}, {x: 3, y: 1}]}]);
|
{End: {X: 4, Y: 1}, Direction: Direction.right, Path: [{X: 3, Y: 2}, {X: 3, Y: 1}]}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Pac-Man rolls four from start, should return two positions", () => {
|
test("Pac-Man rolls four from start, should return two positions", () => {
|
||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 4, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 4, []);
|
||||||
expect(result.length).toBe(2);
|
expect(result.length).toBe(2);
|
||||||
arrayEquals(result, [{
|
arrayEquals(result, [{
|
||||||
End: {x: 1, y: 1},
|
End: {X: 1, Y: 1},
|
||||||
Direction: Direction.left,
|
Direction: Direction.left,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 2, y: 1}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 2, Y: 1}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 5, y: 1},
|
End: {X: 5, Y: 1},
|
||||||
Direction: Direction.right,
|
Direction: Direction.right,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}]
|
||||||
}]);
|
}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,21 +51,21 @@ test("Pac-Man rolls five from start, should return four positions", () => {
|
|||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 5, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 5, []);
|
||||||
expect(result.length).toBe(4);
|
expect(result.length).toBe(4);
|
||||||
arrayEquals(result, [{
|
arrayEquals(result, [{
|
||||||
End: {x: 5, y: 0},
|
End: {X: 5, Y: 0},
|
||||||
Direction: Direction.up,
|
Direction: Direction.up,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}, {X: 5, Y: 1}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 6, y: 1},
|
End: {X: 6, Y: 1},
|
||||||
Direction: Direction.right,
|
Direction: Direction.right,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}, {X: 5, Y: 1}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 1, y: 2},
|
End: {X: 1, Y: 2},
|
||||||
Direction: Direction.down,
|
Direction: Direction.down,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 2, y: 1}, {x: 1, y: 1}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 2, Y: 1}, {X: 1, Y: 1}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 5, y: 2},
|
End: {X: 5, Y: 2},
|
||||||
Direction: Direction.down,
|
Direction: Direction.down,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}, {X: 5, Y: 1}]
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@ -75,72 +75,72 @@ test("Pac-Man rolls six from start, should return six positions", () => {
|
|||||||
expect(result.length).toBe(6);
|
expect(result.length).toBe(6);
|
||||||
arrayEquals(result, [
|
arrayEquals(result, [
|
||||||
{
|
{
|
||||||
End: {x: 1, y: 3},
|
End: {X: 1, Y: 3},
|
||||||
Direction: Direction.down,
|
Direction: Direction.down,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 2, y: 1}, {x: 1, y: 1}, {x: 1, y: 2}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 2, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 2}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 0, y: 5},
|
End: {X: 0, Y: 5},
|
||||||
Direction: Direction.right,
|
Direction: Direction.right,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 5, y: 0}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 0}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 5, y: 3},
|
End: {X: 5, Y: 3},
|
||||||
Direction: Direction.down,
|
Direction: Direction.down,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 5, y: 2}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 2}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 7, y: 1},
|
End: {X: 7, Y: 1},
|
||||||
Direction: Direction.right,
|
Direction: Direction.right,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 6, y: 1}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}, {X: 5, Y: 1}, {X: 6, Y: 1}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 10, y: 5},
|
End: {X: 10, Y: 5},
|
||||||
Direction: Direction.left,
|
Direction: Direction.left,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 5, y: 0}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 0}]
|
||||||
}, {
|
}, {
|
||||||
End: {x: 5, y: 10},
|
End: {X: 5, Y: 10},
|
||||||
Direction: Direction.up,
|
Direction: Direction.up,
|
||||||
Path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 5, y: 0}]
|
Path: [{X: 3, Y: 2}, {X: 3, Y: 1}, {X: 4, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 0}]
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Pac-Man rolls four from position [5,1] (right), should return 11", () => {
|
test("Pac-Man rolls four from position [5,1] (right), should return 11", () => {
|
||||||
pacMan.follow({End: {x: 5, y: 1}, Direction: Direction.right});
|
pacMan.follow({End: {X: 5, Y: 1}, Direction: Direction.right});
|
||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 4, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 4, []);
|
||||||
expect(result.length).toBe(11);
|
expect(result.length).toBe(11);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Pac-Man rolls four from position [5,1] (left), should return 12", () => {
|
test("Pac-Man rolls four from position [5,1] (left), should return 12", () => {
|
||||||
pacMan.follow({End: {x: 5, y: 1}, Direction: Direction.left});
|
pacMan.follow({End: {X: 5, Y: 1}, Direction: Direction.left});
|
||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 4, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 4, []);
|
||||||
expect(result.length).toBe(12);
|
expect(result.length).toBe(12);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Pac-Man rolls three from position [1,5] (left), should return 5", () => {
|
test("Pac-Man rolls three from position [1,5] (left), should return 5", () => {
|
||||||
pacMan.follow({End: {x: 1, y: 5}, Direction: Direction.left});
|
pacMan.follow({End: {X: 1, Y: 5}, Direction: Direction.left});
|
||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 3, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 3, []);
|
||||||
arrayEquals(result, [
|
arrayEquals(result, [
|
||||||
{End: {x: 1, y: 2}, Direction: Direction.up, Path: [{x: 1, y: 4}, {x: 1, y: 3}]},
|
{End: {X: 1, Y: 2}, Direction: Direction.up, Path: [{X: 1, Y: 4}, {X: 1, Y: 3}]},
|
||||||
{End: {x: 1, y: 8}, Direction: Direction.down, Path: [{x: 1, y: 6}, {x: 1, y: 7}]},
|
{End: {X: 1, Y: 8}, Direction: Direction.down, Path: [{X: 1, Y: 6}, {X: 1, Y: 7}]},
|
||||||
{End: {x: 5, y: 1}, Direction: Direction.down, Path: [{x: 0, y: 5}, {x: 5, y: 0}]},
|
{End: {X: 5, Y: 1}, Direction: Direction.down, Path: [{X: 0, Y: 5}, {X: 5, Y: 0}]},
|
||||||
{End: {x: 9, y: 5}, Direction: Direction.left, Path: [{x: 0, y: 5}, {x: 10, y: 5}]},
|
{End: {X: 9, Y: 5}, Direction: Direction.left, Path: [{X: 0, Y: 5}, {X: 10, Y: 5}]},
|
||||||
{End: {x: 5, y: 9}, Direction: Direction.up, Path: [{x: 0, y: 5}, {x: 5, y: 10}]},
|
{End: {X: 5, Y: 9}, Direction: Direction.up, Path: [{X: 0, Y: 5}, {X: 5, Y: 10}]},
|
||||||
]);
|
]);
|
||||||
expect(result.length).toBe(5);
|
expect(result.length).toBe(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Pac-Man rolls six from position [1,5] (down), should return 17", () => {
|
test("Pac-Man rolls six from position [1,5] (down), should return 17", () => {
|
||||||
pacMan.follow({End: {x: 1, y: 5}, Direction: Direction.down});
|
pacMan.follow({End: {X: 1, Y: 5}, Direction: Direction.down});
|
||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 6, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 6, []);
|
||||||
expect(result.length).toBe(17);
|
expect(result.length).toBe(17);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Pac-Man rolls six from position [7,1] (right), path to [9,5] should be five tiles long", () => {
|
test("Pac-Man rolls six from position [7,1] (right), path to [9,5] should be five tiles long", () => {
|
||||||
pacMan.follow({End: {x: 7, y: 1}, Direction: Direction.right});
|
pacMan.follow({End: {X: 7, Y: 1}, Direction: Direction.right});
|
||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 6, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 6, []);
|
||||||
expect(result[0].Path?.length).toBe(5);
|
expect(result[0].Path?.length).toBe(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Pac-Man rolls 5 from position [9,3] (down), should return 5", () => {
|
test("Pac-Man rolls 5 from position [9,3] (down), should return 5", () => {
|
||||||
pacMan.follow({End: {x: 9, y: 3}, Direction: Direction.down});
|
pacMan.follow({End: {X: 9, Y: 3}, Direction: Direction.down});
|
||||||
const result = possibleMovesAlgorithm(testMap, pacMan, 5, []);
|
const result = possibleMovesAlgorithm(testMap, pacMan, 5, []);
|
||||||
expect(result.length).toBe(5);
|
expect(result.length).toBe(5);
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@ namespace pacMan.Controllers;
|
|||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class GameController : GenericController
|
public class GameController : GenericController // TODO reconnect using player id
|
||||||
{
|
{
|
||||||
private readonly IActionService _actionService;
|
private readonly IActionService _actionService;
|
||||||
|
|
||||||
|
@ -12,15 +12,10 @@ public enum GameAction
|
|||||||
|
|
||||||
public class ActionMessage<T>
|
public class ActionMessage<T>
|
||||||
{
|
{
|
||||||
public GameAction Action { get; set; }
|
public GameAction Action { get; init; }
|
||||||
public T? Data { get; set; }
|
public T? Data { get; set; }
|
||||||
|
|
||||||
public static ActionMessage FromJson(string json)
|
public static ActionMessage FromJson(string json) => JsonSerializer.Deserialize<ActionMessage>(json)!;
|
||||||
{
|
|
||||||
return JsonSerializer.Deserialize<ActionMessage>(json)!;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ActionMessage : ActionMessage<dynamic>
|
public class ActionMessage : ActionMessage<dynamic> { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
@ -2,11 +2,11 @@ namespace pacMan.Game;
|
|||||||
|
|
||||||
public class Character : IEquatable<Character>
|
public class Character : IEquatable<Character>
|
||||||
{
|
{
|
||||||
public required string Colour { get; set; }
|
public required string Colour { get; init; }
|
||||||
public MovePath? Position { get; set; }
|
public MovePath? Position { get; set; }
|
||||||
public bool IsEatable { get; set; } = true;
|
public bool IsEatable { get; set; } = true;
|
||||||
public DirectionalPosition? SpawnPosition { get; set; }
|
public DirectionalPosition? SpawnPosition { get; set; }
|
||||||
public required CharacterType Type { get; set; }
|
public required CharacterType? Type { get; init; }
|
||||||
|
|
||||||
public bool Equals(Character? other)
|
public bool Equals(Character? other)
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@ namespace pacMan.Game.Items;
|
|||||||
|
|
||||||
public class Box : IEquatable<Box>
|
public class Box : IEquatable<Box>
|
||||||
{
|
{
|
||||||
public required List<Pellet>? Pellets { get; init; } = new();
|
public List<Pellet>? Pellets { get; init; } = new();
|
||||||
public required string Colour { get; init; }
|
public required string Colour { get; init; }
|
||||||
|
|
||||||
public int CountNormal => Pellets?.Count(pellet => !pellet.IsPowerPellet) ?? 0;
|
public int CountNormal => Pellets?.Count(pellet => !pellet.IsPowerPellet) ?? 0;
|
||||||
|
@ -5,7 +5,7 @@ public interface IPlayer
|
|||||||
string Name { get; init; }
|
string Name { get; init; }
|
||||||
Character PacMan { get; init; }
|
Character PacMan { get; init; }
|
||||||
string Colour { get; init; }
|
string Colour { get; init; }
|
||||||
Box Box { get; init; }
|
Box? Box { get; init; }
|
||||||
State State { get; set; }
|
State State { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ public class Player : IPlayer, IEquatable<Player>
|
|||||||
public required string Name { get; init; }
|
public required string Name { get; init; }
|
||||||
public required Character PacMan { get; init; }
|
public required Character PacMan { get; init; }
|
||||||
public required string Colour { get; init; }
|
public required string Colour { get; init; }
|
||||||
public required Box Box { get; init; }
|
public Box? Box { get; init; }
|
||||||
public State State { get; set; } = State.WaitingForPlayers;
|
public State State { get; set; } = State.WaitingForPlayers;
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
|
@ -1,16 +1,55 @@
|
|||||||
namespace pacMan.Game;
|
namespace pacMan.Game;
|
||||||
|
|
||||||
public class MovePath
|
public class MovePath : IEquatable<MovePath>
|
||||||
{
|
{
|
||||||
public Position[]? Path { get; set; }
|
public Position[]? Path { get; set; }
|
||||||
public required Position End { get; set; }
|
public required Position End { get; init; }
|
||||||
public required Direction Direction { get; set; }
|
public required Direction Direction { get; init; }
|
||||||
|
|
||||||
|
public bool Equals(MovePath? other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
return Equals(Path, other.Path) && End.Equals(other.End) && Direction == other.Direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator MovePath(DirectionalPosition path) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
End = path.At,
|
||||||
|
Direction = path.Direction
|
||||||
|
};
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
return obj.GetType() == GetType() && Equals((MovePath)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() => HashCode.Combine(Path, End, (int)Direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Position
|
public class Position : IEquatable<Position>
|
||||||
{
|
{
|
||||||
public int X { get; set; } = 0;
|
public int X { get; init; }
|
||||||
public int Y { get; set; } = 0;
|
public int Y { get; init; }
|
||||||
|
|
||||||
|
public bool Equals(Position? other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
return X == other.X && Y == other.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
return obj.GetType() == GetType() && Equals((Position)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() => HashCode.Combine(X, Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Direction
|
public enum Direction
|
||||||
@ -21,8 +60,31 @@ public enum Direction
|
|||||||
Down
|
Down
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DirectionalPosition
|
public class DirectionalPosition : IEquatable<DirectionalPosition>
|
||||||
{
|
{
|
||||||
public required Position At { get; set; }
|
public required Position At { get; init; }
|
||||||
public required Direction Direction { get; set; }
|
public required Direction Direction { get; init; }
|
||||||
}
|
|
||||||
|
public bool Equals(DirectionalPosition? other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
return At.Equals(other.At) && Direction == other.Direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator DirectionalPosition(MovePath path) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
At = path.End,
|
||||||
|
Direction = path.Direction
|
||||||
|
};
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
return obj.GetType() == GetType() && Equals((DirectionalPosition)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() => HashCode.Combine(At, (int)Direction);
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
|
using pacMan.Game;
|
||||||
using pacMan.Game.Items;
|
using pacMan.Game.Items;
|
||||||
using pacMan.Services;
|
using pacMan.Services;
|
||||||
|
|
||||||
@ -13,5 +14,5 @@ public interface IWebSocketService
|
|||||||
void SendToAll(ArraySegment<byte> segment);
|
void SendToAll(ArraySegment<byte> segment);
|
||||||
Task<WebSocketReceiveResult> Receive(WebSocket webSocket, byte[] buffer);
|
Task<WebSocketReceiveResult> Receive(WebSocket webSocket, byte[] buffer);
|
||||||
Task Close(WebSocket webSocket, WebSocketCloseStatus closeStatus, string? closeStatusDescription);
|
Task Close(WebSocket webSocket, WebSocketCloseStatus closeStatus, string? closeStatusDescription);
|
||||||
GameGroup AddPlayer(IPlayer player);
|
GameGroup AddPlayer(IPlayer player, Queue<DirectionalPosition> spawns);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ public class ActionService : IActionService
|
|||||||
_wsService = wsService;
|
_wsService = wsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameGroup Group { get; set; } = new();
|
public GameGroup? Group { get; set; }
|
||||||
|
|
||||||
public IPlayer? Player { get; set; }
|
public IPlayer? Player { get; set; }
|
||||||
|
|
||||||
@ -56,14 +56,16 @@ public class ActionService : IActionService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Receieved JsonElement from frontend
|
// Receieving JsonElement from frontend
|
||||||
Player = JsonSerializer.Deserialize<Player>(message.Data);
|
PlayerInfoData data = JsonSerializer.Deserialize<PlayerInfoData>(message.Data);
|
||||||
Group = _wsService.AddPlayer(Player);
|
Player = data.Player;
|
||||||
|
|
||||||
|
Group = _wsService.AddPlayer(Player, data.Spawns);
|
||||||
}
|
}
|
||||||
catch (RuntimeBinderException e)
|
catch (RuntimeBinderException e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(e);
|
Console.WriteLine(e);
|
||||||
if (message.Data == null) throw new NullReferenceException();
|
if (message.Data is null) throw new NullReferenceException();
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@ -74,7 +76,7 @@ public class ActionService : IActionService
|
|||||||
public object Ready()
|
public object Ready()
|
||||||
{
|
{
|
||||||
object data;
|
object data;
|
||||||
if (Player != null)
|
if (Player != null && Group != null)
|
||||||
{
|
{
|
||||||
var players = Group.SetReady(Player).ToArray();
|
var players = Group.SetReady(Player).ToArray();
|
||||||
if (players.All(p => p.State == State.Ready))
|
if (players.All(p => p.State == State.Ready))
|
||||||
@ -96,3 +98,9 @@ public class ActionService : IActionService
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PlayerInfoData
|
||||||
|
{
|
||||||
|
public required Player Player { get; set; }
|
||||||
|
public required Queue<DirectionalPosition> Spawns { get; set; }
|
||||||
|
}
|
||||||
|
@ -8,14 +8,20 @@ namespace pacMan.Services;
|
|||||||
public class GameGroup : IEnumerable<IPlayer>
|
public class GameGroup : IEnumerable<IPlayer>
|
||||||
{
|
{
|
||||||
private readonly Random _random = new();
|
private readonly Random _random = new();
|
||||||
|
|
||||||
|
public GameGroup(Queue<DirectionalPosition> spawns) => Spawns = spawns;
|
||||||
|
|
||||||
public List<IPlayer> Players { get; } = new();
|
public List<IPlayer> Players { get; } = new();
|
||||||
|
private Queue<DirectionalPosition> Spawns { get; }
|
||||||
|
|
||||||
public IPlayer RandomPlayer => Players[_random.Next(Count)];
|
public IPlayer RandomPlayer => Players[_random.Next(Count)];
|
||||||
|
|
||||||
public int Count => Players.Count;
|
public int Count => Players.Count;
|
||||||
|
|
||||||
public IEnumerator<IPlayer> GetEnumerator() => Players.GetEnumerator();
|
public IEnumerator<IPlayer> GetEnumerator() => Players.GetEnumerator();
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
public event Func<ArraySegment<byte>, Task>? Connections;
|
public event Func<ArraySegment<byte>, Task>? Connections;
|
||||||
|
|
||||||
public bool AddPlayer(IPlayer player) // TODO if name exists, use that player instead
|
public bool AddPlayer(IPlayer player) // TODO if name exists, use that player instead
|
||||||
@ -25,9 +31,18 @@ public class GameGroup : IEnumerable<IPlayer>
|
|||||||
player.State = State.WaitingForPlayers;
|
player.State = State.WaitingForPlayers;
|
||||||
if (Players.Exists(p => p.Name == player.Name)) return true;
|
if (Players.Exists(p => p.Name == player.Name)) return true;
|
||||||
Players.Add(player);
|
Players.Add(player);
|
||||||
|
if (player.PacMan.SpawnPosition is null) SetSpawn(player);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetSpawn(IPlayer player)
|
||||||
|
{
|
||||||
|
if (player.PacMan.SpawnPosition is not null) return;
|
||||||
|
var spawn = Spawns.Dequeue();
|
||||||
|
player.PacMan.SpawnPosition = spawn;
|
||||||
|
player.PacMan.Position = spawn;
|
||||||
|
}
|
||||||
|
|
||||||
public void SendToAll(ArraySegment<byte> segment) => Connections?.Invoke(segment);
|
public void SendToAll(ArraySegment<byte> segment) => Connections?.Invoke(segment);
|
||||||
|
|
||||||
public IEnumerable<IPlayer> SetReady(IPlayer player)
|
public IEnumerable<IPlayer> SetReady(IPlayer player)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
|
using pacMan.Game;
|
||||||
using pacMan.Game.Items;
|
using pacMan.Game.Items;
|
||||||
using pacMan.Interfaces;
|
using pacMan.Interfaces;
|
||||||
using pacMan.Utils;
|
using pacMan.Utils;
|
||||||
@ -56,7 +57,7 @@ public class WebSocketService : IWebSocketService
|
|||||||
_logger.Log(LogLevel.Information, "WebSocket connection closed");
|
_logger.Log(LogLevel.Information, "WebSocket connection closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameGroup AddPlayer(IPlayer player)
|
public GameGroup AddPlayer(IPlayer player, Queue<DirectionalPosition> spawns)
|
||||||
{
|
{
|
||||||
var index = 0;
|
var index = 0;
|
||||||
try
|
try
|
||||||
@ -65,7 +66,7 @@ public class WebSocketService : IWebSocketService
|
|||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException)
|
catch (ArgumentOutOfRangeException)
|
||||||
{
|
{
|
||||||
var game = new GameGroup();
|
var game = new GameGroup(spawns);
|
||||||
game.AddPlayer(player);
|
game.AddPlayer(player);
|
||||||
Games.Add(game);
|
Games.Add(game);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user