Denemek içni HTML Runner sayfasına yapıştırmanız yeterli.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Futbol Simülasyon Motoru (Canlı Düzenlenebilir)</title>
<!-- Tailwind CSS -->
<script src="
<link rel="stylesheet" href="
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
.tab-btn.active { border-bottom: 3px solid #10b981; color: #10b981; font-weight: bold; }
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
input[type=number] { -moz-appearance: textfield; }
</style>
</head>
<body class="bg-slate-900 text-slate-100 min-h-screen">
<div class="max-w-6xl mx-auto p-4 md
-8">
<!-- ÜST BAŞLIK -->
<header class="text-center mb-8 border-b border-slate-800 pb-6">
<h1 class="text-3xl md:text-4xl font-extrabold text-emerald-400 tracking-wide flex items-center justify-center gap-3">
<i class="fa-solid fa-futbol"></i> Futbol Simülasyon & Yönetim Motoru
</h1>
<p class="text-slate-400 mt-2 text-sm md:text-base">Canlı İstatistik Düzenleme ve Skor Müdahale Özellikli</p>
</header>
<!-- PANEL 1: AYARLAR VE TAKIM LİSTESİ -->
<section id="setup-panel" class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div class="bg-slate-800 p-6 rounded-2xl shadow-xl border border-slate-700 h-fit">
<h2 class="text-xl font-bold mb-4 text-emerald-300 border-b border-slate-700 pb-2">
<i class="fa-solid fa-sliders"></i> Turnuva Ayarları
</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-semibold mb-1 text-slate-300">Format:</label>
<select id="tourney-type" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2.5 text-slate-200 focus
utline-none focus:border-emerald-500">
<option value="league">Lig Usulü (Puan Tablosu)</option>
<option value="knockout">Eleme Turnuvası (Bracket)</option>
</select>
</div>
<div>
<label class="block text-sm font-semibold mb-1 text-slate-300">Maç Tipi:</label>
<select id="match-legs" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2.5 text-slate-200 focus
utline-none focus:border-emerald-500">
<option value="1">Tek Maç</option>
<option value="2">Çift Maç (Rövanşlı)</option>
</select>
</div>
<div class="pt-4 border-t border-slate-700">
<label class="block text-sm font-semibold mb-2 text-slate-300">Hazır Şablonlar:</label>
<div class="grid grid-cols-2 gap-2">
<button onclick="loadTemplate('superlig')" class="bg-slate-700 hover:bg-slate-600 text-xs py-2 px-3 rounded text-center transition">Süper Lig (4 Takım)</button>
<button onclick="loadTemplate('ucl')" class="bg-slate-700 hover:bg-slate-600 text-xs py-2 px-3 rounded text-center transition">Şampiyonlar Ligi (8 Takım)</button>
</div>
</div>
<button onclick="startSimulation()" class="w-full bg-emerald-600 hover:bg-emerald-500 text-white font-bold py-3 px-4 rounded-xl shadow-lg transition duration-200 mt-6 flex items-center justify-center gap-2">
<i class="fa-solid fa-play"></i> Turnuvayı Başlat
</button>
</div>
</div>
<!-- Takım Listesi -->
<div class="lg:col-span-2 bg-slate-800 p-6 rounded-2xl shadow-xl border border-slate-700">
<div class="flex justify-between items-center mb-4 border-b border-slate-700 pb-2">
<h2 class="text-xl font-bold text-emerald-300">
<i class="fa-solid fa-shield-halved"></i> Başlangıç Takımları (<span id="team-count">0</span>)
</h2>
<button onclick="addTeamField()" class="text-xs bg-emerald-700 hover:bg-emerald-600 px-3 py-1.5 rounded-lg text-white font-semibold transition">
<i class="fa-solid fa-plus"></i> Takım Ekle
</button>
</div>
<div id="teams-list" class="space-y-3 max-h-[420px] overflow-y-auto pr-2"></div>
</div>
</section>
<!-- PANEL 2: OYUN / SİMÜLASYON EKRANI -->
<section id="sim-panel" class="hidden">
<!-- Kontrol Çubuğu -->
<div class="flex flex-wrap justify-between items-center bg-slate-800 p-4 rounded-xl border border-slate-700 mb-6 gap-4">
<div class="flex gap-2 md:gap-6 border-b border-slate-700 md:border-b-0">
<button id="tab-matches-btn" onclick="switchTab('matches')" class="tab-btn active pb-2 px-2 text-sm md:text-base">
<i class="fa-solid fa-calendar-days"></i> Fikstür & Skorlar
</button>
<button id="tab-standings-btn" onclick="switchTab('standings')" class="tab-btn pb-2 px-2 text-sm md:text-base">
<i class="fa-solid fa-table-list"></i> Puan Durumu / Eşleşme
</button>
<button id="tab-teams-btn" onclick="switchTab('teams')" class="tab-btn pb-2 px-2 text-sm md:text-base">
<i class="fa-solid fa-sliders"></i> Takım & Güç Yönetimi
</button>
</div>
<div class="flex flex-wrap gap-2">
<button onclick="playNextRound()" id="next-round-btn" class="bg-emerald-600 hover:bg-emerald-500 text-white font-semibold px-3 py-1.5 md
x-4 md
y-2 rounded-lg text-xs md:text-sm transition flex items-center gap-1.5">
<i class="fa-solid fa-forward-step"></i> Sıradaki Tur
</button>
<button onclick="playAllRounds()" id="all-rounds-btn" class="bg-teal-600 hover:bg-teal-500 text-white font-semibold px-3 py-1.5 md
x-4 md
y-2 rounded-lg text-xs md:text-sm transition flex items-center gap-1.5">
<i class="fa-solid fa-forward-fast"></i> Hepsini Oyna
</button>
<button onclick="resetAll()" class="bg-rose-700 hover:bg-rose-600 text-white font-semibold px-3 py-1.5 md
x-4 md
y-2 rounded-lg text-xs md:text-sm transition flex items-center gap-1.5">
<i class="fa-solid fa-rotate-left"></i> Sıfırla
</button>
</div>
</div>
<!-- Şampiyon Kartı -->
<div id="winner-banner" class="hidden mb-6 p-5 bg-gradient-to-r from-amber-600 to-yellow-500 rounded-2xl text-center shadow-xl">
<h3 class="text-2xl font-black text-slate-900 flex items-center justify-center gap-2">
<i class="fa-solid fa-trophy text-3xl"></i> KAZANAN / LİDER: <span id="champion-name"></span>!
</h3>
</div>
<!-- TAB 1: MAÇLAR & SKOR MÜDAHALESİ -->
<div id="tab-matches" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"></div>
<!-- TAB 2: PUAN DURUMU / ELEME TABLOSU -->
<div id="tab-standings" class="hidden bg-slate-800 p-6 rounded-2xl border border-slate-700 shadow-xl overflow-x-auto">
<div id="standings-content"></div>
</div>
<!-- TAB 3: CANLI TAKIM VE GÜÇ YÖNETİMİ -->
<div id="tab-teams" class="hidden bg-slate-800 p-6 rounded-2xl border border-slate-700 shadow-xl">
<div class="max-w-xl mx-auto">
<h3 class="text-lg font-bold text-emerald-300 mb-2 border-b border-slate-700 pb-2">
<i class="fa-solid fa-pen-to-square"></i> Canlı Güç & İsim Düzenleyici
</h3>
<p class="text-xs text-slate-400 mb-4">Burada yapacağınız değişiklikler oynanmamış tüm gelecek maçlara anında etki eder.</p>
<div id="live-team-editor" class="space-y-3"></div>
</div>
</div>
</section>
</div>
<!-- JAVASCRIPT MOTORU -->
<script>
let teams = [];
let fixtures = [];
let currentRound = 0;
let config = { type: 'league', legs: 1 };
let standings = {};
const templates = {
superlig: [
{ id: "t1", name: "Galatasaray", rating: 83 },
{ id: "t2", name: "Fenerbahçe", rating: 82 },
{ id: "t3", name: "Beşiktaş", rating: 78 },
{ id: "t4", name: "Trabzonspor", rating: 76 }
],
ucl: [
{ id: "t1", name: "Real Madrid", rating: 89 },
{ id: "t2", name: "Manchester City", rating: 90 },
{ id: "t3", name: "Bayern Münih", rating: 87 },
{ id: "t4", name: "PSG", rating: 85 },
{ id: "t5", name: "Arsenal", rating: 86 },
{ id: "t6", name: "Inter", rating: 84 },
{ id: "t7", name: "Barcelona", rating: 85 },
{ id: "t8", name: "Leverkusen", rating: 83 }
]
};
window.onload = () => loadTemplate('superlig');
function loadTemplate(key) {
teams = JSON.parse(JSON.stringify(templates[key]));
renderTeamInputs();
}
function renderTeamInputs() {
const container = document.getElementById('teams-list');
container.innerHTML = '';
teams.forEach((team, index) => {
container.innerHTML += `
<div class="flex items-center gap-3 bg-slate-900 p-3 rounded-xl border border-slate-700">
<span class="text-slate-500 font-bold text-sm w-6">${index + 1}.</span>
<input type="text" value="${team.name}" onchange="updateTeam(${index}, 'name', this.value)"
class="flex-1 bg-slate-800 border border-slate-700 rounded-lg px-3 py-1.5 text-sm text-slate-100 focus
utline-none focus:border-emerald-500" placeholder="Takım İsmi">
<div class="flex items-center gap-2">
<span class="text-xs text-slate-400 font-semibold">Rating:</span>
<input type="number" min="1" max="99" value="${team.rating}" onchange="updateTeam(${index}, 'rating', this.value)"
class="w-16 bg-slate-800 border border-slate-700 rounded-lg px-2 py-1.5 text-sm font-bold text-emerald-400 text-center focus
utline-none focus:border-emerald-500">
</div>
<button onclick="removeTeam(${index})" class="text-rose-400 hover:text-rose-300 p-1.5 transition">
<i class="fa-solid fa-trash-can"></i>
</button>
</div>
`;
});
document.getElementById('team-count').innerText = teams.length;
}
function addTeamField() {
const id = 't_' + Math.random().toString(36).substr(2, 9);
teams.push({ id: id, name: `Takım ${teams.length + 1}`, rating: 75 });
renderTeamInputs();
}
function updateTeam(index, field, value) {
if (field === 'rating') value = Math.max(1, Math.min(99, parseInt(value) || 50));
teams[index][field] = value;
}
function removeTeam(index) {
if (teams.length <= 2) {
alert("En az 2 takım olmalıdır!");
return;
}
teams.splice(index, 1);
renderTeamInputs();
}
function getTeam(id) {
return teams.find(t => t.id === id) || { name: 'Bilinmiyor', rating: 50 };
}
// ================= SİMÜLASYON BAŞLATMA =================
function startSimulation() {
config.type = document.getElementById('tourney-type').value;
config.legs = parseInt(document.getElementById('match-legs').value);
if (teams.length < 2) {
alert("En az 2 takım eklemelisiniz.");
return;
}
if (config.type === 'knockout' && !isPowerOfTwo(teams.length)) {
alert(`Eleme formatında takım sayısı 2'nin katı olmalıdır (2, 4, 8, 16)! Şu anki takım sayısı: ${teams.length}`);
return;
}
// ID Kontrolü
teams.forEach((t, idx) => { if (!t.id) t.id = 't' + idx; });
document.getElementById('setup-panel').classList.add('hidden');
document.getElementById('sim-panel').classList.remove('hidden');
currentRound = 0;
generateSchedule();
recalculateStandings();
renderFixtures();
renderLiveTeamEditor();
}
function isPowerOfTwo(n) {
return n > 0 && (n & (n - 1)) === 0;
}
// ================= MAÇ MATEMATİĞİ =================
function simulateMatchLogic(homeId, awayId) {
const home = getTeam(homeId);
const away = getTeam(awayId);
const diff = home.rating - away.rating;
let expHome = Math.max(0.2, 1.35 + (diff * 0.035) + 0.25);
let expAway = Math.max(0.1, 1.10 - (diff * 0.035));
let homeGoals = generatePoisson(expHome);
let awayGoals = generatePoisson(expAway);
return { homeGoals, awayGoals };
}
function generatePoisson(lambda) {
let L = Math.exp(-lambda), k = 0, p = 1;
do {
k++;
p *= Math.random();
} while (p > L);
return k - 1;
}
// ================= FİKSTÜR KURULUMU =================
function generateSchedule() {
fixtures = [];
let tList = [...teams];
if (config.type === 'league') {
if (tList.length % 2 !== 0) tList.push({ id: "BAY", name: "BAY", rating: 0 });
const n = tList.length;
const totalRounds = (n - 1) * config.legs;
for (let r = 0; r < totalRounds; r++) {
let roundMatches = [];
let isSecondHalf = r >= (n - 1);
for (let i = 0; i < n / 2; i++) {
let t1 = tList;
let t2 = tList[n - 1 - i];
if (t1.id !== "BAY" && t2.id !== "BAY") {
let homeId = isSecondHalf ? t2.id : t1.id;
let awayId = isSecondHalf ? t1.id : t2.id;
roundMatches.push({
homeId: homeId,
awayId: awayId,
homeGoals: null,
awayGoals: null,
played: false
});
}
}
fixtures.push({ roundName: `${r + 1}. Hafta`, matches: roundMatches, played: false });
tList.splice(1, 0, tList.pop());
}
} else {
createKnockoutRound(teams.map(t => t.id), "1. Tur");
}
}
function createKnockoutRound(teamIds, roundTitle) {
let matches = [];
for (let i = 0; i < teamIds.length; i += 2) {
matches.push({
teamAId: teamIds,
teamBId: teamIds[i+1],
leg1: { homeGoals: null, awayGoals: null },
leg2: { homeGoals: null, awayGoals: null },
penalties: null,
winnerId: null,
played: false
});
}
fixtures.push({ roundName: roundTitle, matches: matches, played: false });
}
// ================= SİMÜLASYON VE SKOR YÖNETİMİ =================
function playNextRound() {
if (currentRound >= fixtures.length) return;
let roundData = fixtures[currentRound];
if (config.type === 'league') {
roundData.matches.forEach(m => {
if (!m.played) {
let res = simulateMatchLogic(m.homeId, m.awayId);
m.homeGoals = res.homeGoals;
m.awayGoals = res.awayGoals;
m.played = true;
}
});
roundData.played = true;
currentRound++;
} else {
let nextRoundTeamIds = [];
roundData.matches.forEach(m => {
if (!m.played) {
if (config.legs === 1) {
let res = simulateMatchLogic(m.teamAId, m.teamBId);
m.leg1 = res;
m.played = true;
resolveKnockoutWinner(m);
} else {
let l1 = simulateMatchLogic(m.teamAId, m.teamBId);
let l2 = simulateMatchLogic(m.teamBId, m.teamAId);
m.leg1 = l1;
m.leg2 = l2;
m.played = true;
resolveKnockoutWinner(m);
}
}
nextRoundTeamIds.push(m.winnerId);
});
roundData.played = true;
currentRound++;
if (nextRoundTeamIds.length > 1) {
let nextTitle = nextRoundTeamIds.length === 2 ? "FİNAL" : (nextRoundTeamIds.length === 4 ? "Yarı Final" : "Çeyrek Final");
createKnockoutRound(nextRoundTeamIds, nextTitle);
}
}
recalculateStandings();
renderFixtures();
}
function playAllRounds() {
while (currentRound < fixtures.length) {
playNextRound();
}
}
function resolveKnockoutWinner(match) {
if (config.legs === 1) {
if (match.leg1.homeGoals > match.leg1.awayGoals) {
match.winnerId = match.teamAId;
match.penalties = null;
} else if (match.leg1.awayGoals > match.leg1.homeGoals) {
match.winnerId = match.teamBId;
match.penalties = null;
} else {
let pA = 0, pB = 0;
while (pA === pB) {
pA = Math.floor(Math.random() * 3) + 3;
pB = Math.floor(Math.random() * 3) + 3;
}
match.penalties = { a: pA, b: pB };
match.winnerId = pA > pB ? match.teamAId : match.teamBId;
}
} else {
let aggA = (match.leg1.homeGoals || 0) + (match.leg2.awayGoals || 0);
let aggB = (match.leg1.awayGoals || 0) + (match.leg2.homeGoals || 0);
if (aggA > aggB) {
match.winnerId = match.teamAId;
match.penalties = null;
} else if (aggB > aggA) {
match.winnerId = match.teamBId;
match.penalties = null;
} else {
let pA = 0, pB = 0;
while (pA === pB) {
pA = Math.floor(Math.random() * 3) + 3;
pB = Math.floor(Math.random() * 3) + 3;
}
match.penalties = { a: pA, b: pB };
match.winnerId = pA > pB ? match.teamAId : match.teamBId;
}
}
}
// ================= CANLI SKOR MÜDAHALE (INPUT) =================
function handleLeagueScoreEdit(rIdx, mIdx, side, val) {
let match = fixtures[rIdx].matches[mIdx];
let numVal = val === '' ? null : parseInt(val);
if (side === 'home') match.homeGoals = numVal;
if (side === 'away') match.awayGoals = numVal;
if (match.homeGoals !== null && match.awayGoals !== null) {
match.played = true;
} else if (match.homeGoals === null && match.awayGoals === null) {
match.played = false;
}
fixtures[rIdx].played = fixtures[rIdx].matches.some(m => m.played);
recalculateStandings();
}
function handleKnockoutScoreEdit(rIdx, mIdx, leg, side, val) {
let match = fixtures[rIdx].matches[mIdx];
let numVal = val === '' ? null : parseInt(val);
if (leg === 1) {
if (side === 'home') match.leg1.homeGoals = numVal;
if (side === 'away') match.leg1.awayGoals = numVal;
} else {
if (side === 'home') match.leg2.homeGoals = numVal;
if (side === 'away') match.leg2.awayGoals = numVal;
}
match.played = true;
resolveKnockoutWinner(match);
renderFixtures();
}
// ================= PUAN DURUMU RE-HESAPLAMA MOTORU =================
function recalculateStandings() {
if (config.type === 'league') {
standings = {};
teams.forEach(t => {
standings[t.id] = { id: t.id, name: t.name, p: 0, w: 0, d: 0, l: 0, gf: 0, ga: 0, gd: 0, pts: 0 };
});
fixtures.forEach(round => {
round.matches.forEach(m => {
if (m.played && m.homeGoals !== null && m.awayGoals !== null) {
let h = standings[m.homeId];
let a = standings[m.awayId];
if (h && a) {
h.p++; a.p++;
h.gf += m.homeGoals; h.ga += m.awayGoals; h.gd = h.gf - h.ga;
a.gf += m.awayGoals; a.ga += m.homeGoals; a.gd = a.gf - a.ga;
if (m.homeGoals > m.awayGoals) {
h.w++; h.pts += 3; a.l++;
} else if (m.homeGoals < m.awayGoals) {
a.w++; a.pts += 3; h.l++;
} else {
h.d++; a.d++; h.pts += 1; a.pts += 1;
}
}
}
});
});
renderStandingsTable();
}
}
// ================= CANLI TAKIM VE GÜÇ DÜZENLEME =================
function handleLiveTeamUpdate(id, field, value) {
let t = teams.find(team => team.id === id);
if (t) {
if (field === 'rating') {
t.rating = Math.max(1, Math.min(99, parseInt(value) || 50));
} else {
t.name = value;
}
}
recalculateStandings();
renderFixtures();
}
function renderLiveTeamEditor() {
const container = document.getElementById('live-team-editor');
container.innerHTML = '';
teams.forEach(t => {
container.innerHTML += `
<div class="flex items-center gap-3 bg-slate-900 p-3 rounded-xl border border-slate-700">
<input type="text" value="${t.name}" oninput="handleLiveTeamUpdate('${t.id}', 'name', this.value)"
class="flex-1 bg-slate-800 border border-slate-700 rounded-lg px-3 py-1.5 text-sm text-slate-100 font-semibold focus
utline-none focus:border-emerald-500">
<div class="flex items-center gap-2">
<span class="text-xs text-slate-400 font-semibold">Rating:</span>
<input type="number" min="1" max="99" value="${t.rating}" oninput="handleLiveTeamUpdate('${t.id}', 'rating', this.value)"
class="w-16 bg-slate-800 border border-slate-700 rounded-lg px-2 py-1.5 text-sm font-bold text-emerald-400 text-center focus
utline-none focus:border-emerald-500">
</div>
</div>
`;
});
}
// ================= GÖRÜNTÜLEME =================
function renderFixtures() {
const container = document.getElementById('tab-matches');
container.innerHTML = '';
fixtures.forEach((round, rIdx) => {
let matchCards = '';
if (config.type === 'league') {
round.matches.forEach((m, mIdx) => {
let hTeam = getTeam(m.homeId);
let aTeam = getTeam(m.awayId);
matchCards += `
<div class="flex items-center justify-between py-2 px-3 bg-slate-900 rounded-lg text-sm border border-slate-700/60 my-2">
<span class="w-5/12 text-right font-semibold truncate ${m.played && m.homeGoals > m.awayGoals ? 'text-emerald-400' : 'text-slate-300'}">${hTeam.name}</span>
<div class="w-2/12 flex items-center justify-center gap-1 mx-1">
<input type="number" value="${m.homeGoals !== null ? m.homeGoals : ''}"
oninput="handleLeagueScoreEdit(${rIdx}, ${mIdx}, 'home', this.value)"
class="w-7 h-7 bg-slate-800 border border-slate-600 rounded text-center text-emerald-400 font-bold text-sm focus:border-emerald-400 focus
utline-none">
<span class="text-slate-600 font-black">-</span>
<input type="number" value="${m.awayGoals !== null ? m.awayGoals : ''}"
oninput="handleLeagueScoreEdit(${rIdx}, ${mIdx}, 'away', this.value)"
class="w-7 h-7 bg-slate-800 border border-slate-600 rounded text-center text-emerald-400 font-bold text-sm focus:border-emerald-400 focus
utline-none">
</div>
<span class="w-5/12 text-left font-semibold truncate ${m.played && m.awayGoals > m.homeGoals ? 'text-emerald-400' : 'text-slate-300'}">${aTeam.name}</span>
</div>
`;
});
} else {
// Knockout
round.matches.forEach((m, mIdx) => {
let tA = getTeam(m.teamAId);
let tB = getTeam(m.teamBId);
if (config.legs === 1) {
let penStr = m.penalties ? `<div class="text-center text-xs text-amber-400 mt-1">Penaltılar: ${m.penalties.a} - ${m.penalties.b} (Kazanan: ${getTeam(m.winnerId).name})</div>` : '';
matchCards += `
<div class="p-3 bg-slate-900 rounded-xl border border-slate-700 my-2">
<div class="flex justify-between items-center text-sm mb-1.5">
<span class="font-semibold ${m.winnerId === m.teamAId ? 'text-emerald-400 font-bold' : 'text-slate-300'}">${tA.name}</span>
<input type="number" value="${m.leg1.homeGoals !== null ? m.leg1.homeGoals : ''}"
oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 1, 'home', this.value)"
class="w-7 h-7 bg-slate-800 border border-slate-600 rounded text-center text-emerald-400 font-bold text-sm">
</div>
<div class="flex justify-between items-center text-sm">
<span class="font-semibold ${m.winnerId === m.teamBId ? 'text-emerald-400 font-bold' : 'text-slate-300'}">${tB.name}</span>
<input type="number" value="${m.leg1.awayGoals !== null ? m.leg1.awayGoals : ''}"
oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 1, 'away', this.value)"
class="w-7 h-7 bg-slate-800 border border-slate-600 rounded text-center text-emerald-400 font-bold text-sm">
</div>
${penStr}
</div>
`;
} else {
let aggA = (m.leg1.homeGoals || 0) + (m.leg2.awayGoals || 0);
let aggB = (m.leg1.awayGoals || 0) + (m.leg2.homeGoals || 0);
let penStr = m.penalties ? `<div class="text-center text-xs text-amber-400 mt-1">Penaltılar: ${m.penalties.a} - ${m.penalties.b}</div>` : '';
matchCards += `
<div class="p-3 bg-slate-900 rounded-xl border border-slate-700 my-2 space-y-2">
<div class="text-xs text-slate-400 flex justify-between items-center border-b border-slate-800 pb-1">
<span>1. Maç:</span>
<div class="flex gap-1">
<input type="number" value="${m.leg1.homeGoals !== null ? m.leg1.homeGoals : ''}" oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 1, 'home', this.value)" class="w-6 h-6 bg-slate-800 border border-slate-700 rounded text-center text-xs"> -
<input type="number" value="${m.leg1.awayGoals !== null ? m.leg1.awayGoals : ''}" oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 1, 'away', this.value)" class="w-6 h-6 bg-slate-800 border border-slate-700 rounded text-center text-xs">
</div>
</div>
<div class="text-xs text-slate-400 flex justify-between items-center border-b border-slate-800 pb-1">
<span>2. Maç:</span>
<div class="flex gap-1">
<input type="number" value="${m.leg2.homeGoals !== null ? m.leg2.homeGoals : ''}" oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 2, 'home', this.value)" class="w-6 h-6 bg-slate-800 border border-slate-700 rounded text-center text-xs"> -
<input type="number" value="${m.leg2.awayGoals !== null ? m.leg2.awayGoals : ''}" oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 2, 'away', this.value)" class="w-6 h-6 bg-slate-800 border border-slate-700 rounded text-center text-xs">
</div>
</div>
<div class="flex justify-between items-center text-sm font-bold pt-1">
<span class="${m.winnerId === m.teamAId ? 'text-emerald-400' : ''}">${tA.name}</span>
<span class="text-slate-400 text-xs">Toplam: ${aggA} - ${aggB}</span>
<span class="${m.winnerId === m.teamBId ? 'text-emerald-400' : ''}">${tB.name}</span>
</div>
${penStr}
</div>
`;
}
});
}
container.innerHTML += `
<div class="bg-slate-800 p-4 rounded-2xl border ${round.played ? 'border-slate-700' : 'border-emerald-600/40'} shadow-lg">
<div class="flex justify-between items-center mb-3">
<span class="font-bold text-emerald-400">${round.roundName}</span>
<span class="text-xs text-slate-400"><i class="fa-solid fa-pen"></i> Skorları elle değiştirebilirsiniz</span>
</div>
<div>${matchCards}</div>
</div>
`;
});
}
function renderStandingsTable() {
const container = document.getElementById('standings-content');
if (config.type === 'league') {
let sorted = Object.values(standings).sort((a,b) => b.pts - a.pts || b.gd - a.gd || b.gf - a.gf);
let rows = sorted.map((t, i) => `
<tr class="border-b border-slate-700/60 hover:bg-slate-700/30 text-sm">
<td class="py-3 px-3 font-bold ${i === 0 ? 'text-amber-400' : 'text-slate-400'}">${i + 1}</td>
<td class="py-3 px-3 font-semibold text-slate-100">${getTeam(t.id).name}</td>
<td class="py-3 px-3 text-center">${t.p}</td>
<td class="py-3 px-3 text-center text-emerald-400">${t.w}</td>
<td class="py-3 px-3 text-center text-slate-400">${t.d}</td>
<td class="py-3 px-3 text-center text-rose-400">${t.l}</td>
<td class="py-3 px-3 text-center">${t.gf}</td>
<td class="py-3 px-3 text-center">${t.ga}</td>
<td class="py-3 px-3 text-center font-semibold">${t.gd > 0 ? '+'+t.gd : t.gd}</td>
<td class="py-3 px-3 text-center font-black text-emerald-300 text-base">${t.pts}</td>
</tr>
`).join('');
container.innerHTML = `
<table class="w-full text-left border-collapse min-w-[500px]">
<thead>
<tr class="text-xs font-bold text-slate-400 border-b border-slate-700 uppercase bg-slate-900/50">
<th class="py-3 px-3">#</th>
<th class="py-3 px-3">Takım</th>
<th class="py-3 px-3 text-center">O</th>
<th class="py-3 px-3 text-center">G</th>
<th class="py-3 px-3 text-center">B</th>
<th class="py-3 px-3 text-center">M</th>
<th class="py-3 px-3 text-center">AG</th>
<th class="py-3 px-3 text-center">YG</th>
<th class="py-3 px-3 text-center">AV</th>
<th class="py-3 px-3 text-center">P</th>
</tr>
</thead>
<tbody>${rows}</tbody>
</table>
`;
if (sorted.length > 0 && sorted[0].p > 0) {
document.getElementById('champion-name').innerText = getTeam(sorted[0].id).name;
document.getElementById('winner-banner').classList.remove('hidden');
}
} else {
container.innerHTML = `
<div class="text-center py-8 text-slate-400">
<i class="fa-solid fa-sitemap text-4xl mb-3 text-slate-600 block"></i>
Eleme turlarında skorları ve bir üst tura çıkanları <b>"Fikstür & Skorlar"</b> sekmesinden takip edebilir veya düzenleyebilirsiniz.
</div>
`;
}
}
// ================= SEKME VE SIFIRLAMA =================
function switchTab(tab) {
['matches', 'standings', 'teams'].forEach(t => {
document.getElementById(`tab-${t}`).classList.add('hidden');
document.getElementById(`tab-${t}-btn`).classList.remove('active');
});
document.getElementById(`tab-${tab}`).classList.remove('hidden');
document.getElementById(`tab-${tab}-btn`).classList.add('active');
if (tab === 'standings') recalculateStandings();
if (tab === 'teams') renderLiveTeamEditor();
}
function resetAll() {
document.getElementById('setup-panel').classList.remove('hidden');
document.getElementById('sim-panel').classList.add('hidden');
document.getElementById('winner-banner').classList.add('hidden');
switchTab('matches');
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Futbol Simülasyon Motoru (Canlı Düzenlenebilir)</title>
<!-- Tailwind CSS -->
<script src="
Linki görebilmek için üye olmanız gerekiyor.
Giriş yap veya üye ol.
"></script><link rel="stylesheet" href="
Linki görebilmek için üye olmanız gerekiyor.
Giriş yap veya üye ol.
"><style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
.tab-btn.active { border-bottom: 3px solid #10b981; color: #10b981; font-weight: bold; }
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
input[type=number] { -moz-appearance: textfield; }
</style>
</head>
<body class="bg-slate-900 text-slate-100 min-h-screen">
<div class="max-w-6xl mx-auto p-4 md
<!-- ÜST BAŞLIK -->
<header class="text-center mb-8 border-b border-slate-800 pb-6">
<h1 class="text-3xl md:text-4xl font-extrabold text-emerald-400 tracking-wide flex items-center justify-center gap-3">
<i class="fa-solid fa-futbol"></i> Futbol Simülasyon & Yönetim Motoru
</h1>
<p class="text-slate-400 mt-2 text-sm md:text-base">Canlı İstatistik Düzenleme ve Skor Müdahale Özellikli</p>
</header>
<!-- PANEL 1: AYARLAR VE TAKIM LİSTESİ -->
<section id="setup-panel" class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div class="bg-slate-800 p-6 rounded-2xl shadow-xl border border-slate-700 h-fit">
<h2 class="text-xl font-bold mb-4 text-emerald-300 border-b border-slate-700 pb-2">
<i class="fa-solid fa-sliders"></i> Turnuva Ayarları
</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-semibold mb-1 text-slate-300">Format:</label>
<select id="tourney-type" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2.5 text-slate-200 focus
<option value="league">Lig Usulü (Puan Tablosu)</option>
<option value="knockout">Eleme Turnuvası (Bracket)</option>
</select>
</div>
<div>
<label class="block text-sm font-semibold mb-1 text-slate-300">Maç Tipi:</label>
<select id="match-legs" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2.5 text-slate-200 focus
<option value="1">Tek Maç</option>
<option value="2">Çift Maç (Rövanşlı)</option>
</select>
</div>
<div class="pt-4 border-t border-slate-700">
<label class="block text-sm font-semibold mb-2 text-slate-300">Hazır Şablonlar:</label>
<div class="grid grid-cols-2 gap-2">
<button onclick="loadTemplate('superlig')" class="bg-slate-700 hover:bg-slate-600 text-xs py-2 px-3 rounded text-center transition">Süper Lig (4 Takım)</button>
<button onclick="loadTemplate('ucl')" class="bg-slate-700 hover:bg-slate-600 text-xs py-2 px-3 rounded text-center transition">Şampiyonlar Ligi (8 Takım)</button>
</div>
</div>
<button onclick="startSimulation()" class="w-full bg-emerald-600 hover:bg-emerald-500 text-white font-bold py-3 px-4 rounded-xl shadow-lg transition duration-200 mt-6 flex items-center justify-center gap-2">
<i class="fa-solid fa-play"></i> Turnuvayı Başlat
</button>
</div>
</div>
<!-- Takım Listesi -->
<div class="lg:col-span-2 bg-slate-800 p-6 rounded-2xl shadow-xl border border-slate-700">
<div class="flex justify-between items-center mb-4 border-b border-slate-700 pb-2">
<h2 class="text-xl font-bold text-emerald-300">
<i class="fa-solid fa-shield-halved"></i> Başlangıç Takımları (<span id="team-count">0</span>)
</h2>
<button onclick="addTeamField()" class="text-xs bg-emerald-700 hover:bg-emerald-600 px-3 py-1.5 rounded-lg text-white font-semibold transition">
<i class="fa-solid fa-plus"></i> Takım Ekle
</button>
</div>
<div id="teams-list" class="space-y-3 max-h-[420px] overflow-y-auto pr-2"></div>
</div>
</section>
<!-- PANEL 2: OYUN / SİMÜLASYON EKRANI -->
<section id="sim-panel" class="hidden">
<!-- Kontrol Çubuğu -->
<div class="flex flex-wrap justify-between items-center bg-slate-800 p-4 rounded-xl border border-slate-700 mb-6 gap-4">
<div class="flex gap-2 md:gap-6 border-b border-slate-700 md:border-b-0">
<button id="tab-matches-btn" onclick="switchTab('matches')" class="tab-btn active pb-2 px-2 text-sm md:text-base">
<i class="fa-solid fa-calendar-days"></i> Fikstür & Skorlar
</button>
<button id="tab-standings-btn" onclick="switchTab('standings')" class="tab-btn pb-2 px-2 text-sm md:text-base">
<i class="fa-solid fa-table-list"></i> Puan Durumu / Eşleşme
</button>
<button id="tab-teams-btn" onclick="switchTab('teams')" class="tab-btn pb-2 px-2 text-sm md:text-base">
<i class="fa-solid fa-sliders"></i> Takım & Güç Yönetimi
</button>
</div>
<div class="flex flex-wrap gap-2">
<button onclick="playNextRound()" id="next-round-btn" class="bg-emerald-600 hover:bg-emerald-500 text-white font-semibold px-3 py-1.5 md
<i class="fa-solid fa-forward-step"></i> Sıradaki Tur
</button>
<button onclick="playAllRounds()" id="all-rounds-btn" class="bg-teal-600 hover:bg-teal-500 text-white font-semibold px-3 py-1.5 md
<i class="fa-solid fa-forward-fast"></i> Hepsini Oyna
</button>
<button onclick="resetAll()" class="bg-rose-700 hover:bg-rose-600 text-white font-semibold px-3 py-1.5 md
<i class="fa-solid fa-rotate-left"></i> Sıfırla
</button>
</div>
</div>
<!-- Şampiyon Kartı -->
<div id="winner-banner" class="hidden mb-6 p-5 bg-gradient-to-r from-amber-600 to-yellow-500 rounded-2xl text-center shadow-xl">
<h3 class="text-2xl font-black text-slate-900 flex items-center justify-center gap-2">
<i class="fa-solid fa-trophy text-3xl"></i> KAZANAN / LİDER: <span id="champion-name"></span>!
</h3>
</div>
<!-- TAB 1: MAÇLAR & SKOR MÜDAHALESİ -->
<div id="tab-matches" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"></div>
<!-- TAB 2: PUAN DURUMU / ELEME TABLOSU -->
<div id="tab-standings" class="hidden bg-slate-800 p-6 rounded-2xl border border-slate-700 shadow-xl overflow-x-auto">
<div id="standings-content"></div>
</div>
<!-- TAB 3: CANLI TAKIM VE GÜÇ YÖNETİMİ -->
<div id="tab-teams" class="hidden bg-slate-800 p-6 rounded-2xl border border-slate-700 shadow-xl">
<div class="max-w-xl mx-auto">
<h3 class="text-lg font-bold text-emerald-300 mb-2 border-b border-slate-700 pb-2">
<i class="fa-solid fa-pen-to-square"></i> Canlı Güç & İsim Düzenleyici
</h3>
<p class="text-xs text-slate-400 mb-4">Burada yapacağınız değişiklikler oynanmamış tüm gelecek maçlara anında etki eder.</p>
<div id="live-team-editor" class="space-y-3"></div>
</div>
</div>
</section>
</div>
<!-- JAVASCRIPT MOTORU -->
<script>
let teams = [];
let fixtures = [];
let currentRound = 0;
let config = { type: 'league', legs: 1 };
let standings = {};
const templates = {
superlig: [
{ id: "t1", name: "Galatasaray", rating: 83 },
{ id: "t2", name: "Fenerbahçe", rating: 82 },
{ id: "t3", name: "Beşiktaş", rating: 78 },
{ id: "t4", name: "Trabzonspor", rating: 76 }
],
ucl: [
{ id: "t1", name: "Real Madrid", rating: 89 },
{ id: "t2", name: "Manchester City", rating: 90 },
{ id: "t3", name: "Bayern Münih", rating: 87 },
{ id: "t4", name: "PSG", rating: 85 },
{ id: "t5", name: "Arsenal", rating: 86 },
{ id: "t6", name: "Inter", rating: 84 },
{ id: "t7", name: "Barcelona", rating: 85 },
{ id: "t8", name: "Leverkusen", rating: 83 }
]
};
window.onload = () => loadTemplate('superlig');
function loadTemplate(key) {
teams = JSON.parse(JSON.stringify(templates[key]));
renderTeamInputs();
}
function renderTeamInputs() {
const container = document.getElementById('teams-list');
container.innerHTML = '';
teams.forEach((team, index) => {
container.innerHTML += `
<div class="flex items-center gap-3 bg-slate-900 p-3 rounded-xl border border-slate-700">
<span class="text-slate-500 font-bold text-sm w-6">${index + 1}.</span>
<input type="text" value="${team.name}" onchange="updateTeam(${index}, 'name', this.value)"
class="flex-1 bg-slate-800 border border-slate-700 rounded-lg px-3 py-1.5 text-sm text-slate-100 focus
<div class="flex items-center gap-2">
<span class="text-xs text-slate-400 font-semibold">Rating:</span>
<input type="number" min="1" max="99" value="${team.rating}" onchange="updateTeam(${index}, 'rating', this.value)"
class="w-16 bg-slate-800 border border-slate-700 rounded-lg px-2 py-1.5 text-sm font-bold text-emerald-400 text-center focus
</div>
<button onclick="removeTeam(${index})" class="text-rose-400 hover:text-rose-300 p-1.5 transition">
<i class="fa-solid fa-trash-can"></i>
</button>
</div>
`;
});
document.getElementById('team-count').innerText = teams.length;
}
function addTeamField() {
const id = 't_' + Math.random().toString(36).substr(2, 9);
teams.push({ id: id, name: `Takım ${teams.length + 1}`, rating: 75 });
renderTeamInputs();
}
function updateTeam(index, field, value) {
if (field === 'rating') value = Math.max(1, Math.min(99, parseInt(value) || 50));
teams[index][field] = value;
}
function removeTeam(index) {
if (teams.length <= 2) {
alert("En az 2 takım olmalıdır!");
return;
}
teams.splice(index, 1);
renderTeamInputs();
}
function getTeam(id) {
return teams.find(t => t.id === id) || { name: 'Bilinmiyor', rating: 50 };
}
// ================= SİMÜLASYON BAŞLATMA =================
function startSimulation() {
config.type = document.getElementById('tourney-type').value;
config.legs = parseInt(document.getElementById('match-legs').value);
if (teams.length < 2) {
alert("En az 2 takım eklemelisiniz.");
return;
}
if (config.type === 'knockout' && !isPowerOfTwo(teams.length)) {
alert(`Eleme formatında takım sayısı 2'nin katı olmalıdır (2, 4, 8, 16)! Şu anki takım sayısı: ${teams.length}`);
return;
}
// ID Kontrolü
teams.forEach((t, idx) => { if (!t.id) t.id = 't' + idx; });
document.getElementById('setup-panel').classList.add('hidden');
document.getElementById('sim-panel').classList.remove('hidden');
currentRound = 0;
generateSchedule();
recalculateStandings();
renderFixtures();
renderLiveTeamEditor();
}
function isPowerOfTwo(n) {
return n > 0 && (n & (n - 1)) === 0;
}
// ================= MAÇ MATEMATİĞİ =================
function simulateMatchLogic(homeId, awayId) {
const home = getTeam(homeId);
const away = getTeam(awayId);
const diff = home.rating - away.rating;
let expHome = Math.max(0.2, 1.35 + (diff * 0.035) + 0.25);
let expAway = Math.max(0.1, 1.10 - (diff * 0.035));
let homeGoals = generatePoisson(expHome);
let awayGoals = generatePoisson(expAway);
return { homeGoals, awayGoals };
}
function generatePoisson(lambda) {
let L = Math.exp(-lambda), k = 0, p = 1;
do {
k++;
p *= Math.random();
} while (p > L);
return k - 1;
}
// ================= FİKSTÜR KURULUMU =================
function generateSchedule() {
fixtures = [];
let tList = [...teams];
if (config.type === 'league') {
if (tList.length % 2 !== 0) tList.push({ id: "BAY", name: "BAY", rating: 0 });
const n = tList.length;
const totalRounds = (n - 1) * config.legs;
for (let r = 0; r < totalRounds; r++) {
let roundMatches = [];
let isSecondHalf = r >= (n - 1);
for (let i = 0; i < n / 2; i++) {
let t1 = tList;
let t2 = tList[n - 1 - i];
if (t1.id !== "BAY" && t2.id !== "BAY") {
let homeId = isSecondHalf ? t2.id : t1.id;
let awayId = isSecondHalf ? t1.id : t2.id;
roundMatches.push({
homeId: homeId,
awayId: awayId,
homeGoals: null,
awayGoals: null,
played: false
});
}
}
fixtures.push({ roundName: `${r + 1}. Hafta`, matches: roundMatches, played: false });
tList.splice(1, 0, tList.pop());
}
} else {
createKnockoutRound(teams.map(t => t.id), "1. Tur");
}
}
function createKnockoutRound(teamIds, roundTitle) {
let matches = [];
for (let i = 0; i < teamIds.length; i += 2) {
matches.push({
teamAId: teamIds,
teamBId: teamIds[i+1],
leg1: { homeGoals: null, awayGoals: null },
leg2: { homeGoals: null, awayGoals: null },
penalties: null,
winnerId: null,
played: false
});
}
fixtures.push({ roundName: roundTitle, matches: matches, played: false });
}
// ================= SİMÜLASYON VE SKOR YÖNETİMİ =================
function playNextRound() {
if (currentRound >= fixtures.length) return;
let roundData = fixtures[currentRound];
if (config.type === 'league') {
roundData.matches.forEach(m => {
if (!m.played) {
let res = simulateMatchLogic(m.homeId, m.awayId);
m.homeGoals = res.homeGoals;
m.awayGoals = res.awayGoals;
m.played = true;
}
});
roundData.played = true;
currentRound++;
} else {
let nextRoundTeamIds = [];
roundData.matches.forEach(m => {
if (!m.played) {
if (config.legs === 1) {
let res = simulateMatchLogic(m.teamAId, m.teamBId);
m.leg1 = res;
m.played = true;
resolveKnockoutWinner(m);
} else {
let l1 = simulateMatchLogic(m.teamAId, m.teamBId);
let l2 = simulateMatchLogic(m.teamBId, m.teamAId);
m.leg1 = l1;
m.leg2 = l2;
m.played = true;
resolveKnockoutWinner(m);
}
}
nextRoundTeamIds.push(m.winnerId);
});
roundData.played = true;
currentRound++;
if (nextRoundTeamIds.length > 1) {
let nextTitle = nextRoundTeamIds.length === 2 ? "FİNAL" : (nextRoundTeamIds.length === 4 ? "Yarı Final" : "Çeyrek Final");
createKnockoutRound(nextRoundTeamIds, nextTitle);
}
}
recalculateStandings();
renderFixtures();
}
function playAllRounds() {
while (currentRound < fixtures.length) {
playNextRound();
}
}
function resolveKnockoutWinner(match) {
if (config.legs === 1) {
if (match.leg1.homeGoals > match.leg1.awayGoals) {
match.winnerId = match.teamAId;
match.penalties = null;
} else if (match.leg1.awayGoals > match.leg1.homeGoals) {
match.winnerId = match.teamBId;
match.penalties = null;
} else {
let pA = 0, pB = 0;
while (pA === pB) {
pA = Math.floor(Math.random() * 3) + 3;
pB = Math.floor(Math.random() * 3) + 3;
}
match.penalties = { a: pA, b: pB };
match.winnerId = pA > pB ? match.teamAId : match.teamBId;
}
} else {
let aggA = (match.leg1.homeGoals || 0) + (match.leg2.awayGoals || 0);
let aggB = (match.leg1.awayGoals || 0) + (match.leg2.homeGoals || 0);
if (aggA > aggB) {
match.winnerId = match.teamAId;
match.penalties = null;
} else if (aggB > aggA) {
match.winnerId = match.teamBId;
match.penalties = null;
} else {
let pA = 0, pB = 0;
while (pA === pB) {
pA = Math.floor(Math.random() * 3) + 3;
pB = Math.floor(Math.random() * 3) + 3;
}
match.penalties = { a: pA, b: pB };
match.winnerId = pA > pB ? match.teamAId : match.teamBId;
}
}
}
// ================= CANLI SKOR MÜDAHALE (INPUT) =================
function handleLeagueScoreEdit(rIdx, mIdx, side, val) {
let match = fixtures[rIdx].matches[mIdx];
let numVal = val === '' ? null : parseInt(val);
if (side === 'home') match.homeGoals = numVal;
if (side === 'away') match.awayGoals = numVal;
if (match.homeGoals !== null && match.awayGoals !== null) {
match.played = true;
} else if (match.homeGoals === null && match.awayGoals === null) {
match.played = false;
}
fixtures[rIdx].played = fixtures[rIdx].matches.some(m => m.played);
recalculateStandings();
}
function handleKnockoutScoreEdit(rIdx, mIdx, leg, side, val) {
let match = fixtures[rIdx].matches[mIdx];
let numVal = val === '' ? null : parseInt(val);
if (leg === 1) {
if (side === 'home') match.leg1.homeGoals = numVal;
if (side === 'away') match.leg1.awayGoals = numVal;
} else {
if (side === 'home') match.leg2.homeGoals = numVal;
if (side === 'away') match.leg2.awayGoals = numVal;
}
match.played = true;
resolveKnockoutWinner(match);
renderFixtures();
}
// ================= PUAN DURUMU RE-HESAPLAMA MOTORU =================
function recalculateStandings() {
if (config.type === 'league') {
standings = {};
teams.forEach(t => {
standings[t.id] = { id: t.id, name: t.name, p: 0, w: 0, d: 0, l: 0, gf: 0, ga: 0, gd: 0, pts: 0 };
});
fixtures.forEach(round => {
round.matches.forEach(m => {
if (m.played && m.homeGoals !== null && m.awayGoals !== null) {
let h = standings[m.homeId];
let a = standings[m.awayId];
if (h && a) {
h.p++; a.p++;
h.gf += m.homeGoals; h.ga += m.awayGoals; h.gd = h.gf - h.ga;
a.gf += m.awayGoals; a.ga += m.homeGoals; a.gd = a.gf - a.ga;
if (m.homeGoals > m.awayGoals) {
h.w++; h.pts += 3; a.l++;
} else if (m.homeGoals < m.awayGoals) {
a.w++; a.pts += 3; h.l++;
} else {
h.d++; a.d++; h.pts += 1; a.pts += 1;
}
}
}
});
});
renderStandingsTable();
}
}
// ================= CANLI TAKIM VE GÜÇ DÜZENLEME =================
function handleLiveTeamUpdate(id, field, value) {
let t = teams.find(team => team.id === id);
if (t) {
if (field === 'rating') {
t.rating = Math.max(1, Math.min(99, parseInt(value) || 50));
} else {
t.name = value;
}
}
recalculateStandings();
renderFixtures();
}
function renderLiveTeamEditor() {
const container = document.getElementById('live-team-editor');
container.innerHTML = '';
teams.forEach(t => {
container.innerHTML += `
<div class="flex items-center gap-3 bg-slate-900 p-3 rounded-xl border border-slate-700">
<input type="text" value="${t.name}" oninput="handleLiveTeamUpdate('${t.id}', 'name', this.value)"
class="flex-1 bg-slate-800 border border-slate-700 rounded-lg px-3 py-1.5 text-sm text-slate-100 font-semibold focus
<div class="flex items-center gap-2">
<span class="text-xs text-slate-400 font-semibold">Rating:</span>
<input type="number" min="1" max="99" value="${t.rating}" oninput="handleLiveTeamUpdate('${t.id}', 'rating', this.value)"
class="w-16 bg-slate-800 border border-slate-700 rounded-lg px-2 py-1.5 text-sm font-bold text-emerald-400 text-center focus
</div>
</div>
`;
});
}
// ================= GÖRÜNTÜLEME =================
function renderFixtures() {
const container = document.getElementById('tab-matches');
container.innerHTML = '';
fixtures.forEach((round, rIdx) => {
let matchCards = '';
if (config.type === 'league') {
round.matches.forEach((m, mIdx) => {
let hTeam = getTeam(m.homeId);
let aTeam = getTeam(m.awayId);
matchCards += `
<div class="flex items-center justify-between py-2 px-3 bg-slate-900 rounded-lg text-sm border border-slate-700/60 my-2">
<span class="w-5/12 text-right font-semibold truncate ${m.played && m.homeGoals > m.awayGoals ? 'text-emerald-400' : 'text-slate-300'}">${hTeam.name}</span>
<div class="w-2/12 flex items-center justify-center gap-1 mx-1">
<input type="number" value="${m.homeGoals !== null ? m.homeGoals : ''}"
oninput="handleLeagueScoreEdit(${rIdx}, ${mIdx}, 'home', this.value)"
class="w-7 h-7 bg-slate-800 border border-slate-600 rounded text-center text-emerald-400 font-bold text-sm focus:border-emerald-400 focus
<span class="text-slate-600 font-black">-</span>
<input type="number" value="${m.awayGoals !== null ? m.awayGoals : ''}"
oninput="handleLeagueScoreEdit(${rIdx}, ${mIdx}, 'away', this.value)"
class="w-7 h-7 bg-slate-800 border border-slate-600 rounded text-center text-emerald-400 font-bold text-sm focus:border-emerald-400 focus
</div>
<span class="w-5/12 text-left font-semibold truncate ${m.played && m.awayGoals > m.homeGoals ? 'text-emerald-400' : 'text-slate-300'}">${aTeam.name}</span>
</div>
`;
});
} else {
// Knockout
round.matches.forEach((m, mIdx) => {
let tA = getTeam(m.teamAId);
let tB = getTeam(m.teamBId);
if (config.legs === 1) {
let penStr = m.penalties ? `<div class="text-center text-xs text-amber-400 mt-1">Penaltılar: ${m.penalties.a} - ${m.penalties.b} (Kazanan: ${getTeam(m.winnerId).name})</div>` : '';
matchCards += `
<div class="p-3 bg-slate-900 rounded-xl border border-slate-700 my-2">
<div class="flex justify-between items-center text-sm mb-1.5">
<span class="font-semibold ${m.winnerId === m.teamAId ? 'text-emerald-400 font-bold' : 'text-slate-300'}">${tA.name}</span>
<input type="number" value="${m.leg1.homeGoals !== null ? m.leg1.homeGoals : ''}"
oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 1, 'home', this.value)"
class="w-7 h-7 bg-slate-800 border border-slate-600 rounded text-center text-emerald-400 font-bold text-sm">
</div>
<div class="flex justify-between items-center text-sm">
<span class="font-semibold ${m.winnerId === m.teamBId ? 'text-emerald-400 font-bold' : 'text-slate-300'}">${tB.name}</span>
<input type="number" value="${m.leg1.awayGoals !== null ? m.leg1.awayGoals : ''}"
oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 1, 'away', this.value)"
class="w-7 h-7 bg-slate-800 border border-slate-600 rounded text-center text-emerald-400 font-bold text-sm">
</div>
${penStr}
</div>
`;
} else {
let aggA = (m.leg1.homeGoals || 0) + (m.leg2.awayGoals || 0);
let aggB = (m.leg1.awayGoals || 0) + (m.leg2.homeGoals || 0);
let penStr = m.penalties ? `<div class="text-center text-xs text-amber-400 mt-1">Penaltılar: ${m.penalties.a} - ${m.penalties.b}</div>` : '';
matchCards += `
<div class="p-3 bg-slate-900 rounded-xl border border-slate-700 my-2 space-y-2">
<div class="text-xs text-slate-400 flex justify-between items-center border-b border-slate-800 pb-1">
<span>1. Maç:</span>
<div class="flex gap-1">
<input type="number" value="${m.leg1.homeGoals !== null ? m.leg1.homeGoals : ''}" oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 1, 'home', this.value)" class="w-6 h-6 bg-slate-800 border border-slate-700 rounded text-center text-xs"> -
<input type="number" value="${m.leg1.awayGoals !== null ? m.leg1.awayGoals : ''}" oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 1, 'away', this.value)" class="w-6 h-6 bg-slate-800 border border-slate-700 rounded text-center text-xs">
</div>
</div>
<div class="text-xs text-slate-400 flex justify-between items-center border-b border-slate-800 pb-1">
<span>2. Maç:</span>
<div class="flex gap-1">
<input type="number" value="${m.leg2.homeGoals !== null ? m.leg2.homeGoals : ''}" oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 2, 'home', this.value)" class="w-6 h-6 bg-slate-800 border border-slate-700 rounded text-center text-xs"> -
<input type="number" value="${m.leg2.awayGoals !== null ? m.leg2.awayGoals : ''}" oninput="handleKnockoutScoreEdit(${rIdx}, ${mIdx}, 2, 'away', this.value)" class="w-6 h-6 bg-slate-800 border border-slate-700 rounded text-center text-xs">
</div>
</div>
<div class="flex justify-between items-center text-sm font-bold pt-1">
<span class="${m.winnerId === m.teamAId ? 'text-emerald-400' : ''}">${tA.name}</span>
<span class="text-slate-400 text-xs">Toplam: ${aggA} - ${aggB}</span>
<span class="${m.winnerId === m.teamBId ? 'text-emerald-400' : ''}">${tB.name}</span>
</div>
${penStr}
</div>
`;
}
});
}
container.innerHTML += `
<div class="bg-slate-800 p-4 rounded-2xl border ${round.played ? 'border-slate-700' : 'border-emerald-600/40'} shadow-lg">
<div class="flex justify-between items-center mb-3">
<span class="font-bold text-emerald-400">${round.roundName}</span>
<span class="text-xs text-slate-400"><i class="fa-solid fa-pen"></i> Skorları elle değiştirebilirsiniz</span>
</div>
<div>${matchCards}</div>
</div>
`;
});
}
function renderStandingsTable() {
const container = document.getElementById('standings-content');
if (config.type === 'league') {
let sorted = Object.values(standings).sort((a,b) => b.pts - a.pts || b.gd - a.gd || b.gf - a.gf);
let rows = sorted.map((t, i) => `
<tr class="border-b border-slate-700/60 hover:bg-slate-700/30 text-sm">
<td class="py-3 px-3 font-bold ${i === 0 ? 'text-amber-400' : 'text-slate-400'}">${i + 1}</td>
<td class="py-3 px-3 font-semibold text-slate-100">${getTeam(t.id).name}</td>
<td class="py-3 px-3 text-center">${t.p}</td>
<td class="py-3 px-3 text-center text-emerald-400">${t.w}</td>
<td class="py-3 px-3 text-center text-slate-400">${t.d}</td>
<td class="py-3 px-3 text-center text-rose-400">${t.l}</td>
<td class="py-3 px-3 text-center">${t.gf}</td>
<td class="py-3 px-3 text-center">${t.ga}</td>
<td class="py-3 px-3 text-center font-semibold">${t.gd > 0 ? '+'+t.gd : t.gd}</td>
<td class="py-3 px-3 text-center font-black text-emerald-300 text-base">${t.pts}</td>
</tr>
`).join('');
container.innerHTML = `
<table class="w-full text-left border-collapse min-w-[500px]">
<thead>
<tr class="text-xs font-bold text-slate-400 border-b border-slate-700 uppercase bg-slate-900/50">
<th class="py-3 px-3">#</th>
<th class="py-3 px-3">Takım</th>
<th class="py-3 px-3 text-center">O</th>
<th class="py-3 px-3 text-center">G</th>
<th class="py-3 px-3 text-center">B</th>
<th class="py-3 px-3 text-center">M</th>
<th class="py-3 px-3 text-center">AG</th>
<th class="py-3 px-3 text-center">YG</th>
<th class="py-3 px-3 text-center">AV</th>
<th class="py-3 px-3 text-center">P</th>
</tr>
</thead>
<tbody>${rows}</tbody>
</table>
`;
if (sorted.length > 0 && sorted[0].p > 0) {
document.getElementById('champion-name').innerText = getTeam(sorted[0].id).name;
document.getElementById('winner-banner').classList.remove('hidden');
}
} else {
container.innerHTML = `
<div class="text-center py-8 text-slate-400">
<i class="fa-solid fa-sitemap text-4xl mb-3 text-slate-600 block"></i>
Eleme turlarında skorları ve bir üst tura çıkanları <b>"Fikstür & Skorlar"</b> sekmesinden takip edebilir veya düzenleyebilirsiniz.
</div>
`;
}
}
// ================= SEKME VE SIFIRLAMA =================
function switchTab(tab) {
['matches', 'standings', 'teams'].forEach(t => {
document.getElementById(`tab-${t}`).classList.add('hidden');
document.getElementById(`tab-${t}-btn`).classList.remove('active');
});
document.getElementById(`tab-${tab}`).classList.remove('hidden');
document.getElementById(`tab-${tab}-btn`).classList.add('active');
if (tab === 'standings') recalculateStandings();
if (tab === 'teams') renderLiveTeamEditor();
}
function resetAll() {
document.getElementById('setup-panel').classList.remove('hidden');
document.getElementById('sim-panel').classList.add('hidden');
document.getElementById('winner-banner').classList.add('hidden');
switchTab('matches');
}
</script>
</body>
</html>