initial commit
This commit is contained in:
commit
ac9aa86d33
14 changed files with 1021 additions and 0 deletions
154
web/templates/play.html
Normal file
154
web/templates/play.html
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Go Fish - Game</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: system-ui, -apple-system, sans-serif; background: #1a1a2e; color: #e0e0e0; min-height: 100vh; }
|
||||
.container { max-width: 800px; margin: 0 auto; padding: 2rem; }
|
||||
h1 { text-align: center; margin-bottom: 1rem; color: #f0f0f0; }
|
||||
.game-status { text-align: center; margin-bottom: 2rem; font-size: 1.2rem; }
|
||||
.deck { text-align: center; margin: 2rem 0; }
|
||||
.card { width: 70px; height: 100px; background: #1a1a2e; border: 2px solid #444; border-radius: 4px; margin: 2px; display: inline-block; position: relative; min-height: 100px; }
|
||||
.card.flip { transition: transform 0.3s; transform: rotateY(180deg); }
|
||||
.card.face { background: #e94560; color: white; }
|
||||
.hand { min-height: 120px; }
|
||||
.book-area { min-height: 80px; margin-top: 1rem; }
|
||||
.book { width: 60px; height: 20px; background: #ff6b7a; color: white; border-radius: 3px; margin: 2px; display: inline-block; }
|
||||
.controls { text-align: center; margin-top: 2rem; }
|
||||
.controls button { margin: 0 0.5rem; }
|
||||
.instruction { text-align: center; margin: 1rem 0; color: #888; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Go Fish</h1>
|
||||
|
||||
<div class="game-status" id="gameStatus" data-currentplayerid="{{ .Player.ID }}" data-opponentid="{{ .Game.ID }}" data-isbot="{{ .IsBot }}">
|
||||
{{ .Player.Name }}'s turn - Ask for a rank
|
||||
{{ if .IsBot }}(playing against a bot){{ end }}
|
||||
</div>
|
||||
|
||||
<div class="deck" id="deck">
|
||||
<!-- Deck cards -->
|
||||
</div>
|
||||
|
||||
<div class="hand" id="hand">
|
||||
<!-- Player's hand cards -->
|
||||
</div>
|
||||
|
||||
<div class="book-area" id="bookArea">
|
||||
<!-- Booked sets -->
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button onclick="askRank('A')">Ask for A</button>
|
||||
<button onclick="askRank('2')">Ask for 2</button>
|
||||
<button onclick="askRank('3')">Ask for 3</button>
|
||||
<button onclick="askRank('4')">Ask for 4</button>
|
||||
<button onclick="askRank('5')">Ask for 5</button>
|
||||
<button onclick="askRank('6')">Ask for 6</button>
|
||||
<button onclick="askRank('7')">Ask for 7</button>
|
||||
<button onclick="askRank('8')">Ask for 8</button>
|
||||
<button onclick="askRank('9')">Ask for 9</button>
|
||||
<button onclick="askRank('10')">Ask for 10</button>
|
||||
<button onclick="askRank('J')">Ask for J</button>
|
||||
<button onclick="askRank('Q')">Ask for Q</button>
|
||||
<button onclick="askRank('K')">Ask for K</button>
|
||||
</div>
|
||||
|
||||
<div class="instruction" id="instruction">
|
||||
Click a card in your hand to see its rank, then ask opponent for rank
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentPlayerId = null;
|
||||
let opponentId = null;
|
||||
let myHand = [];
|
||||
let myBooks = [];
|
||||
let opponentBooks = [];
|
||||
let isBot = false;
|
||||
|
||||
// Load game state from rendered template
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const statusDiv = document.getElementById('gameStatus');
|
||||
if (statusDiv) {
|
||||
currentPlayerId = statusDiv.dataset.currentplayerid || null;
|
||||
opponentId = statusDiv.dataset.opponentid || null;
|
||||
isBot = statusDiv.dataset.isbot === 'true' || false;
|
||||
}
|
||||
});
|
||||
|
||||
function askRank(rank) {
|
||||
if (!currentPlayerId || !opponentId) return;
|
||||
|
||||
fetch('/ask', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ playerId: currentPlayerId, opponentId: opponentId, rank: rank })
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
updateGameState(data);
|
||||
});
|
||||
}
|
||||
|
||||
function updateGameState(data) {
|
||||
myHand = data.myHand || [];
|
||||
myBooks = data.myBooks || [];
|
||||
opponentBooks = data.opponentBooks || [];
|
||||
|
||||
renderHand();
|
||||
renderBooks();
|
||||
renderStatus(data.status);
|
||||
|
||||
// Check if game over
|
||||
if (data.gameOver) {
|
||||
alert(data.message || 'Game over!');
|
||||
}
|
||||
}
|
||||
|
||||
function renderHand() {
|
||||
const handDiv = document.getElementById('hand');
|
||||
handDiv.innerHTML = '';
|
||||
myHand.forEach((card, i) => {
|
||||
const cardEl = document.createElement('div');
|
||||
cardEl.className = 'card' + (i === 0 ? ' flip' : '');
|
||||
cardEl.textContent = card;
|
||||
cardEl.dataset.rank = card;
|
||||
cardEl.onclick = function() { askRank(card); };
|
||||
handDiv.appendChild(cardEl);
|
||||
});
|
||||
}
|
||||
|
||||
function renderBooks() {
|
||||
const bookArea = document.getElementById('bookArea');
|
||||
bookArea.innerHTML = '';
|
||||
|
||||
// My books
|
||||
myBooks.forEach(rank => {
|
||||
const book = document.createElement('div');
|
||||
book.className = 'book';
|
||||
book.textContent = rank + ' set';
|
||||
bookArea.appendChild(book);
|
||||
});
|
||||
|
||||
// Opponent books
|
||||
opponentBooks.forEach(rank => {
|
||||
const book = document.createElement('div');
|
||||
book.className = 'book';
|
||||
book.textContent = rank + ' set (opp)';
|
||||
bookArea.appendChild(book);
|
||||
});
|
||||
}
|
||||
|
||||
function renderStatus(status) {
|
||||
const statusDiv = document.getElementById('gameStatus');
|
||||
statusDiv.textContent = status || 'Your turn';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue