Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions AI_PROMPT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Backgammon AI Move Prompt

Use this prompt template to ask an AI model for a valid backgammon move suggestion given a board state and dice roll.

---

## Prompt Template

```
We are playing backgammon. You are playing as {{color}} ({{color}} moves in the {{direction}} direction, from point {{start}} toward point {{end}} and then bearing off).

### Board Configuration

The board has 24 points numbered 1–24. Positive values represent {{positiveColor}} pieces; negative values represent {{negativeColor}} pieces. Zero means the point is empty.

Board (point 1 to 24):
{{board}}

Pieces in prison (hit and waiting to re-enter):
- White: {{prison.white}}
- Black: {{prison.black}}

Pieces already borne off (home):
- White: {{home.white}}
- Black: {{home.black}}

### Dice

You rolled: {{dice[0]}} and {{dice[1]}}
{{#doubles}}(Doubles! You have four moves of {{dice[0]}} to use.){{/doubles}}

### Your Task

Choose the best legal play for this turn and respond **only** in standard backgammon notation. If no legal moves are available, respond with: `no move`
```

---

## Field Reference

| Placeholder | Source in `Game` type | Description |
|---|---|---|
| `{{color}}` | `game.color` | Current player's color (`white` or `black`) |
| `{{board}}` | `game.board` (24-element array) | Piece counts per point; positive = white, negative = black |
| `{{prison.white}}` | `game.prison.white` | White pieces on the bar |
| `{{prison.black}}` | `game.prison.black` | Black pieces on the bar |
| `{{home.white}}` | `game.home.white` | White pieces borne off |
| `{{home.black}}` | `game.home.black` | Black pieces borne off |
| `{{dice[0]}}`, `{{dice[1]}}` | `game.dice` | The two dice values rolled |

### Direction by Color

| Color | Moves toward | Entry range | Home board |
|---|---|---|---|
| White | Point 24 → 1, then off | Points 19–24 | Points 1–6 |
| Black | Point 1 → 24, then off | Points 1–6 | Points 19–24 |
4 changes: 3 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@
"notificationsDisabled": "Notifications Disabled",
"notificationsEnabled": "Notifications Enabled",
"enableNotifications": "Enable Notifications",
"privacyPolicy": "Privacy Policy"
"privacyPolicy": "Privacy Policy",
"aiOpponent": "AI Opponent",
"aiComingSoon": "Coming soon — pick your model"
}
5 changes: 5 additions & 0 deletions src/Dialogues/Friends.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
overflow: hidden;
text-overflow: ellipsis;
}
&.ai-opponent {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
> svg, > img {
width: 4em;
height: 4em;
Expand Down
12 changes: 12 additions & 0 deletions src/Dialogues/Friends.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import NotificationsActiveIcon from '@material-design-icons/svg/filled/notifications_active.svg?react';
import CircleNotificationsIcon from '@material-design-icons/svg/filled/circle_notifications.svg?react';
import LocalIcon from '@material-design-icons/svg/filled/location_on.svg?react';
import SmartToyIcon from '@material-design-icons/svg/filled/smart_toy.svg?react';
import AutoAwesomeIcon from '@material-design-icons/svg/filled/auto_awesome.svg?react';
import RestartAltIcon from '@material-design-icons/svg/filled/restart_alt.svg?react';
import BugReportIcon from '@material-design-icons/svg/filled/bug_report.svg?react';
import InfoIcon from '@material-design-icons/svg/filled/info.svg?react';
Expand Down Expand Up @@ -214,7 +216,7 @@
case 'denied':
alert(t('notificationsDenied'));
break;
// @ts-expect-error

Check failure on line 219 in src/Dialogues/Friends.tsx

View workflow job for this annotation

GitHub Actions / test

Include a description after the "@ts-expect-error" directive to explain why the @ts-expect-error is necessary. The description must be 3 characters or longer
case 'granted':
if (hasFcmToken) {
const confirmMessage = t('disableNotificationsConfirm');
Expand All @@ -226,7 +228,7 @@
break;
}
// fall-through
case 'default':

Check failure on line 231 in src/Dialogues/Friends.tsx

View workflow job for this annotation

GitHub Actions / test

Expected a 'break' statement before 'case'

setNotificationStatus('processing');
fcmTokenRef.current = await saveFcmToken();
Expand Down Expand Up @@ -327,6 +329,16 @@
{t('local')}
</h3>
</li> : null}
<li className="ai-opponent" aria-disabled="true">
<span className="ai-icon">
<SmartToyIcon className="material-icons-svg notranslate" />
<AutoAwesomeIcon className="material-icons-svg notranslate" />
</span>
<div>
<h3>{t('aiOpponent')}</h3>
<time>{t('aiComingSoon')}</time>
</div>
</li>
{[...myTurnFriends, ...renderFriends]}
</ul>
</section>
Expand Down
25 changes: 25 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,31 @@ body,
}
}

.ai-icon {
position: relative;
display: inline-flex;
flex-shrink: 0;
width: 4em;
height: 4em;

> .material-icons-svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
fill: var(--primary);
}

> .material-icons-svg:last-child {
top: 30%;
left: 30%;
width: 55%;
height: 55%;
fill: white;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
}

.offline-icon {
position: relative;
display: inline-flex;
Expand Down
Loading