<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tournament POC</title>
<style>
.hidden { display: none; }
body { font-family: sans-serif; padding: 1rem; }
.view { margin-bottom: 2rem; }
button { margin: 0.5rem; }
#lobby-players { list-style: none; padding: 0; }
</style>
</head>
<body>
<!-- 1) JOIN & ROLE SELECTION -->
<div id="join-view" class="view">
<h2>Join or Host a Room</h2>
<label>Your name: <input id="input-name" /></label><br/>
<label><input type="radio" name="role" value="host" checked /> Host</label>
<label><input type="radio" name="role" value="player" /> Player</label><br/>
<div id="join-code-container" class="hidden">
<label>Room code: <input id="input-roomcode" /></label><br/>
</div>
<button id="btn-join-next">Next ▶</button>
</div>
<!-- 2) SETUP (Host) / CHARACTER PICK (Player) -->
<div id="setup-view" class="view hidden">
<!-- Host configuration -->
<div id="host-setup">
<h2>Room Setup</h2>
<label>Time limit (seconds): <input id="input-timelimit" type="number" value="30" /></label><br/>
<label>Questions (one per line):<br/>
<textarea id="textarea-questions" rows="4" cols="30">Who’s braver?
Who’ll win a fight?</textarea>
</label><br/>
<button id="btn-create-room">Create Room</button>
</div>
<!-- Player character pick -->
<div id="player-setup" class="hidden">
<h2>Enter Your Character</h2>
<label>Character name: <input id="input-character" /></label><br/>
<button id="btn-join-room">Join Room</button>
</div>
</div>
<!-- 3) LOBBY -->
<div id="lobby-view" class="view hidden">
<h2>Lobby — Room <span id="lobby-code"></span></h2>
<ul id="lobby-players"></ul>
<button id="btn-begin" class="hidden">Begin Tournament</button>
</div>
<!-- 4) GAME -->
<div id="game-view" class="view hidden">
<h2>Match</h2>
<p><strong id="match-players"></strong></p>
<p>Question: <em id="match-question"></em></p>
<p id="timer">Time left: <span id="time-left"></span>s</p>
<div id="voting-buttons" class="hidden">
<button id="vote-A"></button>
<button id="vote-B"></button>
</div>
<h3 id="champion" class="hidden">🏆 Champion: <span id="winner-name"></span></h3>
</div>
<!-- Firebase + App Logic -->
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.8.1/firebase-app.js";
import { getDatabase, ref, push, set, onValue, get, remove, update } from "https://www.gstatic.com/firebasejs/11.8.1/firebase-database.js";
// ─── Your Firebase config ──────────────────────────────────────────────────
const firebaseConfig = {
apiKey: "AIzaSyAIQND6Pag2yX66cIQmeMGFr-rwImy8SRA",
authDomain: "argumentproject-d61ee.firebaseapp.com",
databaseURL: "https://argumentproject-d61ee-default-rtdb.europe-west1.firebasedatabase.app",
projectId: "argumentproject-d61ee",
storageBucket: "argumentproject-d61ee.appspot.com",
messagingSenderId: "413461652291",
appId: "1:413461652291:web:fe83c0c8b61885ba0fc5f6"
};
const app = initializeApp(firebaseConfig);
const db = getDatabase(app);
// ─── DOM Helpers ───────────────────────────────────────────────────────────
const $ = id => document.getElementById(id);
const hide = el => el.classList.add("hidden");
const show = el => el.classList.remove("hidden");
// ─── State ─────────────────────────────────────────────────────────────────
let playerName, role, roomCode, timeLimit, questions = [];
let bracket = [], currentMatch = null, voteCast = false;
let timerInterval;
// ─── VIEW SWITCHERS ─────────────────────────────────────────────────────────
const views = { join: $("join-view"), setup: $("setup-view"),
lobby: $("lobby-view"), game: $("game-view") };
function setView(name) {
Object.values(views).forEach(v => hide(v));
show(views[name]);
}
// ─── JOIN / ROLE ────────────────────────────────────────────────────────────
$("btn-join-next").onclick = () => {
playerName = $("input-name").value.trim();
if (!playerName) return alert("Enter your name");
role = document.querySelector('input[name="role"]:checked').value;
sessionStorage.setItem("playerName", playerName);
sessionStorage.setItem("role", role);
if (role === "player") show($("join-code-container"));
else hide($("join-code-container"));
setView("setup");
if (role === "player") {
hide($("host-setup"));
show($("player-setup"));
}
};
// ─── HOST: CREATE ROOM ──────────────────────────────────────────────────────
$("btn-create-room").onclick = async () => {
roomCode = Math.random().toString(36).substr(2, 5).toUpperCase();
timeLimit = parseInt($("input-timelimit").value, 10);
questions = $("textarea-questions").value.trim().split("\n").filter(Boolean);
await set(ref(db, `rooms/${roomCode}`), {
admin: playerName,
state: "lobby",
timeLimit,
questions
});
await push(ref(db, `rooms/${roomCode}/players`), playerName);
sessionStorage.setItem("roomCode", roomCode);
lobbyInit();
};
// ─── PLAYER: JOIN ROOM ──────────────────────────────────────────────────────
$("btn-join-room").onclick = async () => {
roomCode = $("input-roomcode").value.trim().toUpperCase();
if (!roomCode) return alert("Enter room code");
sessionStorage.setItem("roomCode", roomCode);
const charName = $("input-character").value.trim();
if (!charName) return alert("Enter a character");
await push(ref(db, `rooms/${roomCode}/players`), playerName);
await push(ref(db, `rooms/${roomCode}/characters`), { name: charName, owner: playerName });
lobbyInit();
};
// ─── LOBBY: SHOW PLAYERS & START ────────────────────────────────────────────
function lobbyInit() {
setView("lobby");
$("lobby-code").textContent = roomCode;
onValue(ref(db, `rooms/${roomCode}/players`), snap => {
const list = Object.values(snap.val()||{});
$("lobby-players").innerHTML = list.map(n => `<li>${n}</li>`).join("");
});
if (role === "host") show($("btn-begin")); else hide($("btn-begin"));
$("btn-begin").onclick = async () => {
const cfg = (await get(ref(db, `rooms/${roomCode}`))).val();
timeLimit = cfg.timeLimit;
questions = cfg.questions;
const charsArr = Object.values((await get(ref(db, `rooms/${roomCode}/characters`))).val()||{});
bracket = shuffle(charsArr);
await update(ref(db, `rooms/${roomCode}`), { state: "started" });
runNextMatch();
};
onValue(ref(db, `rooms/${roomCode}/state`), snap => {
if (snap.val() === "started") runClientGame();
});
}
// ─── GAME ORCHESTRATION (HOST) ──────────────────────────────────────────────
function runNextMatch() {
if (bracket.length === 1) {
update(ref(db, `rooms/${roomCode}`), { state: "finished" });
set(ref(db, `rooms/${roomCode}/champion`), bracket[0].name);
return;
}
const A = bracket.shift();
const B = bracket.shift() || null;
const question = questions[Math.floor(Math.random()*questions.length)];
set(ref(db, `rooms/${roomCode}/currentMatch`), { A, B, question });
remove(ref(db, `rooms/${roomCode}/votes`));
let remaining = timeLimit;
timerInterval = setInterval(() => {
updateUI({ time: remaining-- });
if (remaining < 0) {
clearInterval(timerInterval);
finishMatch(A, B);
}
}, 1000);
}
async function finishMatch(A, B) {
const votesObj = (await get(ref(db, `rooms/${roomCode}/votes`))).val()||{};
const countA = votesObj.A?Object.keys(votesObj.A).length:0;
const countB = votesObj.B?Object.keys(votesObj.B).length:0;
const winner = countA>countB?A:countB>countA?B:(Math.random()<0.5?A:B);
bracket.push(winner);
runNextMatch();
}
// ─── CLIENT GAME VIEW ───────────────────────────────────────────────────────
function runClientGame() {
setView("game");
onValue(ref(db, `rooms/${roomCode}/currentMatch`), snap => {
currentMatch = snap.val();
if (currentMatch) updateUI({ match: currentMatch });
});
onValue(ref(db, `rooms/${roomCode}/state`), snap => {
if (snap.val()==="finished") {
get(ref(db, `rooms/${roomCode}/champion`))
.then(ch => {
setView("game");
show($("champion"));
$("winner-name").textContent = ch.val();
hide($("timer"));
});
}
});
}
// ─── VOTING & UI UPDATE ─────────────────────────────────────────────────────
function updateUI({ match, time }) {
if (match) {
hide($("champion")); show($("timer")); show($("voting-buttons"));
$("match-players").textContent = `${match.A?.name||"BYE"} vs ${match.B?.name||"BYE"}`;
$("match-question").textContent = match.question;
$("vote-A").textContent = match.A?.name||"BYE";
$("vote-B").textContent = match.B?.name||"BYE";
voteCast = false;
}
if (time !== undefined) $("time-left").textContent = time;
}
$("vote-A").onclick = () => castVote("A");
$("vote-B").onclick = () => castVote("B");
async function castVote(side) {
if (voteCast||!currentMatch) return;
await push(ref(db, `rooms/${roomCode}/votes/${side}`), playerName);
voteCast = true;
}
// ─── UTILS ─────────────────────────────────────────────────────────────────
function shuffle(a) {
for (let i=a.length-1; i>0; i--) {
const j = Math.floor(Math.random()*(i+1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
</script>
</body>
</html>