mirror of
https://github.com/NousResearch/atropos.git
synced 2026-04-23 16:54:56 +00:00
Move to subfolder
This commit is contained in:
parent
a88e3afddf
commit
7eae51cc5c
23 changed files with 0 additions and 0 deletions
1
environments/hack0/DeepSacrifice/.env.template
Normal file
1
environments/hack0/DeepSacrifice/.env.template
Normal file
|
|
@ -0,0 +1 @@
|
|||
OPENAI_API_KEY=
|
||||
6
environments/hack0/DeepSacrifice/.gitignore
vendored
Normal file
6
environments/hack0/DeepSacrifice/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
node_modules
|
||||
dist
|
||||
.DS_Store
|
||||
*.md
|
||||
!README.md
|
||||
.env
|
||||
138
environments/hack0/DeepSacrifice/README.md
Normal file
138
environments/hack0/DeepSacrifice/README.md
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# DeepSacrifice
|
||||
|
||||
## Overview
|
||||
|
||||
DeepSacrifice is a **design prototype** for a lightweight **reinforcement learning (RL)** loop in a chess environment. The goal is to train an agent to play **aggressive**, **sacrificial**, and **attacking** chess using feedback from **direct human-vs-agent gameplay** and **post-game evaluations** by a language model (LLM).
|
||||
|
||||
The idea is that, over time, the agent will adapt its skill level to the user's skill level (and surpass it) while playing exclusively aggressive chess (e.g., sacrificing material for the initiative, attacking the king, luring the opponent to overextend).
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
- **Human-in-the-loop RL**: The user serves as the environment, directly interacting with the agent. Each complete game generates a full **trajectory** (sequence of states and actions), which is scored and used for learning.
|
||||
|
||||
- **LLM-based reward model**: The LLM acts as a **reward function**, scoring trajectories for **aggression**, **brilliance**, and **sacrifice justification**. This replaces sparse binary rewards with dense, informative feedback.
|
||||
|
||||
- **Policy improvement**: The agent's **policy** (its move-selection strategy) is updated based on **rewards** received at the end of each game, enabling **reinforcement learning** over time.
|
||||
|
||||
- **Exploration vs. Exploitation**: The agent balances exploring risky sacrifices versus exploiting known aggressive lines that have yielded high rewards in the past.
|
||||
|
||||
---
|
||||
|
||||
## Core Concepts
|
||||
|
||||
| RL Term | Implementation in DeepSacrifice |
|
||||
|----------------------|---------------------------------------------------------|
|
||||
| **State** | The chess board (FEN) at each ply |
|
||||
| **Action** | A legal move by the agent (SAN) |
|
||||
| **Trajectory** | Full game history of states and agent actions |
|
||||
| **Reward** | Post-game score from LLM: aggression, brilliance, win |
|
||||
| **Policy** | Move selection logic (with aggression weighting) |
|
||||
| **Learning** | Heuristic updates to parameters based on reward |
|
||||
| **Environment** | The human player and game loop |
|
||||
| **Episode** | A single completed chess game |
|
||||
|
||||
---
|
||||
|
||||
## Walkthrough
|
||||
|
||||
### 1) Start a new game
|
||||
|
||||

|
||||
|
||||
### 2) Play against an aggressive chess agent
|
||||
|
||||

