diff --git a/app/games/[gameId]/visualizer.tsx b/app/games/[gameId]/visualizer.tsx new file mode 100644 index 0000000..f0abbff --- /dev/null +++ b/app/games/[gameId]/visualizer.tsx @@ -0,0 +1,90 @@ +import { Button } from "@/components/ui/button"; +import { ZombieSurvival } from "@/simulators/zombie-survival"; +import { useEffect, useRef, useState } from "react"; + +const REPLAY_SPEED = 600; + +export function Visualizer({ + map, + autoStart = false, + onSimulationEnd, +}: { + map: string[][]; + autoStart?: boolean; + onSimulationEnd?: (isWin: boolean) => void; +}) { + const simulator = useRef(null); + const interval = useRef(null); + const [isRunning, setIsRunning] = useState(false); + const [mapState, setMapState] = useState(map); + const [needsReset, setNeedsReset] = useState(false); + + const startSimulation = () => { + setNeedsReset(true); + const clonedMap = JSON.parse(JSON.stringify(map)); + simulator.current = new ZombieSurvival(clonedMap); + setMapState(simulator.current!.getState()); + setIsRunning(true); + interval.current = setInterval(() => { + if (simulator.current!.finished()) { + clearInterval(interval.current!); + interval.current = null; + setIsRunning(false); + if (onSimulationEnd) { + console.log("here"); + onSimulationEnd(!simulator.current!.getPlayer().dead()); + } + return; + } + simulator.current!.step(); + setMapState(simulator.current!.getState()); + }, REPLAY_SPEED); + }; + + useEffect(() => { + if (autoStart) { + startSimulation(); + } + }, [autoStart]); + + useEffect(() => { + return () => { + if (interval.current) { + clearInterval(interval.current); + } + }; + }, []); + + return ( +
+ {mapState.map((row, y) => ( +
+ {row.map((cell, x) => ( +
+ {cell} +
+ ))} +
+ ))} +
+ + +
+
+ ); +} diff --git a/app/header.tsx b/app/header.tsx index aa11012..a10f60d 100644 --- a/app/header.tsx +++ b/app/header.tsx @@ -44,6 +44,11 @@ export default function Header() { + {isAuthenticated && ( + + + + )} {flags?.showTestPage && ( diff --git a/app/maps/page.tsx b/app/maps/page.tsx new file mode 100644 index 0000000..82c329e --- /dev/null +++ b/app/maps/page.tsx @@ -0,0 +1,173 @@ +"use client"; + +import { Input } from "@/components/ui/input"; +import React, { useEffect, useState } from "react"; +import { Button } from "@/components/ui/button"; +import { useMutation } from "convex/react"; +import { api } from "@/convex/_generated/api"; + +export default function AddMapPage() { + const [height, setHeight] = useState(1); + const [width, setWidth] = useState(1); + const [map, setMap] = useState([]); + const [isSubmitted, setIsSubmitted] = useState(false); + const [isZombie, setIsZombie] = useState(false); + const createMap = useMutation(api.maps.addMap); + useEffect(() => { + generateMap(); + }, [height, width]); + + const generateMap = () => { + const newMap = Array.from({ length: height }, () => + Array.from({ length: width }, () => " "), + ); + newMap.forEach((row, y) => { + row.forEach((cell, x) => { + newMap[y][x] = " "; + }); + }); + setMap(newMap); + }; + const checkValidMap = () => { + var flag = false; + map.forEach((row, y) => { + row.forEach((cell, x) => { + if (map[y][x] == " ") { + console.log("All well!"); + flag = true; + } + }); + }); + console.log(map); + if (!flag) { + console.log("All set"); + console.log(map); + alert("No place left to place the player!"); + }else{ + createMap({grid: map}); + alert("Map saved"); + } + }; + const setCell = (y: number, x: number, z: boolean) => { + var cell = " "; + if (z == true) { + if (map[y][x] == "Z") { + cell = " "; + } else { + cell = "Z"; + } + } else { + if (map[y][x] == "B") { + cell = " "; + } else { + cell = "B"; + } + } + const newMap = map.map((row) => [...row]); + newMap[y][x] = cell; + setMap(newMap); + }; + return ( +
+ {isSubmitted ? ( +
+
+ + +
+
+ {map.map((row, y) => ( +
+ {row.map((cell, x) => ( +
+ +
+ ))} +
+ ))} +
+
+ ) : ( +
+

Enter the height of the map:

+ { + setHeight(+e.target.value); + }} + /> +

Enter the width of the map:

+ { + setWidth(+e.target.value); + }} + /> +
+ {map.map((row, y) => ( +
+ {row.map((cell, x) => ( +
+ {cell} +
+ ))} +
+ ))} +
+
+ )} +
+ {isSubmitted ? ( +
+ + +
+ ) : ( + + )} +
+
+ ); +} diff --git a/convex/maps.ts b/convex/maps.ts index b4ff3fd..28062b0 100644 --- a/convex/maps.ts +++ b/convex/maps.ts @@ -1,6 +1,7 @@ import { internalAction, internalMutation, + mutation, query, action, } from "./_generated/server"; @@ -37,6 +38,19 @@ const LEVELS = [ }, ]; +export const addMap = mutation({ + args: { + grid: v.array(v.array(v.string())), + }, + handler: async(ctx, args)=>{ + const arr = ctx.db.query("maps").collect(); + await ctx.db.insert("maps", { + level: (await arr).length+1, + grid: args.grid, + }); + } +}); + export const seedMaps = internalMutation({ handler: async (ctx) => { const maps = await ctx.db.query("maps").collect();