hamle geri al - ses aç - kapa - oyun kuralları - menü

menü de mod bölümünde 2 adet mod bulunuyor 2 kişi aynı bilgisayarda veya yapay zekaya karşı



3 adet zorluk bölümü var kolay -orta - zor




başla diyoruz oyun başlıyor zarlar otomatik atıyor








pul toplama ise çift tıklayarak gerçekleşmekte oyun bitince oyun özetini txt olarak indirebiliyorsunuz




kodlar;

<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Türk Tavlası - Büyük Pullar</title>
    <style>
        :root {
            --wood-primary: #8B4513;
            --wood-secondary: #DEB887;
            --wood-border: #5D4037;
            --point-dark: #3E2723;
            --point-light: #D7CCC8;
            --checker-white: #F5F5F5;
            --checker-black: #111;
            --highlight-color: rgba(0, 255, 0, 0.5);
            --text-color: #fff;
        }

        * { box-sizing: border-box; user-select: none; -webkit-user-select: none; touch-action: manipulation; }

        body {
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: #222;
            color: var(--text-color);
            height: 100vh;
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        /* --- UI HEADER --- */
        header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 20px;
            background: #1a1a1a;
            border-bottom: 2px solid #444;
            height: 60px;
            z-index: 10;
        }

        h1 { margin: 0; font-size: 1.2rem; color: var(--wood-secondary); }

        .controls { display: flex; gap: 10px; }

        button {
            background: #444;
            border: none;
            color: white;
            padding: 5px 12px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 0.9rem;
            transition: background 0.2s;
        }
        button:hover { background: #666; }
        button:disabled { opacity: 0.5; cursor: not-allowed; }
        button.primary { background: var(--wood-primary); font-weight: bold; }

        /* --- GAME AREA --- */
        #game-container {
            flex: 1;
            display: flex;
            justify-content: center;
            align-items: center;
            position: relative;
            padding: 5px; /* Mobilde kenar boşluğunu azalttık */
            background-color: #2a2a2a;
        }

        /* --- BOARD --- */
        .board {
            width: 100%;
            max-width: 900px; /* Biraz daha genişlettik */
            aspect-ratio: 4/3;
            background-color: var(--wood-secondary);
            border: 12px solid var(--wood-border);
            border-radius: 8px;
            display: flex;
            position: relative;
            box-shadow: 0 10px 30px rgba(0,0,0,0.6);
        }

        .half-board {
            flex: 1;
            display: flex;
            flex-direction: column;
            border: 2px solid rgba(0,0,0,0.2);
        }
        .half-board:first-child { border-right: 6px solid var(--wood-border); } 

        .quadrant {
            flex: 1;
            display: flex;
            position: relative;
        }
        
        .quadrant.top { border-bottom: 2px solid rgba(0,0,0,0.1); align-items: flex-start; }
        .quadrant.bottom { border-top: 2px solid rgba(0,0,0,0.1); align-items: flex-end; }

        /* --- POINTS (TRIANGLES) --- */
        .point {
            flex: 1;
            height: 45%; 
            position: relative;
            display: flex;
            justify-content: center;
            z-index: 1;
        }

        .point:nth-child(odd) { background-color: var(--point-dark); clip-path: polygon(50% 100%, 0 0, 100% 0); }
        .point:nth-child(even) { background-color: var(--point-light); clip-path: polygon(50% 100%, 0 0, 100% 0); }
        
        .bottom .point:nth-child(odd) { clip-path: polygon(50% 0, 0 100%, 100% 100%); }
        .bottom .point:nth-child(even) { clip-path: polygon(50% 0, 0 100%, 100% 100%); }

        .point.valid-target { cursor: pointer; }
        .point.valid-target::after {
            content: '';
            position: absolute;
            top:0; left:0; width:100%; height:100%;
            background-color: var(--highlight-color);
            z-index: 0;
        }

        /* --- CHECKERS (PULLAR) - GÜNCELLENDİ --- */
        .checker-container {
            position: absolute;
            width: 100%;
            height: 100%;
            pointer-events: none;
            display: flex;
        }
        
        .col {
            position: absolute;
            width: calc(100% / 6); 
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: flex-start; 
            align-items: center;
            padding: 0; /* Padding kaldırıldı, yer kazanıldı */
            pointer-events: auto; 
        }

        .quadrant.bottom .col { justify-content: flex-end; }

        /* PUL BOYUTU AYARLARI */
        .checker {
            width: 160%; /* %80'den %94'e çıkarıldı - Daha büyük */
            max-width: 65px; /* Çok büyük ekranlarda devasa olmasın */
            aspect-ratio: 1/1;
            border-radius: 50%;
            margin: 1px 0; /* Dikey boşluk */
            box-shadow: inset 0 0 8px rgba(0,0,0,0.6), 0 3px 5px rgba(0,0,0,0.4);
            border: 1px solid rgba(0,0,0,0.3);
            position: relative;
            transition: transform 0.1s, box-shadow 0.2s;
            z-index: 10;
        }

        .checker.white { background: radial-gradient(circle at 35% 35%, #fff, var(--checker-white)); }
        .checker.black { background: radial-gradient(circle at 35% 35%, #666, var(--checker-black)); border-color: #000; }

        .checker.selected {
            box-shadow: 0 0 0 3px gold, 0 0 15px gold;
            transform: scale(1.1);
            z-index: 20;
        }

        /* SIKIŞTIRMA (STACK) AYARLARI - Pullar büyük olduğu için daha çok üst üste binmeli */
        .col.stacked .checker {
            margin-bottom: -45%; /* Bindirme oranı artırıldı */
        }
        .quadrant.bottom .col.stacked .checker {
            margin-bottom: 0;
            margin-top: -45%;
        }

        /* --- BAR (Middle) --- */
        .bar-area {
            position: absolute;
            left: 50%;
            top: 0;
            bottom: 0;
            width: 40px; /* Bar biraz daraltıldı */
            transform: translateX(-50%);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 5;
            background: rgba(0,0,0,0.1); /* Hafif gölge */
        }
        .bar-box {
            width: 100%;
            height: 40%;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }
        .bar-box .checker { margin: -20% 0; width: 85%; } /* Bardaki pullar biraz daha sıkışık */
        .bar-box.has-checkers { cursor: pointer; background: rgba(255,0,0,0.15); border-radius: 5px; }

        /* --- DICE AREA --- */
        .dice-container {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            display: flex;
            gap: 15px;
            z-index: 100;
            pointer-events: none;
        }
        
        .die {
            width: 44px;
            height: 44px;
            background-color: #fff;
            border-radius: 8px;
            box-shadow: 0 4px 10px rgba(0,0,0,0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 22px;
            font-weight: bold;
            color: #000;
            opacity: 0;
            transform: scale(0);
            transition: all 0.3s ease-out;
            border: 1px solid #999;
        }
        .die.active { opacity: 1; transform: scale(1); }

        /* --- NOTIFICATIONS & MODALS --- */
        #notification {
            position: absolute;
            bottom: 10%;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0,0,0,0.85);
            color: #FFD700;
            padding: 10px 25px;
            border-radius: 30px;
            font-size: 1.1rem;
            font-weight: bold;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.3s;
            white-space: nowrap;
            z-index: 200;
            box-shadow: 0 5px 15px rgba(0,0,0,0.5);
        }

        .modal-overlay {
            position: fixed; top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0,0,0,0.85);
            display: none; justify-content: center; align-items: center;
            z-index: 1000;
            backdrop-filter: blur(3px);
        }
        .modal {
            background: #222; color: white; padding: 25px;
            border-radius: 12px; max-width: 400px; width: 90%;
            text-align: center; border: 1px solid #444;
            box-shadow: 0 10px 25px rgba(0,0,0,0.8);
        }
        .modal h2 { margin-top: 0; color: var(--wood-secondary); border-bottom: 1px solid #444; padding-bottom: 10px;}
        .modal-buttons { margin-top: 20px; display: flex; justify-content: center; gap: 10px; }
        
        select { padding: 8px; border-radius: 4px; border: none; background: #444; color: white; font-size: 1rem;}
        
        #scoreboard {
            display: flex; align-items: center; gap: 20px; font-weight: bold;
            font-size: 1.1rem; color: #ccc;
        }
        .turn-indicator {
            width: 12px; height: 12px; border-radius: 50%; display: inline-block; margin-right: 6px;
            border: 1px solid #666;
        }
        .turn-white { background: #fff; box-shadow: 0 0 8px #fff; }
        .turn-black { background: #333; border-color: #999; }

        @media (max-width: 600px) {
            header { flex-direction: column; height: auto; gap: 8px; padding: 10px; }
            h1 { display: none; } /* Mobilde başlığı gizle yer aç */
            .board { border-width: 6px; margin-top: 10px;}
            .checker { width: 96%; } /* Mobilde daha da büyük olsun */
        }
    </style>
</head>
<body>

<header>
    <div id="scoreboard">
        <div id="p1-score"><span id="indicator-white" class="turn-indicator turn-white"></span>Beyaz: <span id="score-white">0</span></div>
        <div id="p2-score"><span id="indicator-black" class="turn-indicator"></span>Siyah: <span id="score-black">0</span></div>
    </div>
    <h1>TÜRK TAVLASI</h1>
    <div class="controls">
        <button onclick="game.undo()" title="Geri Al">↩</button>
        <button onclick="ui.toggleSound()" id="btn-sound" title="Ses">🔊</button>
        <button onclick="ui.showRules()">?</button>
        <button class="primary" onclick="ui.showNewGameModal()">Menü</button>
    </div>
</header>

<div id="game-container">
    <div class="board">
        <div class="half-board">
            <div class="quadrant top" id="quad-tl"></div> <div class="quadrant bottom" id="quad-bl"></div> </div>
        
        <div class="half-board">
            <div class="quadrant top" id="quad-tr"></div> <div class="quadrant bottom" id="quad-br"></div> </div>

        <div class="checker-container"></div>

        <div class="bar-area">
            <div class="bar-box" id="bar-black-area"></div> <div class="bar-box" id="bar-white-area"></div> </div>

        <div class="dice-container">
            <div class="die" id="die1"></div>
            <div class="die" id="die2"></div>
        </div>
    </div>
</div>

<div id="notification">Bildirim Alanı</div>

<div class="modal-overlay" id="modal-newgame">
    <div class="modal">
        <h2>Oyun Ayarları</h2>
        <p style="margin-bottom: 15px;">
            <label>Mod:</label><br>
            <select id="game-mode" style="width: 100%; margin-top: 5px;">
                <option value="pvp">2 Oyunculu (Aynı Cihaz)</option>
                <option value="ai" selected>Yapay Zeka'ya Karşı</option>
            </select>
        </p>
        <p id="ai-diff-container">
            <label>Zorluk:</label><br>
            <select id="ai-level" style="width: 100%; margin-top: 5px;">
                <option value="easy">Kolay (Acemi)</option>
                <option value="medium" selected>Orta (Dengeli)</option>
                <option value="hard">Zor (Agresif)</option>
            </select>
        </p>
        <div class="modal-buttons">
            <button onclick="ui.hideModal('modal-newgame')">Kapat</button>
            <button class="primary" onclick="game.startNewGame()">BAŞLA</button>
        </div>
    </div>
</div>

<div class="modal-overlay" id="modal-rules">
    <div class="modal" style="text-align: left;">
        <h2>Kurallar</h2>
        <ul style="font-size: 0.9rem; line-height: 1.5; padding-left: 20px;">
            <li><strong>Beyaz:</strong> Sağ altta toplar (Saat yönü tersi).</li>
            <li><strong>Siyah:</strong> Sağ üstte toplar (Saat yönü).</li>
            <li><strong>Kırma:</strong> Tek pula vurulabilir. Kırılan pul Bar'a gider.</li>
            <li><strong>Giriş:</strong> Bar'daki pul girmeden hamle yapılamaz.</li>
            <li><strong>Çift Zar:</strong> 4 kere oynanır (Örn: 6-6 gelirse 4 tane 6).</li>
        </ul>
        <div class="modal-buttons">
            <button class="primary" onclick="ui.hideModal('modal-rules')">Tamam</button>
        </div>
    </div>
</div>

<div class="modal-overlay" id="modal-gameover">
    <div class="modal">
        <h2 id="winner-text">Oyun Bitti!</h2>
        <p id="game-summary" style="white-space: pre-line; line-height: 1.6;"></p>
        <div class="modal-buttons">
            <button onclick="game.downloadSummary()">Özeti İndir</button>
            <button class="primary" onclick="ui.showNewGameModal()">Yeni Oyun</button>
        </div>
    </div>
</div>

<script>
const PLAYER_WHITE = 1;
const PLAYER_BLACK = -1;
const BOARD_SIZE = 24;

class BackgammonGame {
    constructor() {
        this.board = Array(BOARD_SIZE).fill(0);
        this.bar = { [PLAYER_WHITE]: 0, [PLAYER_BLACK]: 0 };
        this.off = { [PLAYER_WHITE]: 0, [PLAYER_BLACK]: 0 };
        this.turn = PLAYER_WHITE; 
        this.dice = [];
        this.movesLeft = []; 
        this.selectedPoint = null; 
        this.history = []; 
        this.gameMode = 'ai'; 
        this.aiLevel = 'medium';
        this.isGameOver = false;
        this.moveCount = 0;
        
        this.initialSetup();
    }

    initialSetup() {
        this.board.fill(0);
        // Standart Dizilim
        this.board[23] = 2;  
        this.board[12] = 5;  
        this.board[7]  = 3;  
        this.board[5]  = 5;  

        this.board[0]  = -2; 
        this.board[11] = -5; 
        this.board[16] = -3; 
        this.board[18] = -5; 

        this.bar = { [PLAYER_WHITE]: 0, [PLAYER_BLACK]: 0 };
        this.off = { [PLAYER_WHITE]: 0, [PLAYER_BLACK]: 0 };
        this.turn = PLAYER_WHITE;
        this.dice = [];
        this.movesLeft = [];
        this.history = [];
        this.isGameOver = false;
        this.moveCount = 0;
        this.saveState();
    }

    startNewGame() {
        const modeEl = document.getElementById('game-mode');
        const levelEl = document.getElementById('ai-level');
        this.gameMode = modeEl.value;
        this.aiLevel = levelEl.value;
        
        this.initialSetup();
        ui.hideModal('modal-newgame');
        ui.hideModal('modal-gameover');
        ui.renderBoard();
        ui.updateScoreboard();
        ui.notify("Oyun Başladı! Bol şans.");
        
        setTimeout(() => this.rollDice(), 800);
    }

    saveState() {
        const state = JSON.stringify({
            board: this.board, bar: this.bar, off: this.off,
            turn: this.turn, dice: this.dice, movesLeft: this.movesLeft
        });
        if (this.history.length > 30) this.history.shift();
        this.history.push(state);
        localStorage.setItem('tavla_save_v2', state);
    }

    undo() {
        if (this.gameMode === 'ai' && this.turn === PLAYER_BLACK) return; 
        if (this.history.length < 2) {
            ui.notify("Geri alınacak hamle yok.");
            return;
        }
        this.history.pop(); 
        const prevState = JSON.parse(this.history[this.history.length - 1]);
        
        this.board = prevState.board;
        this.bar = prevState.bar;
        this.off = prevState.off;
        this.turn = prevState.turn;
        this.dice = prevState.dice;
        this.movesLeft = prevState.movesLeft;
        
        this.selectedPoint = null;
        ui.renderBoard();
        ui.renderDice();
        ui.highlightValidMoves([]);
    }

    rollDice() {
        if (this.isGameOver) return;
        audio.play('roll');

        const d1 = Math.floor(Math.random() * 6) + 1;
        const d2 = Math.floor(Math.random() * 6) + 1;
        this.dice = [d1, d2];

        if (d1 === d2) {
            this.movesLeft = [d1, d1, d1, d1];
            ui.notify("DÜŞEŞ! (" + d1 + "-" + d1 + ")");
        } else {
            this.movesLeft = [d1, d2];
        }

        ui.renderDice();
        
        if (!this.hasAnyValidMove()) {
            setTimeout(() => {
                ui.notify("Hamle yok. Sıra geçiyor.");
                this.endTurn();
            }, 2000);
        } else {
            if (this.gameMode === 'ai' && this.turn === PLAYER_BLACK) {
                setTimeout(() => ai.playTurn(), 1000);
            }
        }
    }

    hasAnyValidMove() {
        if (this.bar[this.turn] > 0) {
            const entryPoints = [...new Set(this.movesLeft)];
            for (let die of entryPoints) {
                const target = this.turn === PLAYER_WHITE ? (24 - die) : (die - 1);
                if (this.isValidTarget(target)) return true;
            }
            return false;
        }

        for (let i = 0; i < BOARD_SIZE; i++) {
            if (Math.sign(this.board[i]) === this.turn) {
                const moves = [...new Set(this.movesLeft)];
                for (let die of moves) {
                    let target = this.turn === PLAYER_WHITE ? i - die : i + die;
                    if (this.canBearOff()) {
                        if (this.isValidBearOffMove(i, die)) return true;
                    } 
                    if (target >= 0 && target < 24 && this.isValidTarget(target)) return true;
                }
            }
        }
        return false;
    }

    isValidTarget(idx) {
        if (idx < 0 || idx >= BOARD_SIZE) return false;
        const count = this.board[idx];
        if (count === 0) return true;
        if (Math.sign(count) === this.turn) return true;
        if (Math.sign(count) !== this.turn && Math.abs(count) === 1) return true;
        return false;
    }

    getValidMovesForPoint(pointIdx) {
        let validDestinations = [];
        let uniqueDice = [...new Set(this.movesLeft)];

        if (this.bar[this.turn] > 0) {
            if (pointIdx !== 'bar') return [];
            uniqueDice.forEach(die => {
                let target = this.turn === PLAYER_WHITE ? (24 - die) : (die - 1);
                if (this.isValidTarget(target)) {
                    validDestinations.push({ target: target, die: die, type: 'normal' });
                }
            });
            return validDestinations;
        }

        if (pointIdx === 'bar' || Math.sign(this.board[pointIdx]) !== this.turn) return [];

        uniqueDice.forEach(die => {
            let target = this.turn === PLAYER_WHITE ? pointIdx - die : pointIdx + die;
            
            if (target >= 0 && target < BOARD_SIZE) {
                if (this.isValidTarget(target)) {
                    validDestinations.push({ target: target, die: die, type: 'normal' });
                }
            } else if (this.canBearOff()) {
                if (this.isValidBearOffMove(pointIdx, die)) {
                    validDestinations.push({ target: 'off', die: die, type: 'off' });
                }
            }
        });

        return validDestinations;
    }

    canBearOff() {
        let start = this.turn === PLAYER_WHITE ? 6 : 0;
        let end = this.turn === PLAYER_WHITE ? 23 : 17;
        if (this.bar[this.turn] > 0) return false;
        for (let i = start; i <= end; i++) {
            if (Math.sign(this.board[i]) === this.turn) return false;
        }
        return true;
    }

    isValidBearOffMove(fromIdx, die) {
        let dist = this.turn === PLAYER_WHITE ? fromIdx + 1 : 24 - fromIdx;
        if (dist === die) return true;
        if (die > dist) {
            if (this.turn === PLAYER_WHITE) {
                for (let i = fromIdx + 1; i <= 5; i++) {
                    if (this.board[i] > 0) return false;
                }
            } else {
                for (let i = fromIdx - 1; i >= 18; i--) {
                    if (this.board[i] < 0) return false;
                }
            }
            return true;
        }
        return false;
    }

    makeMove(from, to, die) {
        this.saveState();
        audio.play('move');
        this.moveCount++;

        if (from === 'bar') {
            this.bar[this.turn]--;
        } else {
            this.board[from] -= this.turn;
        }

        if (to === 'off') {
            this.off[this.turn]++;
            audio.play('bearoff');
        } else {
            if (this.board[to] !== 0 && Math.sign(this.board[to]) !== this.turn) {
                this.bar[-this.turn]++;
                this.board[to] = 0;
                audio.play('hit');
                ui.notify("KIRILDI!");
            }
            this.board[to] += this.turn;
        }

        const dieIdx = this.movesLeft.indexOf(die);
        if (dieIdx > -1) this.movesLeft.splice(dieIdx, 1);

        ui.renderBoard();
        ui.renderDice();

        if (this.checkWin()) {
            this.gameOver();
            return;
        }

        if (this.movesLeft.length === 0) {
            setTimeout(() => this.endTurn(), 500);
        } else if (!this.hasAnyValidMove()) {
            setTimeout(() => {
                ui.notify("Kalan zarlarla hamle yok.");
                this.endTurn();
            }, 1500);
        } else {
             if (this.gameMode === 'ai' && this.turn === PLAYER_BLACK) {
                 setTimeout(() => ai.playTurn(), 800);
             }
        }
    }

    endTurn() {
        this.turn = -this.turn;
        this.movesLeft = [];
        this.dice = [];
        ui.renderDice();
        ui.updateScoreboard();
        ui.selectedPoint = null;
        ui.highlightValidMoves([]);
        
        if (this.gameMode === 'ai' && this.turn === PLAYER_BLACK) {
            ui.notify("Sıra Siyah'ta (Düşünüyor...)");
            setTimeout(() => this.rollDice(), 1000);
        } else {
            ui.notify(this.turn === PLAYER_WHITE ? "Sıra Beyaz'da" : "Sıra Siyah'ta");
            setTimeout(() => this.rollDice(), 500);
        }
    }

    checkWin() { return this.off[this.turn] === 15; }

    gameOver() {
        this.isGameOver = true;
        const winner = this.turn === PLAYER_WHITE ? "BEYAZ" : "SİYAH";
        document.getElementById('winner-text').innerText = winner + " KAZANDI!";
        
        let summary = `Toplam Hamle: ${this.moveCount}\n`;
        summary += `Beyaz Toplanan: ${this.off[PLAYER_WHITE]}\n`;
        summary += `Siyah Toplanan: ${this.off[PLAYER_BLACK]}\n`;
        if (this.off[-this.turn] === 0) summary += "\nMARS (2 Kat)!";

        document.getElementById('game-summary').innerText = summary;
        ui.showModal('modal-gameover');
        audio.play('win');
    }

    downloadSummary() {
        const text = document.getElementById('game-summary').innerText;
        const blob = new Blob([text], { type: 'text/plain' });
        const a = document.createElement('a');
        a.href = URL.createObjectURL(blob);
        a.download = 'tavla_ozet.txt';
        a.click();
    }
}

class AI {
    playTurn() {
        if (game.turn !== PLAYER_BLACK || game.movesLeft.length === 0) return;

        let sources = [];
        if (game.bar[PLAYER_BLACK] > 0) {
            sources = ['bar'];
        } else {
            for (let i = 0; i < BOARD_SIZE; i++) {
                if (game.board[i] < 0) sources.push(i);
            }
        }

        let dieToUse = game.movesLeft[0];
        let candidates = [];
        
        sources.forEach(source => {
            const moves = game.getValidMovesForPoint(source);
            moves.forEach(m => {
                if (game.movesLeft.includes(m.die)) {
                    candidates.push({ source: source, move: m });
                }
            });
        });

        if (candidates.length === 0) return;

        let bestMove = null;
        let bestScore = -9999;

        candidates.forEach(cand => {
            let score = this.evaluateMove(cand.source, cand.move);
            if (score > bestScore) {
                bestScore = score;
                bestMove = cand;
            }
        });

        if (bestMove) {
            game.makeMove(bestMove.source, bestMove.move.target, bestMove.move.die);
        }
    }

    evaluateMove(from, moveData) {
        let score = 0;
        let target = moveData.target;

        if (target === 'off') return 2000;
        
        // Kırma
        if (game.board[target] > 0) score += 600;

        // Kapı Alma
        if (game.board[target] < -1) score += 100; 
        if (game.board[target] === -1) score += 300; 

        // Açık Verme Riski
        if (game.board[target] === 0) {
            score -= 50; 
            if (target >= 18) score += 40; 
        }
        
        // Evden kaçış (Siyah için 0-5 arası tehlikeli)
        if (from !== 'bar' && from < 6) score += 50;

        // Zorluk Varyasyonu
        if (game.aiLevel === 'easy') score += Math.random() * 800;
        if (game.aiLevel === 'medium') score += Math.random() * 200;

        return score;
    }
}

class UI {
    constructor() {
        this.boardEl = document.querySelector('.checker-container');
        this.soundEnabled = true;
    }

    initBoardDOM() {
        this.boardEl.innerHTML = '';
        document.getElementById('quad-tl').innerHTML = ''; 
        document.getElementById('quad-tr').innerHTML = ''; 
        document.getElementById('quad-bl').innerHTML = ''; 
        document.getElementById('quad-br').innerHTML = ''; 

        const createPoints = (parent, startIdx, endIdx) => {
            let indices = [];
            if (startIdx < endIdx) {
                for (let i=startIdx; i<=endIdx; i++) indices.push(i);
            } else {
                for (let i=startIdx; i>=endIdx; i--) indices.push(i);
            }

            indices.forEach(idx => {
                let pt = document.createElement('div');
                pt.className = 'point';
                pt.dataset.index = idx;
                pt.onclick = () => this.handlePointClick(idx);
                
                let col = document.createElement('div');
                col.className = 'col';
                col.id = `col-${idx}`;
                
                pt.appendChild(col);
                parent.appendChild(pt);
            });
        };

        createPoints(document.getElementById('quad-tl'), 12, 17);
        createPoints(document.getElementById('quad-tr'), 18, 23);
        createPoints(document.getElementById('quad-bl'), 11, 6);
        createPoints(document.getElementById('quad-br'), 5, 0);

        document.getElementById('bar-white-area').onclick = () => this.handleBarClick(PLAYER_WHITE);
        document.getElementById('bar-black-area').onclick = () => this.handleBarClick(PLAYER_BLACK);
    }

    renderBoard() {
        for (let i = 0; i < BOARD_SIZE; i++) {
            const col = document.getElementById(`col-${i}`);
            col.innerHTML = '';
            col.classList.remove('stacked');
            
            const count = game.board[i];
            const player = Math.sign(count);
            const numCheckers = Math.abs(count);
            
            if (numCheckers > 5) col.classList.add('stacked');

            for (let k = 0; k < numCheckers; k++) {
                const checker = document.createElement('div');
                checker.className = `checker ${player === 1 ? 'white' : 'black'}`;
                
                if (game.selectedPoint === i && k === numCheckers - 1) {
                    checker.classList.add('selected');
                }
                col.appendChild(checker);
            }
        }

        const renderBar = (pid, elemId) => {
            const el = document.getElementById(elemId);
            el.innerHTML = '';
            const count = game.bar[pid];
            el.classList.toggle('has-checkers', count > 0);
            
            for(let k=0; k<count; k++) {
                const c = document.createElement('div');
                c.className = `checker ${pid === 1 ? 'white' : 'black'}`;
                if (game.selectedPoint === 'bar' && game.turn === pid && k === count - 1) {
                    c.classList.add('selected');
                }
                el.appendChild(c);
            }
        };
        renderBar(PLAYER_WHITE, 'bar-white-area');
        renderBar(PLAYER_BLACK, 'bar-black-area');
        this.updateScoreboard();
    }

    renderDice() {
        const d1 = document.getElementById('die1');
        const d2 = document.getElementById('die2');
        
        if (game.movesLeft.length === 0 && game.dice.length === 0) {
            d1.className = 'die'; d2.className = 'die';
            return;
        }
        d1.innerText = game.dice[0] || '';
        d2.innerText = game.dice[1] || '';
        d1.classList.add('active');
        d2.classList.add('active');
    }

    updateScoreboard() {
        document.getElementById('score-white').innerText = game.off[PLAYER_WHITE];
        document.getElementById('score-black').innerText = game.off[PLAYER_BLACK];
        
        document.getElementById('indicator-white').style.opacity = game.turn === PLAYER_WHITE ? 1 : 0.3;
        document.getElementById('indicator-black').style.opacity = game.turn === PLAYER_BLACK ? 1 : 0.3;
    }

    handlePointClick(idx) {
        if (this.canBearOffSelection && game.selectedPoint === idx) {
            const moves = game.getValidMovesForPoint(idx);
            const offMove = moves.find(m => m.target === 'off');
            if (offMove) {
                game.makeMove(idx, 'off', offMove.die);
                this.highlightValidMoves([]);
                game.selectedPoint = null;
                this.canBearOffSelection = false;
                return;
            }
        }

        if (game.gameMode === 'ai' && game.turn === PLAYER_BLACK) return;
        const pointEl = document.querySelector(`.point[data-index='${idx}']`);
        
        if (pointEl.classList.contains('valid-target') && game.selectedPoint !== idx) {
            const moves = game.getValidMovesForPoint(game.selectedPoint);
            const move = moves.find(m => m.target === idx);
            if (move) {
                game.makeMove(game.selectedPoint, idx, move.die);
                this.highlightValidMoves([]);
                game.selectedPoint = null;
                return;
            }
        }

        if (game.bar[game.turn] > 0) {
            this.notify("Bar'da taşınız var! Önce onu oynayın.");
            return;
        }
        if (Math.sign(game.board[idx]) === game.turn) {
            if (game.selectedPoint === idx && !this.canBearOffSelection) {
                game.selectedPoint = null;
                this.highlightValidMoves([]);
                this.renderBoard();
            } else {
                game.selectedPoint = idx;
                this.renderBoard();
                const moves = game.getValidMovesForPoint(idx);
                this.highlightValidMoves(moves);
            }
        }
    }

    handleBarClick(pid) {
        if (game.gameMode === 'ai' && game.turn === PLAYER_BLACK) return;
        if (pid !== game.turn) return;
        if (game.bar[pid] === 0) return;

        game.selectedPoint = 'bar';
        this.renderBoard();
        const moves = game.getValidMovesForPoint('bar');
        this.highlightValidMoves(moves);
    }

    highlightValidMoves(moves) {
        document.querySelectorAll('.point').forEach(el => {
            el.classList.remove('valid-target');
        });

        moves.forEach(m => {
            if (m.type === 'off') {
                this.notify("Taşı dışarı atabilirsiniz (Tekrar tıklayın)");
                const pt = document.querySelector(`.point[data-index='${game.selectedPoint}']`);
                if(pt) pt.classList.add('valid-target');
            } else {
                const el = document.querySelector(`.point[data-index='${m.target}']`);
                if(el) el.classList.add('valid-target');
            }
        });

        if (moves.some(m => m.target === 'off')) {
            this.canBearOffSelection = true;
        } else {
            this.canBearOffSelection = false;
        }
    }

    notify(msg) {
        const el = document.getElementById('notification');
        el.innerText = msg;
        el.style.opacity = 1;
        clearTimeout(this.notifyTimer);
        this.notifyTimer = setTimeout(() => {
            el.style.opacity = 0;
        }, 2500);
    }

    showModal(id) { document.getElementById(id).style.display = 'flex'; }
    hideModal(id) { document.getElementById(id).style.display = 'none'; }
    showNewGameModal() { this.showModal('modal-newgame'); }
    showRules() { this.showModal('modal-rules'); }

    toggleSound() {
        this.soundEnabled = !this.soundEnabled;
        document.getElementById('btn-sound').innerText = this.soundEnabled ? '🔊' : '🔇';
    }
}

class AudioManager {
    constructor() {
        this.ctx = new (window.AudioContext || window.webkitAudioContext)();
    }

    play(type) {
        if (!ui.soundEnabled) return;
        if (this.ctx.state === 'suspended') this.ctx.resume();

        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.connect(gain);
        gain.connect(this.ctx.destination);
        const now = this.ctx.currentTime;

        if (type === 'roll') {
            osc.type = 'square';
            osc.frequency.setValueAtTime(150, now);
            osc.frequency.exponentialRampToValueAtTime(40, now + 0.1);
            gain.gain.setValueAtTime(0.1, now);
            gain.gain.exponentialRampToValueAtTime(0.01, now + 0.1);
            osc.start(now); osc.stop(now + 0.1);
        } else if (type === 'move') {
            osc.type = 'sine';
            osc.frequency.setValueAtTime(300, now);
            gain.gain.setValueAtTime(0.1, now);
            gain.gain.exponentialRampToValueAtTime(0.01, now + 0.1);
            osc.start(now); osc.stop(now + 0.1);
        } else if (type === 'hit') {
            osc.type = 'sawtooth';
            osc.frequency.setValueAtTime(100, now);
            osc.frequency.linearRampToValueAtTime(600, now + 0.1);
            gain.gain.setValueAtTime(0.1, now);
            gain.gain.linearRampToValueAtTime(0.01, now + 0.1);
            osc.start(now); osc.stop(now + 0.1);
        } else if (type === 'bearoff') {
            osc.type = 'triangle';
            osc.frequency.setValueAtTime(600, now);
            osc.frequency.exponentialRampToValueAtTime(1000, now + 0.2);
            gain.gain.setValueAtTime(0.1, now);
            gain.gain.linearRampToValueAtTime(0.01, now + 0.2);
            osc.start(now); osc.stop(now + 0.2);
        } else if (type === 'win') {
            this.playTone(440, 0, 0.2);
            this.playTone(554, 0.2, 0.2);
            this.playTone(659, 0.4, 0.4);
        }
    }

    playTone(freq, delay, dur) {
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.connect(gain);
        gain.connect(this.ctx.destination);
        const now = this.ctx.currentTime + delay;
        osc.frequency.value = freq;
        gain.gain.setValueAtTime(0.1, now);
        gain.gain.linearRampToValueAtTime(0.01, now + dur);
        osc.start(now); osc.stop(now + dur);
    }
}

const game = new BackgammonGame();
const ui = new UI();
const ai = new AI();
const audio = new AudioManager();

window.onload = () => {
    ui.initBoardDOM();
    const saved = localStorage.getItem('tavla_save_v2');
    if (saved) {
        try {
            const s = JSON.parse(saved);
            game.board = s.board;
            game.bar = s.bar;
            game.off = s.off;
            game.turn = s.turn;
            game.dice = s.dice;
            game.movesLeft = s.movesLeft;
            ui.renderBoard();
            ui.renderDice();
            ui.updateScoreboard();
            ui.notify("Oyun yüklendi.");
        } catch(e) { game.startNewGame(); }
    } else {
        ui.showNewGameModal();
    }
};
</script>
</body>
</html>


Kodları metin dosyasına atıp tavla.html olarak kaydedip deneyimleyebilirsiniz gemini 3 ile ilk projem bu şekilde iyi forumlar geliştirmek size kalmış