|
||||
|
||||
### 3) Score the game with an LLM
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Learning Flow
|
||||
|
||||
1. **Game is played**
|
||||
The agent and user alternate actions in the chess environment. The episode ends when the game is complete.
|
||||
|
||||
2. **Trajectory is recorded**
|
||||
Log the full sequence of states (FENs) and agent actions (SANs), including sacrificial decisions and the final outcome (win/draw/loss).
|
||||
|
||||
3. **LLM evaluates the trajectory**
|
||||
After the episode, the trajectory is passed to an LLM, which provides dense feedback using a structured prompt:
|
||||
|
||||
> "Given the following chess game FEN history and SAN moves, evaluate each agent move for aggression/brilliance and sacrifice justification. Return a JSON array of scores and justifications."
|
||||
|
||||
4. **Reward is computed**
|
||||
The LLM scores are aggregated into a **scalar reward** using a weighted formula, incorporating:
|
||||
- Aggression
|
||||
- Brilliance
|
||||
- Game outcome
|
||||
|
||||
5. **Policy is updated**
|
||||
Based on the final reward, the agent performs **policy improvement** by adjusting its internal parameters:
|
||||
- Aggression threshold
|
||||
- Sacrifice prioritization
|
||||
- Move ordering or evaluation heuristics
|
||||
|
||||
6. **Next episode begins**
|
||||
The updated policy is used in the next game against the user, completing the **reinforcement loop**.
|
||||
|
||||
---
|
||||
|
||||
## Data Flow
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
User[User] -->|Makes move| Frontend
|
||||
Frontend -->|POST /api/move| API
|
||||
API -->|Get move| Agent
|
||||
Agent -->|Move| API
|
||||
API -->|Update| Frontend
|
||||
Frontend -->|Show board| User
|
||||
Frontend -->|Click 'Score Game'| API2[API /api/game/llm_feedback]
|
||||
API2 -->|Send FENs/SANs| LLM
|
||||
LLM -->|Scores/Justifies| API2
|
||||
API2 -->|Scored moves| Frontend
|
||||
Frontend -->|Show LLM feedback| User
|
||||
API2 -->|LLM feedback| Agent
|
||||
Agent -->|Update policy| Agent
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setup & Install
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Bun](https://bun.sh/) (package management, runtime)
|
||||
- [OpenAI API key](https://platform.openai.com/account/api-keys)
|
||||
|
||||
### Environment Setup
|
||||
|
||||
1. Copy the example environment file:
|
||||
```sh
|
||||
cp .env.template .env
|
||||
```
|
||||
2. Open `.env` and input your OpenAI API key for `OPENAI_API_KEY`.
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```sh
|
||||
bun install
|
||||
```
|
||||
|
||||
Now, open two terminals and run the following commands:
|
||||
|
||||
### Run the frontend
|
||||
|
||||
```sh
|
||||
bun dev
|
||||
```
|
||||
|
||||
### Run the backend
|
||||
|
||||
```sh
|
||||
bun dev:server
|
||||
```
|
||||
365
environments/hack0/DeepSacrifice/bun.lock
Normal file
365
environments/hack0/DeepSacrifice/bun.lock
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "deepsacrifice-frontend",
|
||||
"dependencies": {
|
||||
"chess.js": "^1.2.0",
|
||||
"chessground": "^8.2.2",
|
||||
"elysia": "^1.3.1",
|
||||
"openai": "^4.100.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^5.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||
|
||||
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
|
||||
|
||||
"@babel/compat-data": ["@babel/compat-data@7.27.2", "", {}, "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ=="],
|
||||
|
||||
"@babel/core": ["@babel/core@7.27.1", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.1", "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-module-transforms": "^7.27.1", "@babel/helpers": "^7.27.1", "@babel/parser": "^7.27.1", "@babel/template": "^7.27.1", "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ=="],
|
||||
|
||||
"@babel/generator": ["@babel/generator@7.27.1", "", { "dependencies": { "@babel/parser": "^7.27.1", "@babel/types": "^7.27.1", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w=="],
|
||||
|
||||
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
|
||||
|
||||
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
|
||||
|
||||
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g=="],
|
||||
|
||||
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
|
||||
|
||||
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
|
||||
|
||||
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
|
||||
|
||||
"@babel/helpers": ["@babel/helpers@7.27.1", "", { "dependencies": { "@babel/template": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ=="],
|
||||
|
||||
"@babel/parser": ["@babel/parser@7.27.2", "", { "dependencies": { "@babel/types": "^7.27.1" }, "bin": "./bin/babel-parser.js" }, "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw=="],
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
|
||||
|
||||
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
|
||||
|
||||
"@babel/traverse": ["@babel/traverse@7.27.1", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.1", "@babel/parser": "^7.27.1", "@babel/template": "^7.27.1", "@babel/types": "^7.27.1", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg=="],
|
||||
|
||||
"@babel/types": ["@babel/types@7.27.1", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q=="],
|
||||
|
||||
"@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="],
|
||||
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="],
|
||||
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="],
|
||||
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="],
|
||||
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="],
|
||||
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="],
|
||||
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.41.0", "", { "os": "android", "cpu": "arm" }, "sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.41.0", "", { "os": "android", "cpu": "arm64" }, "sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.41.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.41.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.41.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.41.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.41.0", "", { "os": "linux", "cpu": "arm" }, "sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.41.0", "", { "os": "linux", "cpu": "arm" }, "sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.41.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.41.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ=="],
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.41.0", "", { "os": "linux", "cpu": "none" }, "sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w=="],
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.41.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.41.0", "", { "os": "linux", "cpu": "none" }, "sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.41.0", "", { "os": "linux", "cpu": "none" }, "sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.41.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.41.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.41.0", "", { "os": "linux", "cpu": "x64" }, "sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.41.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.41.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.41.0", "", { "os": "win32", "cpu": "x64" }, "sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA=="],
|
||||
|
||||
"@sinclair/typebox": ["@sinclair/typebox@0.34.33", "", {}, "sha512-5HAV9exOMcXRUxo+9iYB5n09XxzCXnfy4VTNW4xnDv+FgjzAGY989C28BIdljKqmF+ZltUwujE3aossvcVtq6g=="],
|
||||
|
||||
"@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="],
|
||||
|
||||
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
|
||||
|
||||
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
||||
|
||||
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
|
||||
|
||||
"@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
|
||||
|
||||
"@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
||||
|
||||
"@types/node": ["@types/node@18.19.100", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-ojmMP8SZBKprc3qGrGk8Ujpo80AXkrP7G2tOT4VWr5jlr5DHjsJF+emXJz+Wm0glmy4Js62oKMdZZ6B9Y+tEcA=="],
|
||||
|
||||
"@types/node-fetch": ["@types/node-fetch@2.6.12", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.0" } }, "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA=="],
|
||||
|
||||
"@types/prop-types": ["@types/prop-types@15.7.14", "", {}, "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="],
|
||||
|
||||
"@types/react": ["@types/react@18.3.21", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-gXLBtmlcRJeT09/sI4PxVwyrku6SaNUj/6cMubjE6T6XdY1fDmBL7r0nX0jbSZPU/Xr0KuwLLZh6aOYY5d91Xw=="],
|
||||
|
||||
"@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="],
|
||||
|
||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.4.1", "", { "dependencies": { "@babel/core": "^7.26.10", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w=="],
|
||||
|
||||
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
|
||||
|
||||
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
|
||||
|
||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||
|
||||
"browserslist": ["browserslist@4.24.5", "", { "dependencies": { "caniuse-lite": "^1.0.30001716", "electron-to-chromium": "^1.5.149", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw=="],
|
||||
|
||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001718", "", {}, "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw=="],
|
||||
|
||||
"chess.js": ["chess.js@1.2.0", "", {}, "sha512-QWdfpAkMslQ48hDDoEzEko6GbYTAKKx4UdXAPEF8nFnAuqp+woyL8LHSbziRP8u1aMAbnlOF0YkXF4ui0Nsubg=="],
|
||||
|
||||
"chessground": ["chessground@8.4.0", "", {}, "sha512-0LPdp2Ln/EzeH/T63fDO4Hn9KcSExoMOqkgz3fPjPiY1mSHDBqVuU3drbctHIdorl6hkyQC3qZPMmNHYgZjnsA=="],
|
||||
|
||||
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
||||
|
||||
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||
|
||||
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||
|
||||
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.155", "", {}, "sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng=="],
|
||||
|
||||
"elysia": ["elysia@1.3.1", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-En41P6cDHcHtQ0nvfsn9ayB+8ahQJqG1nzvPX8FVZjOriFK/RtZPQBtXMfZDq/AsVIk7JFZGFEtAVEmztNJVhQ=="],
|
||||
|
||||
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||
|
||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||
|
||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||
|
||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
||||
|
||||
"esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
"event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
|
||||
|
||||
"exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="],
|
||||
|
||||
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
|
||||
|
||||
"fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
|
||||
|
||||
"file-type": ["file-type@20.5.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.6", "strtok3": "^10.2.0", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-BfHZtG/l9iMm4Ecianu7P8HRD2tBHLtjXinm4X62XBOYzi7CYA7jyqfJzOvXHqzVrVPYqBo2/GvbARMaaJkKVg=="],
|
||||
|
||||
"form-data": ["form-data@4.0.2", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" } }, "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w=="],
|
||||
|
||||
"form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="],
|
||||
|
||||
"formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||
|
||||
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||
|
||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||
|
||||
"globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
||||
|
||||
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||
|
||||
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||
|
||||
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
|
||||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
|
||||
|
||||
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||
|
||||
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||
|
||||
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
|
||||
|
||||
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||
|
||||
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
|
||||
|
||||
"openai": ["openai@4.100.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" }, "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-9soq/wukv3utxcuD7TWFqKdKp0INWdeyhUCvxwrne5KwnxaCp4eHL4GdT/tMFhYolxgNhxFzg5GFwM331Z5CZg=="],
|
||||
|
||||
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||
|
||||
"peek-readable": ["peek-readable@7.0.0", "", {}, "sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
||||
|
||||
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
|
||||
|
||||
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
|
||||
|
||||
"rollup": ["rollup@4.41.0", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.41.0", "@rollup/rollup-android-arm64": "4.41.0", "@rollup/rollup-darwin-arm64": "4.41.0", "@rollup/rollup-darwin-x64": "4.41.0", "@rollup/rollup-freebsd-arm64": "4.41.0", "@rollup/rollup-freebsd-x64": "4.41.0", "@rollup/rollup-linux-arm-gnueabihf": "4.41.0", "@rollup/rollup-linux-arm-musleabihf": "4.41.0", "@rollup/rollup-linux-arm64-gnu": "4.41.0", "@rollup/rollup-linux-arm64-musl": "4.41.0", "@rollup/rollup-linux-loongarch64-gnu": "4.41.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.41.0", "@rollup/rollup-linux-riscv64-gnu": "4.41.0", "@rollup/rollup-linux-riscv64-musl": "4.41.0", "@rollup/rollup-linux-s390x-gnu": "4.41.0", "@rollup/rollup-linux-x64-gnu": "4.41.0", "@rollup/rollup-linux-x64-musl": "4.41.0", "@rollup/rollup-win32-arm64-msvc": "4.41.0", "@rollup/rollup-win32-ia32-msvc": "4.41.0", "@rollup/rollup-win32-x64-msvc": "4.41.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg=="],
|
||||
|
||||
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
|
||||
|
||||
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"strtok3": ["strtok3@10.2.2", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^7.0.0" } }, "sha512-Xt18+h4s7Z8xyZ0tmBoRmzxcop97R4BAh+dXouUDCYn+Em+1P3qpkUfI5ueWLT8ynC5hZ+q4iPEmGG1urvQGBg=="],
|
||||
|
||||
"token-types": ["token-types@6.0.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA=="],
|
||||
|
||||
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"uint8array-extras": ["uint8array-extras@1.4.0", "", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="],
|
||||
|
||||
"undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
||||
|
||||
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
|
||||
|
||||
"vite": ["vite@5.4.19", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA=="],
|
||||
|
||||
"web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="],
|
||||
|
||||
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||
|
||||
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
||||
|
||||
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
}
|
||||
}
|
||||
BIN
environments/hack0/DeepSacrifice/images/ds-1.png
Normal file
BIN
environments/hack0/DeepSacrifice/images/ds-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 607 KiB |
BIN
environments/hack0/DeepSacrifice/images/ds-2.png
Normal file
BIN
environments/hack0/DeepSacrifice/images/ds-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 675 KiB |
BIN
environments/hack0/DeepSacrifice/images/ds-3.png
Normal file
BIN
environments/hack0/DeepSacrifice/images/ds-3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 756 KiB |
12
environments/hack0/DeepSacrifice/index.html
Normal file
12
environments/hack0/DeepSacrifice/index.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>DeepSacrifice</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
12
environments/hack0/DeepSacrifice/public/index.html
Normal file
12
environments/hack0/DeepSacrifice/public/index.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;700&family=IBM+Plex+Sans:wght@400;500;700&display=swap" rel="stylesheet" />
|
||||
<title>DeepSacrifice</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import { Chess } from "chess.js";
|
||||
|
||||
export function getAggressiveMove(
|
||||
fen: string,
|
||||
): { from: string; to: string } | null {
|
||||
const chess = new Chess(fen);
|
||||
const moves = chess.moves({ verbose: true });
|
||||
if (moves.length === 0) return null;
|
||||
|
||||
// Prefer captures
|
||||
const captures = moves.filter(
|
||||
(m) => m.flags.includes("c") || m.flags.includes("e"),
|
||||
);
|
||||
if (captures.length > 0) {
|
||||
const move = captures[Math.floor(Math.random() * captures.length)];
|
||||
return { from: move.from, to: move.to };
|
||||
}
|
||||
|
||||
// Prefer checks
|
||||
const checks = moves.filter((m) => {
|
||||
chess.move({ from: m.from, to: m.to });
|
||||
const isCheck = chess.inCheck();
|
||||
chess.undo();
|
||||
return isCheck;
|
||||
});
|
||||
if (checks.length > 0) {
|
||||
const move = checks[Math.floor(Math.random() * checks.length)];
|
||||
return { from: move.from, to: move.to };
|
||||
}
|
||||
|
||||
// Otherwise, pick random
|
||||
const move = moves[Math.floor(Math.random() * moves.length)];
|
||||
return { from: move.from, to: move.to };
|
||||
}
|
||||
|
||||
// Minimal AttackerAgent class with placeholder learning
|
||||
export class AttackerAgent {
|
||||
getMove(fen: string): { from: string; to: string } | null {
|
||||
return getAggressiveMove(fen);
|
||||
}
|
||||
|
||||
learnFromGame(gameData: any, llmFeedback: any): void {
|
||||
// TODO: Implement incremental learning from LLM feedback
|
||||
// For now, this is a placeholder
|
||||
}
|
||||
}
|
||||
149
environments/hack0/DeepSacrifice/server/api/serve.ts
Normal file
149
environments/hack0/DeepSacrifice/server/api/serve.ts
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
import { Elysia } from "elysia";
|
||||
import { getAggressiveMove } from "../agents/attacker_agent";
|
||||
import { ChessEnv } from "../env/chess_env";
|
||||
import { scoreAndJustifyGame } from "../llm/llm_feedback";
|
||||
import { computeReward } from "../reward/reward_fn";
|
||||
|
||||
const env = new ChessEnv();
|
||||
const games: any[] = [];
|
||||
let currentGame: any[] = [];
|
||||
|
||||
const app = new Elysia()
|
||||
.get("/ping", () => "pong")
|
||||
.get("/api/games/latest", () => games.slice(-5))
|
||||
.post("/api/move", async ({ body }) => {
|
||||
const { from, to, san, color } = body as {
|
||||
from: string;
|
||||
to: string;
|
||||
san?: string;
|
||||
color?: string;
|
||||
};
|
||||
const currentFen = env.getFEN();
|
||||
const currentColor = currentFen.split(" ")[1] === "b" ? "black" : "white";
|
||||
if (color && color !== currentColor) {
|
||||
return { error: `It's not ${color}'s turn.` };
|
||||
}
|
||||
// User move
|
||||
const { fen: userFen, done: userDone } = env.step({ from, to });
|
||||
const userMoveData = {
|
||||
fen: userFen,
|
||||
move: { from, to, san },
|
||||
reward: null, // Placeholder, to be filled after scoring
|
||||
llmFeedback: { score: null, justification: null },
|
||||
};
|
||||
currentGame.push(userMoveData);
|
||||
// If game is over after user move, return
|
||||
if (userDone) {
|
||||
games.push([...currentGame]);
|
||||
const moves = [...currentGame];
|
||||
currentGame = [];
|
||||
return {
|
||||
moves,
|
||||
done: true,
|
||||
};
|
||||
}
|
||||
// Agent move (as black)
|
||||
const agentMove = getAggressiveMove(userFen);
|
||||
let agentMoveData = null;
|
||||
let agentDone = false;
|
||||
if (agentMove) {
|
||||
const agentPrevFen = env.getFEN();
|
||||
const { fen: agentFen, done: agentIsDone } = env.step(agentMove);
|
||||
agentMoveData = {
|
||||
fen: agentFen,
|
||||
move: agentMove,
|
||||
reward: null, // Placeholder
|
||||
llmFeedback: { score: null, justification: null },
|
||||
};
|
||||
currentGame.push(agentMoveData);
|
||||
agentDone = agentIsDone;
|
||||
if (agentIsDone) {
|
||||
games.push([...currentGame]);
|
||||
const moves = [...currentGame];
|
||||
currentGame = [];
|
||||
return {
|
||||
moves,
|
||||
done: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
moves: [userMoveData, agentMoveData].filter(Boolean),
|
||||
done: agentDone,
|
||||
};
|
||||
})
|
||||
// .get("/evaluate", async () => {
|
||||
// const fen = env.getFEN();
|
||||
// const evalResult = await evaluatePosition(fen);
|
||||
// return evalResult;
|
||||
// })
|
||||
.post("/api/train/start", () => ({ started: true }))
|
||||
.get("/api/agent/status", () => ({ gamesPlayed: games.length, avgReward: 0 }))
|
||||
.post("/api/reset", () => {
|
||||
env.reset();
|
||||
currentGame.length = 0;
|
||||
return { fen: env.getFEN() };
|
||||
})
|
||||
.post("/api/game/llm_feedback", async ({ body }) => {
|
||||
// Expects: { moves: [{ fen, move: { from, to, san } }] }
|
||||
const { moves } = body as {
|
||||
moves: {
|
||||
fen: string;
|
||||
move: { from: string; to: string; san?: string };
|
||||
}[];
|
||||
};
|
||||
if (!Array.isArray(moves)) {
|
||||
return { error: "Missing or invalid moves array" };
|
||||
}
|
||||
const fenHistory = moves.map((m) => m.fen);
|
||||
const moveSANs = moves.map(
|
||||
(m) => m.move.san || `${m.move.from}-${m.move.to}`,
|
||||
);
|
||||
// Only score agent moves (even indices)
|
||||
const agentMoveIndices = moves
|
||||
.map((_, idx) => idx)
|
||||
.filter((idx) => idx % 2 === 1);
|
||||
const agentFens = agentMoveIndices.map((idx) => fenHistory[idx]);
|
||||
const agentSANs = agentMoveIndices.map((idx) => moveSANs[idx]);
|
||||
let feedbackArr = [];
|
||||
try {
|
||||
feedbackArr = await scoreAndJustifyGame(agentFens, agentSANs);
|
||||
} catch (e) {
|
||||
return { error: "LLM feedback failed", details: String(e) };
|
||||
}
|
||||
const scoredMoves = await Promise.all(
|
||||
moves.map(async (moveData, idx) => {
|
||||
if (idx % 2 === 1) {
|
||||
// Agent move: fill in feedback
|
||||
const { fen, move } = moveData;
|
||||
const moveSAN = String(move.san ?? `${move.from}-${move.to}`);
|
||||
const feedback = feedbackArr.shift() || {
|
||||
score: null,
|
||||
justification: null,
|
||||
};
|
||||
const reward = await computeReward(
|
||||
fen,
|
||||
moveSAN,
|
||||
feedback.score ?? "",
|
||||
feedback.justification ?? "",
|
||||
);
|
||||
return {
|
||||
...moveData,
|
||||
reward,
|
||||
llmFeedback: feedback,
|
||||
};
|
||||
} else {
|
||||
// User move: leave feedback/reward as null
|
||||
return {
|
||||
...moveData,
|
||||
reward: null,
|
||||
llmFeedback: { score: null, justification: null },
|
||||
};
|
||||
}
|
||||
}),
|
||||
);
|
||||
return { moves: scoredMoves };
|
||||
})
|
||||
.listen(3001);
|
||||
|
||||
console.log("API running on http://localhost:3001");
|
||||
76
environments/hack0/DeepSacrifice/server/llm/llm_feedback.ts
Normal file
76
environments/hack0/DeepSacrifice/server/llm/llm_feedback.ts
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* Placeholder for LLM-based move aggression/brilliance scoring.
|
||||
* Will use OpenAI GPT-4o-mini via callOpenAI in the future.
|
||||
*/
|
||||
import { callOpenAI } from "./openai_client";
|
||||
|
||||
export async function scoreMoveAggression(
|
||||
fenHistory: string[],
|
||||
moveIdx: number,
|
||||
moveSAN: string,
|
||||
): Promise<string> {
|
||||
const prompt = `Given the following chess game FEN history (one FEN per move):\n${fenHistory.map((f, i) => `${i + 1}: ${f}`).join("\n")}\nEvaluate the aggression or brilliance of move #${moveIdx + 1} (${moveSAN}). Respond ONLY with a single digit from 1 (not aggressive) to 10 (extremely aggressive/brilliant). Be fast and concise.`;
|
||||
const response = await callOpenAI(
|
||||
[
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are a chess grandmaster evaluating move aggression and brilliance. Respond as quickly and concisely as possible.",
|
||||
},
|
||||
{ role: "user", content: prompt },
|
||||
],
|
||||
16,
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder for LLM-based sacrifice justification.
|
||||
* Will use OpenAI GPT-4o-mini via callOpenAI in the future.
|
||||
*/
|
||||
export async function justifySacrifice(
|
||||
fenHistory: string[],
|
||||
moveIdx: number,
|
||||
moveSAN: string,
|
||||
): Promise<string> {
|
||||
const prompt = `Given the following chess game FEN history (one FEN per move):\n${fenHistory.map((f, i) => `${i + 1}: ${f}`).join("\n")}\nWas the sacrifice in move #${moveIdx + 1} (${moveSAN}) justified? Reply in 1 short sentence: is the sacrifice justified or not, and why. Be fast and concise.`;
|
||||
const response = await callOpenAI(
|
||||
[
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are a chess grandmaster evaluating sacrifices. Respond as quickly and concisely as possible.",
|
||||
},
|
||||
{ role: "user", content: prompt },
|
||||
],
|
||||
16,
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function scoreAndJustifyGame(
|
||||
fenHistory: string[],
|
||||
moveSANs: string[],
|
||||
): Promise<{ score: string; justification: string }[]> {
|
||||
const prompt = `Given the following chess game FEN history (one FEN per move) and the corresponding SAN moves, evaluate each move for aggression/brilliance and sacrifice justification.\n\nFEN history (one per move):\n${fenHistory.map((f, i) => `${i + 1}: ${f}`).join("\n")}\n\nSAN moves (one per move):\n${moveSANs.map((san, i) => `${i + 1}: ${san}`).join("\n")}\n\nFor each move, respond with a JSON array of objects, each with:\n- score: a single digit from 1 (not aggressive) to 10 (extremely aggressive/brilliant)\n- justification: 1 short sentence on whether the move is a justified sacrifice or not, and why.\n\nExample:\n[{"score": "7", "justification": "The sacrifice is risky but justified."}, ...]\n\nRespond ONLY with the JSON array, nothing else.`;
|
||||
const response = await callOpenAI(
|
||||
[
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are a chess grandmaster evaluating a full game for aggression and sacrifice justification. Respond as quickly and concisely as possible.",
|
||||
},
|
||||
{ role: "user", content: prompt },
|
||||
],
|
||||
512,
|
||||
);
|
||||
try {
|
||||
const parsed = JSON.parse(response);
|
||||
if (Array.isArray(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
throw new Error("Response is not an array");
|
||||
} catch (e) {
|
||||
throw new Error("Failed to parse LLM response as JSON: " + response);
|
||||
}
|
||||
}
|
||||
31
environments/hack0/DeepSacrifice/server/llm/openai_client.ts
Normal file
31
environments/hack0/DeepSacrifice/server/llm/openai_client.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* OpenAI API client for GPT-4o-mini feedback.
|
||||
* Expects to run in Bun/Node.js where process.env is available.
|
||||
* If you see a type error for 'process', install @types/node as a dev dependency.
|
||||
*/
|
||||
|
||||
import OpenAI from "openai";
|
||||
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY || "";
|
||||
const MODEL = "gpt-4o-mini"; // Use gpt-4o-mini if available, else gpt-4o
|
||||
|
||||
if (!OPENAI_API_KEY) {
|
||||
throw new Error("OPENAI_API_KEY is not set");
|
||||
}
|
||||
|
||||
const openai = new OpenAI({ apiKey: OPENAI_API_KEY });
|
||||
|
||||
export async function callOpenAI(
|
||||
messages: ChatCompletionMessageParam[],
|
||||
max_tokens = 64,
|
||||
): Promise<string> {
|
||||
const response = await openai.chat.completions.create({
|
||||
model: MODEL,
|
||||
messages,
|
||||
max_tokens,
|
||||
});
|
||||
const content = response.choices[0]?.message?.content;
|
||||
if (!content) throw new Error("No content returned from OpenAI");
|
||||
return content.trim();
|
||||
}
|
||||
14
environments/hack0/DeepSacrifice/server/reward/reward_fn.ts
Normal file
14
environments/hack0/DeepSacrifice/server/reward/reward_fn.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Placeholder reward function using LLM feedback.
|
||||
* Will use OpenAI GPT-4o-mini feedback in the future.
|
||||
*/
|
||||
export async function computeReward(
|
||||
fen: string,
|
||||
moveSAN: string,
|
||||
llmScore?: string,
|
||||
llmJustification?: string,
|
||||
): Promise<number> {
|
||||
// TODO: Use real LLM feedback to compute reward
|
||||
// For now, return a dummy reward
|
||||
return 0.5;
|
||||
}
|
||||
18
environments/hack0/DeepSacrifice/server/runner/async_loop.ts
Normal file
18
environments/hack0/DeepSacrifice/server/runner/async_loop.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { getAggressiveMove } from "../agents/attacker_agent";
|
||||
import { ChessEnv } from "../env/chess_env";
|
||||
|
||||
export async function runTrainingLoop(episodes = 1) {
|
||||
const env = new ChessEnv();
|
||||
for (let ep = 0; ep < episodes; ep++) {
|
||||
env.reset();
|
||||
let done = false;
|
||||
while (!done) {
|
||||
const move = getAggressiveMove(env.getFEN());
|
||||
if (!move) break;
|
||||
const { done: isDone } = env.step(move);
|
||||
done = isDone;
|
||||
}
|
||||
// Log or store game
|
||||
console.log(`Episode ${ep + 1} finished. FEN: ${env.getFEN()}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import { Chess } from "chess.js";
|
||||
import { AttackerAgent } from "../agents/attacker_agent";
|
||||
import { ChessEnv } from "../env/chess_env";
|
||||
|
||||
// Simulate user move by picking a random legal move
|
||||
function getRandomUserMove(fen: string): { from: string; to: string } | null {
|
||||
const chess = new Chess(fen);
|
||||
const moves = chess.moves({ verbose: true });
|
||||
if (moves.length === 0) return null;
|
||||
const move = moves[Math.floor(Math.random() * moves.length)];
|
||||
return { from: move.from, to: move.to };
|
||||
}
|
||||
|
||||
export async function runUserVsAgentGame() {
|
||||
const env = new ChessEnv();
|
||||
const agent = new AttackerAgent();
|
||||
let done = false;
|
||||
let moveCount = 0;
|
||||
let fen = env.reset();
|
||||
let userTurn = true;
|
||||
const gameData: any[] = [];
|
||||
|
||||
while (!done && moveCount < 100) {
|
||||
let move;
|
||||
let player;
|
||||
if (userTurn) {
|
||||
move = getRandomUserMove(fen); // Placeholder for real user input
|
||||
player = "user";
|
||||
console.log(`User move:`, move);
|
||||
} else {
|
||||
move = agent.getMove(fen);
|
||||
player = "agent";
|
||||
console.log(`Agent move:`, move);
|
||||
}
|
||||
if (!move) break;
|
||||
// Placeholder for LLM feedback (to be replaced with real call)
|
||||
const llmFeedback = { score: 7, justification: "Placeholder feedback" };
|
||||
const { fen: newFen, reward, done: isDone } = env.step(move);
|
||||
moveCount++;
|
||||
gameData.push({
|
||||
moveNumber: moveCount,
|
||||
player,
|
||||
move,
|
||||
fen: newFen,
|
||||
reward,
|
||||
llmFeedback,
|
||||
});
|
||||
console.log("FEN:", newFen);
|
||||
console.log("Reward:", reward);
|
||||
fen = newFen;
|
||||
done = isDone;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
console.log(`User-vs-Agent game finished after ${moveCount} moves.`);
|
||||
console.log("Game data:", gameData);
|
||||
}
|
||||
|
||||
// If run directly, play a game
|
||||
(async () => {
|
||||
await runUserVsAgentGame();
|
||||
})();
|
||||
16
environments/hack0/DeepSacrifice/src/api/client.ts
Normal file
16
environments/hack0/DeepSacrifice/src/api/client.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// API client for DeepSacrifice frontend
|
||||
|
||||
export async function fetchLatestGames() {
|
||||
// TODO: Replace with real fetch
|
||||
return [{ fen: "startpos", moves: [] }];
|
||||
}
|
||||
|
||||
export async function fetchAgentStatus() {
|
||||
// TODO: Replace with real fetch
|
||||
return { gamesPlayed: 0, avgReward: 0 };
|
||||
}
|
||||
|
||||
export async function startTraining() {
|
||||
// TODO: Replace with real POST
|
||||
return { started: true };
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import { Chess } from "chess.js";
|
||||
import { Chessground } from "chessground";
|
||||
import type React from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import "./chessground.css";
|
||||
|
||||
interface ChessBoardProps {
|
||||
fen: string;
|
||||
onMove?: (from: string, to: string) => void;
|
||||
userTurn: boolean;
|
||||
}
|
||||
|
||||
function getTurnColor(fen: string): "white" | "black" {
|
||||
const parts = fen.split(" ");
|
||||
return parts[1] === "b" ? "black" : "white";
|
||||
}
|
||||
|
||||
function allSquares(): string[] {
|
||||
const files = "abcdefgh";
|
||||
const ranks = "12345678";
|
||||
const squares: string[] = [];
|
||||
for (let f = 0; f < 8; f++) {
|
||||
for (let r = 0; r < 8; r++) {
|
||||
squares.push(files[f] + ranks[r]);
|
||||
}
|
||||
}
|
||||
return squares;
|
||||
}
|
||||
|
||||
function getDests(fen: string) {
|
||||
const chess = new Chess(fen);
|
||||
const dests: Record<string, string[]> = {};
|
||||
allSquares().forEach((sqr) => {
|
||||
const moves = chess.moves({ square: sqr as any, verbose: true });
|
||||
if (moves.length) dests[sqr] = moves.map((m: any) => m.to);
|
||||
});
|
||||
// Chessground expects a Map
|
||||
return new Map(Object.entries(dests));
|
||||
}
|
||||
|
||||
const ChessBoard: React.FC<ChessBoardProps> = ({ fen, onMove, userTurn }) => {
|
||||
const boardRef = useRef<HTMLDivElement>(null);
|
||||
const groundRef = useRef<any>(null);
|
||||
const color = getTurnColor(fen);
|
||||
const dests = getDests(fen);
|
||||
|
||||
useEffect(() => {
|
||||
if (boardRef.current) {
|
||||
if (!groundRef.current) {
|
||||
groundRef.current = Chessground(boardRef.current, {
|
||||
fen,
|
||||
orientation: "white",
|
||||
turnColor: color,
|
||||
movable: {
|
||||
color,
|
||||
dests: dests as any,
|
||||
free: false,
|
||||
events: {
|
||||
after: (orig: string, dest: string) => {
|
||||
if (onMove && userTurn) onMove(orig, dest);
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
groundRef.current.set({
|
||||
fen,
|
||||
turnColor: color,
|
||||
orientation: "white",
|
||||
movable: {
|
||||
color,
|
||||
dests: dests as any,
|
||||
free: false,
|
||||
events: {
|
||||
after: (orig: string, dest: string) => {
|
||||
if (onMove && userTurn) onMove(orig, dest);
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [
|
||||
fen,
|
||||
onMove,
|
||||
color,
|
||||
userTurn,
|
||||
JSON.stringify(Array.from(dests.entries())),
|
||||
]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={boardRef}
|
||||
style={{ width: 400, height: 400 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChessBoard;
|
||||
289
environments/hack0/DeepSacrifice/src/components/chessground.css
Normal file
289
environments/hack0/DeepSacrifice/src/components/chessground.css
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
.cg-wrap {
|
||||
box-sizing: content-box;
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
|
||||
cg-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
cg-board {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
line-height: 0;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.cg-wrap.manipulable cg-board {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
cg-board square {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 12.5%;
|
||||
height: 12.5%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
cg-board square.move-dest {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
cg-board square.last-move {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.cg-wrap piece {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 12.5%;
|
||||
height: 12.5%;
|
||||
background-size: cover;
|
||||
z-index: 2;
|
||||
will-change: transform;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
cg-board piece.dragging {
|
||||
cursor: move;
|
||||
/* !important to override z-index from 3D piece inline style */
|
||||
z-index: 11 !important;
|
||||
}
|
||||
|
||||
piece.anim {
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
piece.fading {
|
||||
z-index: 1;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.cg-wrap piece.ghost {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.cg-wrap piece svg {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.cg-wrap cg-auto-pieces,
|
||||
.cg-wrap .cg-shapes,
|
||||
.cg-wrap .cg-custom-svgs {
|
||||
overflow: visible;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.cg-wrap cg-auto-pieces {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.cg-wrap cg-auto-pieces piece {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.cg-wrap .cg-shapes {
|
||||
overflow: hidden;
|
||||
opacity: 0.6;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.cg-wrap .cg-custom-svgs {
|
||||
/* over piece.anim = 8, but under piece.dragging = 11 */
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.cg-wrap .cg-custom-svgs svg {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.cg-wrap coords {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
pointer-events: none;
|
||||
opacity: 0.8;
|
||||
font-family: sans-serif;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.cg-wrap coords.ranks {
|
||||
left: 4px;
|
||||
top: -20px;
|
||||
flex-flow: column-reverse;
|
||||
height: 100%;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.cg-wrap coords.ranks.black {
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
.cg-wrap coords.ranks.left {
|
||||
left: -15px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.cg-wrap coords.files {
|
||||
bottom: -4px;
|
||||
left: 24px;
|
||||
flex-flow: row;
|
||||
width: 100%;
|
||||
height: 16px;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cg-wrap coords.files.black {
|
||||
flex-flow: row-reverse;
|
||||
}
|
||||
|
||||
.cg-wrap coords coord {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.cg-wrap coords.ranks coord {
|
||||
transform: translateY(39%);
|
||||
}
|
||||
|
||||
/** Colored board squares as an embedded SVG */
|
||||
cg-board {
|
||||
background-color: #f0d9b5;
|
||||
background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4PSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICAgIHZpZXdCb3g9IjAgMCA4IDgiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+CjxnIGlkPSJhIj4KICA8ZyBpZD0iYiI+CiAgICA8ZyBpZD0iYyI+CiAgICAgIDxnIGlkPSJkIj4KICAgICAgICA8cmVjdCB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBpZD0iZSIgb3BhY2l0eT0iMCIvPgogICAgICAgIDx1c2UgeD0iMSIgeT0iMSIgaHJlZj0iI2UiIHg6aHJlZj0iI2UiLz4KICAgICAgICA8cmVjdCB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBpZD0iZiIgb3BhY2l0eT0iMC4yIi8+CiAgICAgICAgPHVzZSB4PSIxIiB5PSItMSIgaHJlZj0iI2YiIHg6aHJlZj0iI2YiLz4KICAgICAgPC9nPgogICAgICA8dXNlIHg9IjIiIGhyZWY9IiNkIiB4OmhyZWY9IiNkIi8+CiAgICA8L2c+CiAgICA8dXNlIHg9IjQiIGhyZWY9IiNjIiB4OmhyZWY9IiNjIi8+CiAgPC9nPgogIDx1c2UgeT0iMiIgaHJlZj0iI2IiIHg6aHJlZj0iI2IiLz4KPC9nPgo8dXNlIHk9IjQiIGhyZWY9IiNhIiB4OmhyZWY9IiNhIi8+Cjwvc3ZnPg==");
|
||||
}
|
||||
|
||||
/** Interactive board square colors */
|
||||
cg-board square.move-dest {
|
||||
background: radial-gradient(
|
||||
rgba(20, 85, 30, 0.5) 22%,
|
||||
#208530 0,
|
||||
rgba(0, 0, 0, 0.3) 0,
|
||||
rgba(0, 0, 0, 0) 0
|
||||
);
|
||||
}
|
||||
cg-board square.premove-dest {
|
||||
background: radial-gradient(
|
||||
rgba(20, 30, 85, 0.5) 22%,
|
||||
#203085 0,
|
||||
rgba(0, 0, 0, 0.3) 0,
|
||||
rgba(0, 0, 0, 0) 0
|
||||
);
|
||||
}
|
||||
cg-board square.oc.move-dest {
|
||||
background: radial-gradient(
|
||||
transparent 0%,
|
||||
transparent 80%,
|
||||
rgba(20, 85, 0, 0.3) 80%
|
||||
);
|
||||
}
|
||||
cg-board square.oc.premove-dest {
|
||||
background: radial-gradient(
|
||||
transparent 0%,
|
||||
transparent 80%,
|
||||
rgba(20, 30, 85, 0.2) 80%
|
||||
);
|
||||
}
|
||||
cg-board square.move-dest:hover {
|
||||
background: rgba(20, 85, 30, 0.3);
|
||||
}
|
||||
cg-board square.premove-dest:hover {
|
||||
background: rgba(20, 30, 85, 0.2);
|
||||
}
|
||||
cg-board square.last-move {
|
||||
background-color: rgba(155, 199, 0, 0.41);
|
||||
}
|
||||
cg-board square.selected {
|
||||
background-color: rgba(20, 85, 30, 0.5);
|
||||
}
|
||||
cg-board square.check {
|
||||
background: radial-gradient(
|
||||
ellipse at center,
|
||||
rgba(255, 0, 0, 1) 0%,
|
||||
rgba(231, 0, 0, 1) 25%,
|
||||
rgba(169, 0, 0, 0) 89%,
|
||||
rgba(158, 0, 0, 0) 100%
|
||||
);
|
||||
}
|
||||
cg-board square.current-premove {
|
||||
background-color: rgba(20, 30, 85, 0.5);
|
||||
}
|
||||
|
||||
/** Alternating colors in rank/file labels */
|
||||
.cg-wrap.orientation-white coords.ranks coord:nth-child(2n),
|
||||
.cg-wrap.orientation-white coords.files coord:nth-child(2n),
|
||||
.cg-wrap.orientation-black coords.ranks coord:nth-child(2n + 1),
|
||||
.cg-wrap.orientation-black coords.files coord:nth-child(2n + 1) {
|
||||
color: rgba(72, 72, 72, 0.8);
|
||||
}
|
||||
|
||||
.cg-wrap.orientation-black coords.ranks coord:nth-child(2n),
|
||||
.cg-wrap.orientation-black coords.files coord:nth-child(2n),
|
||||
.cg-wrap.orientation-white coords.ranks coord:nth-child(2n + 1),
|
||||
.cg-wrap.orientation-white coords.files coord:nth-child(2n + 1) {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
/** Embedded SVGs for all chess pieces */
|
||||
.cg-wrap piece.pawn.white {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PHBhdGggZD0iTTIyLjUgOWMtMi4yMSAwLTQgMS43OS00IDQgMCAuODkuMjkgMS43MS43OCAyLjM4QzE3LjMzIDE2LjUgMTYgMTguNTkgMTYgMjFjMCAyLjAzLjk0IDMuODQgMi40MSA1LjAzLTMgMS4wNi03LjQxIDUuNTUtNy40MSAxMy40N2gyM2MwLTcuOTItNC40MS0xMi40MS03LjQxLTEzLjQ3IDEuNDctMS4xOSAyLjQxLTMgMi40MS01LjAzIDAtMi40MS0xLjMzLTQuNS0zLjI4LTUuNjIuNDktLjY3Ljc4LTEuNDkuNzgtMi4zOCAwLTIuMjEtMS43OS00LTQtNHoiIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==");
|
||||
}
|
||||
.cg-wrap piece.bishop.white {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxnIGZpbGw9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJidXR0Ij48cGF0aCBkPSJNOSAzNmMzLjM5LS45NyAxMC4xMS40MyAxMy41LTIgMy4zOSAyLjQzIDEwLjExIDEuMDMgMTMuNSAyIDAgMCAxLjY1LjU0IDMgMi0uNjguOTctMS42NS45OS0zIC41LTMuMzktLjk3LTEwLjExLjQ2LTEzLjUtMS0zLjM5IDEuNDYtMTAuMTEuMDMtMTMuNSAxLTEuMzU0LjQ5LTIuMzIzLjQ3LTMtLjUgMS4zNTQtMS45NCAzLTIgMy0yeiIvPjxwYXRoIGQ9Ik0xNSAzMmMyLjUgMi41IDEyLjUgMi41IDE1IDAgLjUtMS41IDAtMiAwLTIgMC0yLjUtMi41LTQtMi41LTQgNS41LTEuNSA2LTExLjUtNS0xNS41LTExIDQtMTAuNSAxNC01IDE1LjUgMCAwLTIuNSAxLjUtMi41IDQgMCAwLS41LjUgMCAyeiIvPjxwYXRoIGQ9Ik0yNSA4YTIuNSAyLjUgMCAxIDEtNSAwIDIuNSAyLjUgMCAxIDEgNSAweiIvPjwvZz48cGF0aCBkPSJNMTcuNSAyNmgxME0xNSAzMGgxNW0tNy41LTE0LjV2NU0yMCAxOGg1IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIi8+PC9nPjwvc3ZnPg==");
|
||||
}
|
||||
.cg-wrap piece.knight.white {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMiAxMGMxMC41IDEgMTYuNSA4IDE2IDI5SDE1YzAtOSAxMC02LjUgOC0yMSIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0yNCAxOGMuMzggMi45MS01LjU1IDcuMzctOCA5LTMgMi0yLjgyIDQuMzQtNSA0LTEuMDQyLS45NCAxLjQxLTMuMDQgMC0zLTEgMCAuMTkgMS4yMy0xIDItMSAwLTQuMDAzIDEtNC00IDAtMiA2LTEyIDYtMTJzMS44OS0xLjkgMi0zLjVjLS43My0uOTk0LS41LTItLjUtMyAxLTEgMyAyLjUgMyAyLjVoMnMuNzgtMS45OTIgMi41LTNjMSAwIDEgMyAxIDMiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNOS41IDI1LjVhLjUuNSAwIDEgMS0xIDAgLjUuNSAwIDEgMSAxIDB6bTUuNDMzLTkuNzVhLjUgMS41IDMwIDEgMS0uODY2LS41LjUgMS41IDMwIDEgMSAuODY2LjV6IiBmaWxsPSIjMDAwIi8+PC9nPjwvc3ZnPg==");
|
||||
}
|
||||
.cg-wrap piece.rook.white {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik05IDM5aDI3di0zSDl2M3ptMy0zdi00aDIxdjRIMTJ6bS0xLTIyVjloNHYyaDVWOWg1djJoNVY5aDR2NSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzQgMTRsLTMgM0gxNGwtMy0zIi8+PHBhdGggZD0iTTMxIDE3djEyLjVIMTRWMTciIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIi8+PHBhdGggZD0iTTMxIDI5LjVsMS41IDIuNWgtMjBsMS41LTIuNSIvPjxwYXRoIGQ9Ik0xMSAxNGgyMyIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIvPjwvZz48L3N2Zz4=");
|
||||
}
|
||||
.cg-wrap piece.queen.white {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik04IDEyYTIgMiAwIDEgMS00IDAgMiAyIDAgMSAxIDQgMHptMTYuNS00LjVhMiAyIDAgMSAxLTQgMCAyIDIgMCAxIDEgNCAwek00MSAxMmEyIDIgMCAxIDEtNCAwIDIgMiAwIDEgMSA0IDB6TTE2IDguNWEyIDIgMCAxIDEtNCAwIDIgMiAwIDEgMSA0IDB6TTMzIDlhMiAyIDAgMSAxLTQgMCAyIDIgMCAxIDEgNCAweiIvPjxwYXRoIGQ9Ik05IDI2YzguNS0xLjUgMjEtMS41IDI3IDBsMi0xMi03IDExVjExbC01LjUgMTMuNS0zLTE1LTMgMTUtNS41LTE0VjI1TDcgMTRsMiAxMnoiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTkgMjZjMCAyIDEuNSAyIDIuNSA0IDEgMS41IDEgMSAuNSAzLjUtMS41IDEtMS41IDIuNS0xLjUgMi41LTEuNSAxLjUuNSAyLjUuNSAyLjUgNi41IDEgMTYuNSAxIDIzIDAgMCAwIDEuNS0xIDAtMi41IDAgMCAuNS0xLjUtMS0yLjUtLjUtMi41LS41LTIgLjUtMy41IDEtMiAyLjUtMiAyLjUtNC04LjUtMS41LTE4LjUtMS41LTI3IDB6IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xMS41IDMwYzMuNS0xIDE4LjUtMSAyMiAwTTEyIDMzLjVjNi0xIDE1LTEgMjEgMCIgZmlsbD0ibm9uZSIvPjwvZz48L3N2Zz4=");
|
||||
}
|
||||
.cg-wrap piece.king.white {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMi41IDExLjYzVjZNMjAgOGg1IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIi8+PHBhdGggZD0iTTIyLjUgMjVzNC41LTcuNSAzLTEwLjVjMCAwLTEtMi41LTMtMi41cy0zIDIuNS0zIDIuNWMtMS41IDMgMyAxMC41IDMgMTAuNSIgZmlsbD0iI2ZmZiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiLz48cGF0aCBkPSJNMTEuNSAzN2M1LjUgMy41IDE1LjUgMy41IDIxIDB2LTdzOS00LjUgNi0xMC41Yy00LTYuNS0xMy41LTMuNS0xNiA0VjI3di0zLjVjLTMuNS03LjUtMTMtMTAuNS0xNi00LTMgNiA1IDEwIDUgMTBWMzd6IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTExLjUgMzBjNS41LTMgMTUuNS0zIDIxIDBtLTIxIDMuNWM1LjUtMyAxNS41LTMgMjEgMG0tMjEgMy41YzUuNS0zIDE1LjUtMyAyMSAwIi8+PC9nPjwvc3ZnPg==");
|
||||
}
|
||||
.cg-wrap piece.pawn.black {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PHBhdGggZD0iTTIyLjUgOWMtMi4yMSAwLTQgMS43OS00IDQgMCAuODkuMjkgMS43MS43OCAyLjM4QzE3LjMzIDE2LjUgMTYgMTguNTkgMTYgMjFjMCAyLjAzLjk0IDMuODQgMi40MSA1LjAzLTMgMS4wNi03LjQxIDUuNTUtNy40MSAxMy40N2gyM2MwLTcuOTItNC40MS0xMi40MS03LjQxLTEzLjQ3IDEuNDctMS4xOSAyLjQxLTMgMi40MS01LjAzIDAtMi40MS0xLjMzLTQuNS0zLjI4LTUuNjIuNDktLjY3Ljc4LTEuNDkuNzgtMi4zOCAwLTIuMjEtMS43OS00LTQtNHoiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==");
|
||||
}
|
||||
.cg-wrap piece.bishop.black {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxnIGZpbGw9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJidXR0Ij48cGF0aCBkPSJNOSAzNmMzLjM5LS45NyAxMC4xMS40MyAxMy41LTIgMy4zOSAyLjQzIDEwLjExIDEuMDMgMTMuNSAyIDAgMCAxLjY1LjU0IDMgMi0uNjguOTctMS42NS45OS0zIC41LTMuMzktLjk3LTEwLjExLjQ2LTEzLjUtMS0zLjM5IDEuNDYtMTAuMTEuMDMtMTMuNSAxLTEuMzU0LjQ5LTIuMzIzLjQ3LTMtLjUgMS4zNTQtMS45NCAzLTIgMy0yeiIvPjxwYXRoIGQ9Ik0xNSAzMmMyLjUgMi41IDEyLjUgMi41IDE1IDAgLjUtMS41IDAtMiAwLTIgMC0yLjUtMi41LTQtMi41LTQgNS41LTEuNSA2LTExLjUtNS0xNS41LTExIDQtMTAuNSAxNC01IDE1LjUgMCAwLTIuNSAxLjUtMi41IDQgMCAwLS41LjUgMCAyeiIvPjxwYXRoIGQ9Ik0yNSA4YTIuNSAyLjUgMCAxIDEtNSAwIDIuNSAyLjUgMCAxIDEgNSAweiIvPjwvZz48cGF0aCBkPSJNMTcuNSAyNmgxME0xNSAzMGgxNW0tNy41LTE0LjV2NU0yMCAxOGg1IiBzdHJva2U9IiNlY2VjZWMiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiLz48L2c+PC9zdmc+");
|
||||
}
|
||||
.cg-wrap piece.knight.black {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMiAxMGMxMC41IDEgMTYuNSA4IDE2IDI5SDE1YzAtOSAxMC02LjUgOC0yMSIgZmlsbD0iIzAwMCIvPjxwYXRoIGQ9Ik0yNCAxOGMuMzggMi45MS01LjU1IDcuMzctOCA5LTMgMi0yLjgyIDQuMzQtNSA0LTEuMDQyLS45NCAxLjQxLTMuMDQgMC0zLTEgMCAuMTkgMS4yMy0xIDItMSAwLTQuMDAzIDEtNC00IDAtMiA2LTEyIDYtMTJzMS44OS0xLjkgMi0zLjVjLS43My0uOTk0LS41LTItLjUtMyAxLTEgMyAyLjUgMyAyLjVoMnMuNzgtMS45OTIgMi41LTNjMSAwIDEgMyAxIDMiIGZpbGw9IiMwMDAiLz48cGF0aCBkPSJNOS41IDI1LjVhLjUuNSAwIDEgMS0xIDAgLjUuNSAwIDEgMSAxIDB6bTUuNDMzLTkuNzVhLjUgMS41IDMwIDEgMS0uODY2LS41LjUgMS41IDMwIDEgMSAuODY2LjV6IiBmaWxsPSIjZWNlY2VjIiBzdHJva2U9IiNlY2VjZWMiLz48cGF0aCBkPSJNMjQuNTUgMTAuNGwtLjQ1IDEuNDUuNS4xNWMzLjE1IDEgNS42NSAyLjQ5IDcuOSA2Ljc1UzM1Ljc1IDI5LjA2IDM1LjI1IDM5bC0uMDUuNWgyLjI1bC4wNS0uNWMuNS0xMC4wNi0uODgtMTYuODUtMy4yNS0yMS4zNC0yLjM3LTQuNDktNS43OS02LjY0LTkuMTktNy4xNmwtLjUxLS4xeiIgZmlsbD0iI2VjZWNlYyIgc3Ryb2tlPSJub25lIi8+PC9nPjwvc3ZnPg==");
|
||||
}
|
||||
.cg-wrap piece.rook.black {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik05IDM5aDI3di0zSDl2M3ptMy41LTdsMS41LTIuNWgxN2wxLjUgMi41aC0yMHptLS41IDR2LTRoMjF2NEgxMnoiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTE0IDI5LjV2LTEzaDE3djEzSDE0eiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiLz48cGF0aCBkPSJNMTQgMTYuNUwxMSAxNGgyM2wtMyAyLjVIMTR6TTExIDE0VjloNHYyaDVWOWg1djJoNVY5aDR2NUgxMXoiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTEyIDM1LjVoMjFtLTIwLTRoMTltLTE4LTJoMTdtLTE3LTEzaDE3TTExIDE0aDIzIiBmaWxsPSJub25lIiBzdHJva2U9IiNlY2VjZWMiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIvPjwvZz48L3N2Zz4=");
|
||||
}
|
||||
.cg-wrap piece.queen.black {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxnIHN0cm9rZT0ibm9uZSI+PGNpcmNsZSBjeD0iNiIgY3k9IjEyIiByPSIyLjc1Ii8+PGNpcmNsZSBjeD0iMTQiIGN5PSI5IiByPSIyLjc1Ii8+PGNpcmNsZSBjeD0iMjIuNSIgY3k9IjgiIHI9IjIuNzUiLz48Y2lyY2xlIGN4PSIzMSIgY3k9IjkiIHI9IjIuNzUiLz48Y2lyY2xlIGN4PSIzOSIgY3k9IjEyIiByPSIyLjc1Ii8+PC9nPjxwYXRoIGQ9Ik05IDI2YzguNS0xLjUgMjEtMS41IDI3IDBsMi41LTEyLjVMMzEgMjVsLS4zLTE0LjEtNS4yIDEzLjYtMy0xNC41LTMgMTQuNS01LjItMTMuNkwxNCAyNSA2LjUgMTMuNSA5IDI2eiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNOSAyNmMwIDIgMS41IDIgMi41IDQgMSAxLjUgMSAxIC41IDMuNS0xLjUgMS0xLjUgMi41LTEuNSAyLjUtMS41IDEuNS41IDIuNS41IDIuNSA2LjUgMSAxNi41IDEgMjMgMCAwIDAgMS41LTEgMC0yLjUgMCAwIC41LTEuNS0xLTIuNS0uNS0yLjUtLjUtMiAuNS0zLjUgMS0yIDIuNS0yIDIuNS00LTguNS0xLjUtMTguNS0xLjUtMjcgMHoiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTExIDM4LjVhMzUgMzUgMSAwIDAgMjMgMCIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTEgMjlhMzUgMzUgMSAwIDEgMjMgMG0tMjEuNSAyLjVoMjBtLTIxIDNhMzUgMzUgMSAwIDAgMjIgMG0tMjMgM2EzNSAzNSAxIDAgMCAyNCAwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlY2VjZWMiLz48L2c+PC9zdmc+");
|
||||
}
|
||||
.cg-wrap piece.king.black {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMi41IDExLjYzVjYiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiLz48cGF0aCBkPSJNMjIuNSAyNXM0LjUtNy41IDMtMTAuNWMwIDAtMS0yLjUtMy0yLjVzLTMgMi41LTMgMi41Yy0xLjUgMyAzIDEwLjUgMyAxMC41IiBmaWxsPSIjMDAwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIvPjxwYXRoIGQ9Ik0xMS41IDM3YzUuNSAzLjUgMTUuNSAzLjUgMjEgMHYtN3M5LTQuNSA2LTEwLjVjLTQtNi41LTEzLjUtMy41LTE2IDRWMjd2LTMuNWMtMy41LTcuNS0xMy0xMC41LTE2LTQtMyA2IDUgMTAgNSAxMFYzN3oiIGZpbGw9IiMwMDAiLz48cGF0aCBkPSJNMjAgOGg1IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIi8+PHBhdGggZD0iTTMyIDI5LjVzOC41LTQgNi4wMy05LjY1QzM0LjE1IDE0IDI1IDE4IDIyLjUgMjQuNWwuMDEgMi4xLS4wMS0yLjFDMjAgMTggOS45MDYgMTQgNi45OTcgMTkuODVjLTIuNDk3IDUuNjUgNC44NTMgOSA0Ljg1MyA5IiBzdHJva2U9IiNlY2VjZWMiLz48cGF0aCBkPSJNMTEuNSAzMGM1LjUtMyAxNS41LTMgMjEgMG0tMjEgMy41YzUuNS0zIDE1LjUtMyAyMSAwbS0yMSAzLjVjNS41LTMgMTUuNS0zIDIxIDAiIHN0cm9rZT0iI2VjZWNlYyIvPjwvZz48L3N2Zz4=");
|
||||
}
|
||||
18
environments/hack0/DeepSacrifice/src/index.css
Normal file
18
environments/hack0/DeepSacrifice/src/index.css
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* IBM Plex Sans for body, IBM Plex Mono for code/pre/monospace */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "IBM Plex Sans", Arial, sans-serif;
|
||||
}
|
||||
|
||||
code,
|
||||
pre,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, "Liberation Mono",
|
||||
Menlo, monospace;
|
||||
}
|
||||
16
environments/hack0/DeepSacrifice/src/main.tsx
Normal file
16
environments/hack0/DeepSacrifice/src/main.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import "./index.css";
|
||||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import GameView from "./pages/GameView";
|
||||
|
||||
const rootElement = document.getElementById("root");
|
||||
if (!rootElement) {
|
||||
throw new Error("Root element not found");
|
||||
}
|
||||
|
||||
const root = createRoot(rootElement);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<GameView />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
486
environments/hack0/DeepSacrifice/src/pages/GameView.tsx
Normal file
486
environments/hack0/DeepSacrifice/src/pages/GameView.tsx
Normal file
|
|
@ -0,0 +1,486 @@
|
|||
import type React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import ChessBoard from "../components/ChessBoard";
|
||||
|
||||
interface MoveData {
|
||||
move: { from: string; to: string; san?: string };
|
||||
fen: string;
|
||||
reward: number;
|
||||
llmFeedback: { score: string; justification: string };
|
||||
}
|
||||
|
||||
const initialFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
|
||||
const GameView: React.FC = () => {
|
||||
const [fen, setFen] = useState<string>(initialFen);
|
||||
const [moveHistory, setMoveHistory] = useState<MoveData[]>([]);
|
||||
const [feedback, setFeedback] = useState<null | {
|
||||
score: string;
|
||||
justification: string;
|
||||
reward: number;
|
||||
}>(null);
|
||||
const [userTurn, setUserTurn] = useState<boolean>(true);
|
||||
const [gameOver, setGameOver] = useState<boolean>(false);
|
||||
const [scoring, setScoring] = useState(false);
|
||||
const [scored, setScored] = useState(false);
|
||||
|
||||
// Start a new game (reset backend state and local state)
|
||||
const startNewGame = async () => {
|
||||
const res = await fetch("/api/reset", { method: "POST" });
|
||||
const data = await res.json();
|
||||
setFen(data.fen || initialFen);
|
||||
setMoveHistory([]);
|
||||
setFeedback(null);
|
||||
setUserTurn(true);
|
||||
setGameOver(false);
|
||||
setScored(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
startNewGame();
|
||||
}, []);
|
||||
|
||||
// Helper to call backend for a move
|
||||
const makeMove = async (from: string, to: string) => {
|
||||
const res = await fetch("/api/move", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ from, to }),
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
// If backend returns moves array (user + agent)
|
||||
if (Array.isArray(data.moves)) {
|
||||
setMoveHistory((prev) => [
|
||||
...prev,
|
||||
...data.moves.map((m: any) => ({
|
||||
move: m.move,
|
||||
fen: m.fen,
|
||||
reward: m.reward,
|
||||
llmFeedback: m.llmFeedback,
|
||||
})),
|
||||
]);
|
||||
// Set FEN to the last move's FEN
|
||||
const lastMove = data.moves[data.moves.length - 1];
|
||||
setFen(lastMove.fen);
|
||||
setFeedback({
|
||||
score: lastMove.llmFeedback?.score,
|
||||
justification: lastMove.llmFeedback?.justification,
|
||||
reward: lastMove.reward,
|
||||
});
|
||||
if (data.done) setGameOver(true);
|
||||
return data;
|
||||
}
|
||||
|
||||
// fallback for old response shape
|
||||
setFen(data.fen);
|
||||
setFeedback({
|
||||
score: data.llmFeedback?.score,
|
||||
justification: data.llmFeedback?.justification,
|
||||
reward: data.reward,
|
||||
});
|
||||
setMoveHistory((prev) => [
|
||||
...prev,
|
||||
{
|
||||
move: { from, to },
|
||||
fen: data.fen,
|
||||
reward: data.reward,
|
||||
llmFeedback: data.llmFeedback,
|
||||
},
|
||||
]);
|
||||
if (data.done) setGameOver(true);
|
||||
return data;
|
||||
};
|
||||
|
||||
// User move handler
|
||||
const handleMove = async (from: string, to: string) => {
|
||||
if (!userTurn || gameOver) return;
|
||||
setUserTurn(false);
|
||||
const data = await makeMove(from, to);
|
||||
// After both moves (user + agent), re-enable user input if game not over
|
||||
if (!data.done) {
|
||||
setTimeout(() => {
|
||||
setUserTurn(true);
|
||||
}, 500); // Small delay for UX
|
||||
}
|
||||
};
|
||||
|
||||
// Score the game after it ends
|
||||
const scoreGame = async () => {
|
||||
setScoring(true);
|
||||
try {
|
||||
const res = await fetch("/api/game/llm_feedback", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ moves: moveHistory }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (Array.isArray(data.moves)) {
|
||||
setMoveHistory(data.moves);
|
||||
setScored(true);
|
||||
}
|
||||
} finally {
|
||||
setScoring(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
background: "#fff",
|
||||
minHeight: "100vh",
|
||||
height: "100vh",
|
||||
fontFamily: "monospace",
|
||||
color: "#111",
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
border: "8px solid #111",
|
||||
boxSizing: "border-box",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{/* Toolbar */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
borderBottom: "4px solid #111",
|
||||
background: "#fff",
|
||||
padding: "0 12px",
|
||||
minHeight: 40,
|
||||
height: 40,
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: 900,
|
||||
fontSize: 18,
|
||||
letterSpacing: 1,
|
||||
marginRight: 16,
|
||||
textTransform: "uppercase",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: 400 }}>Deep</span>Sacrifice
|
||||
</span>
|
||||
<button
|
||||
onClick={startNewGame}
|
||||
style={{
|
||||
fontWeight: 900,
|
||||
fontSize: 12,
|
||||
border: "2px solid #111",
|
||||
background: "#fff",
|
||||
color: "#111",
|
||||
padding: "2px 10px",
|
||||
cursor: "pointer",
|
||||
textTransform: "uppercase",
|
||||
boxShadow: "none",
|
||||
borderRadius: 0,
|
||||
height: 28,
|
||||
lineHeight: "24px",
|
||||
alignSelf: "center",
|
||||
}}
|
||||
>
|
||||
New Game
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
minWidth: 0,
|
||||
justifyContent: "space-between",
|
||||
alignItems: "stretch",
|
||||
padding: 16,
|
||||
gap: 24,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: "0 0 auto",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<ChessBoard
|
||||
fen={fen}
|
||||
onMove={handleMove}
|
||||
userTurn={userTurn && !gameOver}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
marginBottom: 8,
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
{!scored ? (
|
||||
<button
|
||||
onClick={scoreGame}
|
||||
disabled={scoring}
|
||||
style={{
|
||||
fontWeight: 700,
|
||||
fontSize: 14,
|
||||
border: "2px solid #111",
|
||||
background: scoring ? "#eee" : "#fff",
|
||||
color: scoring ? "#aaa" : "#111",
|
||||
padding: "2px 10px",
|
||||
cursor: scoring ? "not-allowed" : "pointer",
|
||||
textTransform: "uppercase",
|
||||
borderRadius: 0,
|
||||
height: 28,
|
||||
lineHeight: "24px",
|
||||
alignSelf: "center",
|
||||
opacity: scoring ? 0.7 : 1,
|
||||
}}
|
||||
>
|
||||
{scoring ? "Scoring..." : "Score Game"}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={startNewGame}
|
||||
style={{
|
||||
fontWeight: 700,
|
||||
fontSize: 14,
|
||||
border: "2px solid #111",
|
||||
background: "#fff",
|
||||
color: "#111",
|
||||
padding: "2px 10px",
|
||||
cursor: "pointer",
|
||||
textTransform: "uppercase",
|
||||
borderRadius: 0,
|
||||
height: 28,
|
||||
lineHeight: "24px",
|
||||
alignSelf: "center",
|
||||
}}
|
||||
>
|
||||
New Game
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{gameOver && (
|
||||
<div
|
||||
style={{
|
||||
color: "#fff",
|
||||
background: "#111",
|
||||
marginBottom: 8,
|
||||
padding: 8,
|
||||
fontWeight: 900,
|
||||
border: "2px solid #111",
|
||||
borderRadius: 0,
|
||||
textAlign: "center",
|
||||
letterSpacing: 1,
|
||||
}}
|
||||
>
|
||||
Game Over
|
||||
</div>
|
||||
)}
|
||||
{feedback && null}
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
fontSize: 13,
|
||||
lineHeight: 1.3,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
overflowY: "auto",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<table
|
||||
style={{
|
||||
width: "100%",
|
||||
borderCollapse: "collapse",
|
||||
background: "#fff",
|
||||
fontFamily: "monospace",
|
||||
tableLayout: "fixed",
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
fontWeight: 900,
|
||||
background: "#eee",
|
||||
textAlign: "left",
|
||||
width: "8%",
|
||||
minWidth: 40,
|
||||
maxWidth: 60,
|
||||
}}
|
||||
>
|
||||
#
|
||||
</th>
|
||||
<th
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
fontWeight: 900,
|
||||
background: "#eee",
|
||||
textAlign: "left",
|
||||
width: "32%",
|
||||
minWidth: 80,
|
||||
maxWidth: 120,
|
||||
}}
|
||||
>
|
||||
Move
|
||||
</th>
|
||||
<th
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
fontWeight: 900,
|
||||
background: "#eee",
|
||||
textAlign: "left",
|
||||
width: "30%",
|
||||
minWidth: 60,
|
||||
maxWidth: 100,
|
||||
}}
|
||||
>
|
||||
Reward
|
||||
</th>
|
||||
<th
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
fontWeight: 900,
|
||||
background: "#eee",
|
||||
textAlign: "left",
|
||||
width: "30%",
|
||||
minWidth: 60,
|
||||
maxWidth: 100,
|
||||
}}
|
||||
>
|
||||
LLM Score
|
||||
</th>
|
||||
<th
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
fontWeight: 900,
|
||||
background: "#eee",
|
||||
textAlign: "left",
|
||||
width: "50%",
|
||||
minWidth: 100,
|
||||
maxWidth: 300,
|
||||
}}
|
||||
>
|
||||
Justification
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{moveHistory.map((m, i) => (
|
||||
<tr key={i}>
|
||||
<td
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
width: "8%",
|
||||
minWidth: 40,
|
||||
maxWidth: 60,
|
||||
}}
|
||||
>
|
||||
{i + 1}
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
width: "32%",
|
||||
minWidth: 80,
|
||||
maxWidth: 120,
|
||||
}}
|
||||
>
|
||||
{m.move.from}-{m.move.to}
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
width: "30%",
|
||||
minWidth: 60,
|
||||
maxWidth: 100,
|
||||
}}
|
||||
>
|
||||
{m.reward === null || m.reward === undefined
|
||||
? "–"
|
||||
: m.reward}
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
width: "30%",
|
||||
minWidth: 60,
|
||||
maxWidth: 100,
|
||||
}}
|
||||
>
|
||||
{m.llmFeedback?.score === null ||
|
||||
m.llmFeedback?.score === undefined
|
||||
? "–"
|
||||
: m.llmFeedback.score}
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
border: "2px solid #111",
|
||||
padding: 6,
|
||||
width: "50%",
|
||||
minWidth: 100,
|
||||
maxWidth: 300,
|
||||
}}
|
||||
>
|
||||
{m.llmFeedback?.justification === null ||
|
||||
m.llmFeedback?.justification === undefined
|
||||
? "–"
|
||||
: m.llmFeedback.justification}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GameView;
|
||||
16
environments/hack0/DeepSacrifice/vite.config.ts
Normal file
16
environments/hack0/DeepSacrifice/vite.config.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import react from "@vitejs/plugin-react";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
open: true,
|
||||
// Local server runs on 3001, so we need to proxy requests to 3000
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: "http://localhost:3001",
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue