Refactored box to use number instead of list of objects

This commit is contained in:
Martin Berg Alstad 2023-07-22 21:20:30 +02:00
parent d98293e3e7
commit 12b40702c8
12 changed files with 49 additions and 76 deletions

View File

@ -11,9 +11,9 @@ namespace BackendTests.Services;
public class ActionServiceTests
{
private readonly Player _blackPlayer = Players.Create("black");
private readonly Player _redPlayer = (Player)Players.Create("red");
private readonly Player _redPlayer = Players.Create("red");
private readonly Player _whitePlayer = (Player)Players.Create("white");
private readonly Player _whitePlayer = Players.Create("white");
private ActionMessage _blackMessage = null!;
private GameService _gameService = null!;
private ActionMessage _redMessage = null!;
@ -92,7 +92,7 @@ public class ActionServiceTests
public void PlayerInfo_DataIsNotPlayer()
{
var serialized =
JsonDocument.Parse(JsonSerializer.Serialize(new Box { Colour = "white", Pellets = new List<Pellet>() }));
JsonDocument.Parse(JsonSerializer.Serialize(new Box { Colour = "white" }));
var message = new ActionMessage
{
Action = GameAction.PlayerInfo,

View File

@ -24,8 +24,7 @@ internal static class Players
internal static Box CreateBox(string colour) =>
new()
{
Colour = colour,
Pellets = new List<Pellet>()
Colour = colour
};
internal static Player Clone(this Player player) =>

View File

@ -3,9 +3,8 @@ import {Character} from "../game/character";
import findPossiblePositions from "../game/possibleMovesAlgorithm";
import {GameTile} from "./gameTile";
import {TileType} from "../game/tileType";
import {atom, PrimitiveAtom, useAtom, useAtomValue, useSetAtom} from "jotai";
import {atom, useAtom, useAtomValue, useSetAtom} from "jotai";
import {allCharactersAtom, currentPlayerAtom, playersAtom, selectedDiceAtom} from "../utils/state";
import Pellet from "../game/pellet";
import {Dialog, Transition} from "@headlessui/react";
interface BoardProps extends ComponentProps {
@ -13,7 +12,7 @@ interface BoardProps extends ComponentProps {
map: GameMap
}
const modalOpenAtom: PrimitiveAtom<boolean> = atom(false);
const modalOpenAtom = atom(false);
const Board: FC<BoardProps> = (
{
@ -77,7 +76,11 @@ const Board: FC<BoardProps> = (
const currentTile = map[tile.y][tile.x];
function updateTileAndPlayerBox(isPowerPellet = false): void {
currentPlayer?.addPellet(new Pellet(isPowerPellet));
if (isPowerPellet) {
currentPlayer?.addPowerPellet();
} else {
currentPlayer?.addPellet();
}
map[tile.y][tile.x] = TileType.empty;
positions.push(tile);
}
@ -182,10 +185,10 @@ const SelectPlayerModal: FC = () => {
{
allPlayers.map(player =>
<div key={player.username} className={"border-b pb-1"}>
<span className={"mx-2"}>{player.username} has {player.box.count} pellets</span>
<span className={"mx-2"}>{player.username} has {player.box.pellets} pellets</span>
<button className={"text-blue-500 enabled:cursor-pointer disabled:text-gray-500"}
style={{background: "none"}}
disabled={player.box.count === 0}
disabled={player.box.pellets === 0}
onClick={() => {
currentPlayer?.stealFrom(player);
close();

View File

@ -20,7 +20,6 @@ const wsService = new WebSocketService(import.meta.env.VITE_API_WS);
// TODO bug, stolen pellets are only updated on the client that stole them
// TODO guest users
// TODO protected routes? checking if user is logged in
// TODO store map in backend and save it in state on each client
// TODO add debug menu on dev, for testing and cheating
// TODO sign up player page

View File

@ -17,9 +17,10 @@ const PlayerStats: FC<{ player: Player } & ComponentProps> = (
<p>Colour: {player.colour}</p>
{player.state === State.inGame || player.state === State.disconnected ?
<>
<p>Pellets: {player.box.count}</p>
<p>PowerPellets: {player.box.countPowerPellets}</p>
</> :
<p>Pellets: {player.box.pellets}</p>
<p>PowerPellets: {player.box.powerPellets}</p>
</>
:
<p>{player.state === State.waitingForPlayers ? "Waiting" : "Ready"}</p>}
</div>
);

View File

@ -1,28 +1,32 @@
import Pellet from "./pellet";
export default class Box implements BoxProps {
public pellets;
public readonly colour;
public pellets;
public powerPellets;
public constructor({colour, pellets = []}: BoxProps) {
public constructor({colour, pellets = 0, powerPellets = 0}: BoxProps) {
this.colour = colour;
this.pellets = pellets;
this.powerPellets = powerPellets;
}
get powerPellet(): Pellet | undefined {
return this.pellets.find(pellet => pellet.isPowerPellet);
public addPellet(): void {
this.pellets++;
}
get count(): number {
return this.pellets.filter(pellet => !pellet.isPowerPellet).length;
public removePellet(): boolean {
if (this.pellets <= 0) return false;
this.pellets--;
return true;
}
get countPowerPellets(): number {
return this.pellets.filter(pellet => pellet.isPowerPellet).length;
public addPowerPellet(): void {
this.powerPellets++;
}
public addPellet(pellet: Pellet): void {
this.pellets.push(pellet);
public removePowerPellet(): boolean {
if (this.powerPellets <= 0) return false;
this.powerPellets--;
return true;
}
}

View File

@ -1,7 +0,0 @@
export default class Pellet {
public readonly isPowerPellet: boolean;
public constructor(isPowerPellet = false) {
this.isPowerPellet = isPowerPellet;
}
}

View File

@ -2,7 +2,6 @@ import {Character, CharacterType} from "./character";
import Box from "./box";
import {getDefaultStore} from "jotai";
import {currentPlayerNameAtom, playersAtom} from "../utils/state";
import Pellet from "./pellet";
import rules from "./rules";
export enum State {
@ -35,15 +34,19 @@ export default class Player implements PlayerProps {
return Player.store.get(currentPlayerNameAtom) === this.username;
}
public addPellet(pellet: Pellet): void {
this.box.addPellet(pellet);
public addPellet(): void {
this.box.addPellet();
}
public addPowerPellet(): void {
this.box.addPowerPellet();
}
public stealFrom(other: Player): void {
for (let i = 0; i < rules.maxStealPellets; i++) {
const pellet = other.box.pellets.pop();
if (pellet)
this.box.addPellet(pellet);
const removed = other.box.removePellet();
if (removed)
this.box.addPellet();
}
Player.store.set(playersAtom, Player.store.get(playersAtom).map(player => player));
}

View File

@ -38,7 +38,8 @@ interface CharacterProps {
}
interface BoxProps {
pellets?: import("../game/pellet").default[],
pellets?: number,
powerPellets?: number,
readonly colour: import("../game/colour").Colour,
}

View File

@ -4,23 +4,16 @@ namespace pacMan.GameStuff.Items;
public class Box : IEquatable<Box>
{
[JsonPropertyName("pellets")] public List<Pellet>? Pellets { get; init; } = new();
[JsonPropertyName("pellets")] public int Pellets { get; init; }
[JsonPropertyName("powerPellets")] public int PowerPellet { get; init; }
[JsonPropertyName("colour")] public required string Colour { get; init; }
public int CountNormal => Pellets?.Count(pellet => !pellet.IsPowerPellet) ?? 0;
public bool Equals(Box? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return (Equals(Pellets, other.Pellets) || (Pellets?.Count == 0 && other.Pellets?.Count == 0)) &&
Colour == other.Colour;
}
public void Add(Pellet pellet)
{
Pellets?.Add(pellet);
return Pellets == other.Pellets && PowerPellet == other.PowerPellet && Colour == other.Colour;
}
public override bool Equals(object? obj)
@ -30,5 +23,5 @@ public class Box : IEquatable<Box>
return obj.GetType() == GetType() && Equals((Box)obj);
}
public override int GetHashCode() => HashCode.Combine(Pellets, Colour);
public override int GetHashCode() => HashCode.Combine(Pellets, PowerPellet, Colour);
}

View File

@ -1,24 +0,0 @@
using System.Text.Json.Serialization;
namespace pacMan.GameStuff.Items;
public class Pellet : IEquatable<Pellet>
{
[JsonPropertyName("isPowerPellet")] public bool IsPowerPellet { get; init; }
public bool Equals(Pellet? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return IsPowerPellet == other.IsPowerPellet;
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
return obj.GetType() == GetType() && Equals((Pellet)obj);
}
public override int GetHashCode() => IsPowerPellet.GetHashCode();
}

View File

@ -48,6 +48,7 @@
<TypeScriptCompile Remove="ClientApp\src\websockets\actions.ts" />
<TypeScriptCompile Remove="ClientApp\src\utils\colours.ts" />
<TypeScriptCompile Remove="ClientApp\src\utils\dom.ts" />
<TypeScriptCompile Remove="ClientApp\src\game\pellet.ts" />
</ItemGroup>
<ItemGroup>