• 20-11-2025, 22:08:27
    #1


    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ış
  • 20-11-2025, 22:09:30
    #2
    Paylaşım için teşekkürler ^^
  • 20-11-2025, 22:11:43
    #3
    Üyeliği durduruldu
    Teşekkür ederim
  • 20-11-2025, 22:12:07
    #4
    SEOKOZ adlı üyeden alıntı: mesajı görüntüle
    Paylaşım için teşekkürler ^^
    rica ederim iyi forumlar
    Vivobayim adlı üyeden alıntı: mesajı görüntüle
    Teşekkür ederim
    rica ederim iyi forumlar
  • 20-11-2025, 22:13:12
    #5
    Üyeliği durduruldu
    Yapay zeka ile Unity oyun yazılabilir mi?
    Unity ve C# Bilmeden.
  • 20-11-2025, 22:15:50
    #6
    A.AY adlı üyeden alıntı: mesajı görüntüle
    Yapay zeka ile Unity oyun yazılabilir mi?
    Unity ve C# Bilmeden.
    Yapay zekayı kullanmayı biliyorsun araştırmayıda seviyorsan neden olmasın
  • 20-11-2025, 22:21:53
    #7
    A.AY adlı üyeden alıntı: mesajı görüntüle
    Yapay zeka ile Unity oyun yazılabilir mi?
    Unity ve C# Bilmeden.
    denemek lazım
  • 20-11-2025, 22:23:13
    #8
    Merhaba; biraz oynadım pulları toplamazsak oyun bitmiyor taşlarla hep dönüyor, güzel bir deneme olmuş.
  • 20-11-2025, 22:33:36
    #9
    grknclk adlı üyeden alıntı: mesajı görüntüle
    Merhaba; biraz oynadım pulları toplamazsak oyun bitmiyor taşlarla hep dönüyor, güzel bir deneme olmuş.
    az önce denedim böyle birşey yaşamadım problemsiz bir oyun başka yaşan varsa yazabilir bende sorun yok