Skip to content

Commit

Permalink
put watch page as main page
Browse files Browse the repository at this point in the history
  • Loading branch information
webdevcody committed Oct 16, 2024
2 parents 0d522c7 + ac30ca5 commit 474616f
Show file tree
Hide file tree
Showing 17 changed files with 281 additions and 243 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This starter project works with [convex](https://www.convex.dev) so to run you n
If you want to mock all models - in convex, please add the following environment variables:

- `npx convex env set MOCK_MODELS true`
- `npx convex env set NODE_ENV development`

Add optional environment variable/s for simulating real AI models without mockup responses(when mockup flags are set to FALSE):

Expand Down
11 changes: 9 additions & 2 deletions app/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import Image from "next/image";
import { Button } from "@/components/ui/button";
import { useAuthActions } from "@convex-dev/auth/react";
import { GitHubLogoIcon } from "@radix-ui/react-icons";
import { useConvexAuth } from "convex/react";
import { useConvexAuth, useQuery } from "convex/react";
import { ThemeToggle } from "@/components/ThemeToggle";
import { api } from "@/convex/_generated/api";

function SignInWithGitHub() {
const { signIn } = useAuthActions();
Expand All @@ -24,6 +25,7 @@ function SignInWithGitHub() {
export default function Header() {
const { signOut } = useAuthActions();
const { isAuthenticated } = useConvexAuth();
const flags = useQuery(api.flags.getFlags);

return (
<header className="flex justify-between items-center py-4 px-6 shadow-sm border-b">
Expand All @@ -33,7 +35,7 @@ export default function Header() {
</Link>

<nav className="flex items-center space-x-4">
<Link href="/watch">
<Link href="/">
<Button variant="ghost">Watch</Button>
</Link>
<Link href="/play">
Expand All @@ -42,6 +44,11 @@ export default function Header() {
<Link href="/leaderboard">
<Button variant="ghost">Leaderboard</Button>
</Link>
{flags?.showTestPage && (
<Link href="/test">
<Button variant="ghost">Test</Button>
</Link>
)}
</nav>

<div className="flex items-center space-x-4">
Expand Down
5 changes: 3 additions & 2 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { Providers } from "./provider";
const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Convex + Next.js + Convex Auth",
description: "Generated by npm create convex",
title: "Survive The Night - Zombie Survival Simulation Game",
description:
"Watch to see if AI models can survive the night. Also challenge yourself to many levels of our puzzle game",
icons: {
icon: "/logo.png",
},
Expand Down
109 changes: 72 additions & 37 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,85 @@
"use client";

import { useQuery } from "convex/react";
import { api } from "@/convex/_generated/api";
import { useAction, useMutation } from "convex/react";
import React, { useState } from "react";
import { Button } from "@/components/ui/button";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { AI_MODELS } from "@/convex/constants";
import { useRouter } from "next/navigation";
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from "@/components/ui/table";
import { TableHeader } from "@/components/ui/table";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import Result from "./result";

export default function GamePage() {
const results = useQuery(api.results.getLastCompletedResults);
const globalRanking = useQuery(api.leaderboard.getGlobalRankings);

export default function MainPage() {
const startNewGame = useMutation(api.games.startNewGame);
const [model, setModel] = useState(AI_MODELS[0].model);
const router = useRouter();
if (results === undefined) {
return (
<div className="min-h-screen container mx-auto pt-12 pb-24 space-y-8">
<h1 className="text-2xl font-bold">Recent Games</h1>
<p>Loading...</p>
</div>
);
}

const handleClick = async () => {
await startNewGame({
modelId: model,
}).then((gameId) => {
router.push(`/games/${gameId}`);
});
};
if (results.length === 0) {
return (
<div className="min-h-screen container mx-auto pt-12 pb-24 space-y-8">
<h1 className="text-2xl font-bold">Recent Games</h1>
<p>No results yet</p>
</div>
);
}

return (
<div className="container mx-auto min-h-screen flex flex-col items-center pt-12 gap-8">
<h1 className="text-4xl font-bold mb-8">Zombie Map Simulator</h1>
<div className="min-h-screen container mx-auto pt-12 pb-24 flex gap-12">
<div className="space-y-8 flex-grow">
<h1 className="text-2xl font-bold">Recent Games</h1>
<div className="h-[80vh] overflow-y-auto flex flex-col gap-4">
{results.map((result) => (
<Result key={result._id} result={result} />
))}
</div>
</div>

<div className="flex justify-center gap-4">
<Select value={model} onValueChange={(value) => setModel(value)}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select model" />
</SelectTrigger>
<SelectContent>
{AI_MODELS.map((model) => (
<SelectItem key={model.model} value={model.model}>
{model.name}
</SelectItem>
<div className="space-y-8">
<div className="flex justify-between items-center">
<h2 className="text-2xl font-bold">LLM Leaderboard</h2>
<Button asChild>
<Link href="/leaderboard">View Full Leaderboard</Link>
</Button>
</div>
<Table className="w-[500px]">
<TableHeader>
<TableRow>
<TableHead>Model ID</TableHead>
<TableHead className="text-right">Wins</TableHead>
<TableHead className="text-right">Losses</TableHead>
<TableHead className="text-right">Total Games</TableHead>
<TableHead className="text-right">Win Ratio</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{globalRanking?.map((item) => (
<TableRow key={item._id}>
<TableCell>{item.modelId}</TableCell>
<TableCell className="text-right">{item.wins}</TableCell>
<TableCell className="text-right">{item.losses}</TableCell>
<TableCell className="text-right">
{item.wins + item.losses}
</TableCell>
<TableCell className="text-right">
{((item.wins / (item.wins + item.losses)) * 100).toFixed(2)}%
</TableCell>
</TableRow>
))}
</SelectContent>
</Select>
<Button onClick={handleClick}>Test Model</Button>
</TableBody>
</Table>
</div>
</div>
);
Expand Down
10 changes: 8 additions & 2 deletions app/watch/result.tsx → app/result.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import { ResultStatus } from "../result-status";
import { ResultStatus } from "./result-status";
import { type ResultWithGame } from "@/convex/results";
import { Visualizer } from "../visualizer";
import { Visualizer } from "./visualizer";
import { format } from "date-fns";
import Link from "next/link";
import { Card } from "@/components/ui/card";
Expand Down Expand Up @@ -40,6 +40,12 @@ export default function Result({ result }: { result: ResultWithGame }) {
>
Night #{result.level}
</Link>{" "}
<Link
href={`/games/${result.game._id}`}
className="whitespace-nowrap hover:underline cursor-pointer"
>
Game {result.game._id.substring(0, 8)}...
</Link>
<div className="flex gap-2">
The <span className="font-bold">{result.game.modelId}</span> model
{result.status === "inProgress" ? (
Expand Down
58 changes: 58 additions & 0 deletions app/test/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";

import React from "react";
import { useQuery, useMutation } from "convex/react";
import { useRouter } from "next/navigation";
import { Button } from "@/components/ui/button";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { api } from "@/convex/_generated/api";

export default function TestPage() {
const models = useQuery(api.models.getActiveModels);
const testModel = useMutation(api.games.testModel);
const [model, setModel] = React.useState("");
const router = useRouter();

React.useEffect(() => {
if (models !== undefined && models.length !== 0) {
setModel(models[0].slug);
}
}, [models]);

const handleClick = async () => {
await testModel({
modelId: model,
}).then((gameId) => {
router.push(`/games/${gameId}`);
});
};

return (
<div className="container mx-auto min-h-screen flex flex-col items-center pt-12 gap-8">
<h1 className="text-4xl font-bold mb-8">Zombie Map Simulator</h1>

<div className="flex justify-center gap-4">
<Select value={model} onValueChange={(value) => setModel(value)}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select model" />
</SelectTrigger>
<SelectContent>
{models !== undefined &&
models.map((model) => (
<SelectItem key={model._id} value={model.slug}>
{model.name}
</SelectItem>
))}
</SelectContent>
</Select>
<Button onClick={handleClick}>Test Model</Button>
</div>
</div>
);
}
86 changes: 0 additions & 86 deletions app/watch/page.tsx

This file was deleted.

6 changes: 6 additions & 0 deletions convex/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ import type {
} from "convex/server";
import type * as auth from "../auth.js";
import type * as constants from "../constants.js";
import type * as crons from "../crons.js";
import type * as flags from "../flags.js";
import type * as games from "../games.js";
import type * as http from "../http.js";
import type * as init from "../init.js";
import type * as leaderboard from "../leaderboard.js";
import type * as maps from "../maps.js";
import type * as models from "../models.js";
import type * as results from "../results.js";
import type * as scores from "../scores.js";
import type * as users from "../users.js";
Expand All @@ -37,11 +40,14 @@ import type * as users from "../users.js";
declare const fullApi: ApiFromModules<{
auth: typeof auth;
constants: typeof constants;
crons: typeof crons;
flags: typeof flags;
games: typeof games;
http: typeof http;
init: typeof init;
leaderboard: typeof leaderboard;
maps: typeof maps;
models: typeof models;
results: typeof results;
scores: typeof scores;
users: typeof users;
Expand Down
12 changes: 12 additions & 0 deletions convex/crons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { cronJobs } from "convex/server";
import { internal } from "./_generated/api";

const crons = cronJobs();

crons.interval(
"run games for all active models",
{ minutes: 60 },
internal.models.runActiveModelsGames,
);

export default crons;
Loading

0 comments on commit 474616f

Please sign in to comment.