← Oyuna dön
İpucu Motorunun Algoritması
Sarı kareyi gösteren motorun iç işleyişi
Yüz Yüze'de ipucu butonuna bastığında bir kare sarıya boyanır. Bu kare, oyun motorunun "şu an oynanabilecek en iyi hamle" olarak hesapladığı seçimdir. Peki motor bu kararı nasıl veriyor? Bu sayfa motorun iç işleyişini açıklar — meraklı oyuncular ve geliştiriciler için.
Tasarım Hedefleri
İpucu motoru üç hedefle tasarlandı:
- Doğruluk: Çoğu pozisyonda gerçekten optimal hamleyi göstermeli.
- Hız: Mobilde bile 200ms altında cevap vermeli.
- Determinizm: Aynı pozisyonda her zaman aynı cevabı vermeli (ipucu güvenilir olsun).
Bu üç hedef birbiriyle çatışır: doğruluk arttıkça hız azalır, determinizm rastgele simülasyonu zorlaştırır. Çözüm hibrit bir yaklaşımdır.
Genel Mimari
Motor üç katmanlı çalışır:
[1] Aday hamleler bul
Mevcut pozisyondan tüm geçerli hamleleri listele.
8 yön: 4 düz (3 kare) + 4 çapraz (2 kare).
[2] Her aday için Monte Carlo değerlendirme
O hamleyi varsay, kalan oyunu N kez simüle et.
Her simülasyon Warnsdorff ile devam eder.
Ortalama final skoru kaydet.
[3] En yüksek ortalama skoru seç
Eşitlikte tie-breaking kuralı uygula.
Kazananı sarı kareye işaretle.
Monte Carlo Simülasyonu
Klasik Monte Carlo Tree Search (MCTS) Yüz Yüze için fazla pahalı. Bunun yerine basit bir flat Monte Carlo yaklaşımı kullanılır:
function evaluateMove(move, currentState) {
let totalScore = 0;
for (let i = 0; i < SIMULATIONS; i++) {
const sim = cloneState(currentState);
applyMove(sim, move);
while (hasValidMoves(sim)) {
const next = warnsdorffPick(sim);
applyMove(sim, next);
}
totalScore += sim.placedCount;
}
return totalScore / SIMULATIONS;
}
Yani: hamleyi yap, sonra "Warnsdorff bilgili rastgele oyuncu" oyunu bitirsin, kaç kareye ulaştığına bak. Bunu birkaç kez tekrarla, ortalamasını al.
İki Mod: Hint vs Quick
Motor iki farklı bağlamda çalışır:
- Hint modu (kullanıcı butona bastığında): 120 simülasyon. ~150-200ms süre. Maksimum doğruluk.
- Quick modu (combo tracker arka planda): 30 simülasyon. ~30-50ms süre. Yeterli doğruluk, gerçek zamanlı yanıt.
Combo sistemi her hamleden sonra "AI ne yapardı?" sorusunu sorar. Eğer kullanıcının yaptığı hamle AI'ın quick mode tahminiyle aynıysa combo sayacı artar. Hızlı bir cevap gerektiği için 30 simülasyon yeterlidir; tam ipucu kalitesinde olmasa da combo amaçları için doğru çalışır.
Warnsdorff Devamı
Simülasyon sırasında "rastgele oyuncu" saf rastgele değil. Her hamlede Warnsdorff kuralı uygulanır:
function warnsdorffPick(state) {
const moves = getValidMoves(state);
let minDegree = Infinity;
let candidates = [];
for (const m of moves) {
const deg = countValidMovesAfter(state, m);
if (deg < minDegree) {
minDegree = deg;
candidates = [m];
} else if (deg === minDegree) {
candidates.push(m);
}
}
return candidates[randomInt(0, candidates.length)];
}
Saf rastgele oyuncu yerine Warnsdorff kullanmak iki etki yaratır: simülasyonların ortalaması daha gerçekçi olur (gerçek bir oyuncu da rastgele değil sezgisel oynar) ve gerekli simülasyon sayısı düşer (varyans azalır).
Seeded PRNG
Determinizm için motor rastgele sayı üreteci olarak Mulberry32 kullanır. Aynı pozisyonda her zaman aynı seed'le başlanır, bu da aynı sonucu garantiler:
function mulberry32(seed) {
return function() {
seed = (seed + 0x6D2B79F5) | 0;
let t = seed;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
Mulberry32 hızlı, basit ve ipucu motoru için yeterli kalitede istatistiksel özelliklere sahip. Kriptografik amaç için yetersiz ama bulmaca simülasyonu için ideal.
Günlük Bulmaca Üretimi
Aynı PRNG günlük bulmacayı üretir. Tohum tarih: YYYYMMDD. Bu, Türkiye saati 00:00'da değişir. Tohum sabit olduğu için dünyada herkes aynı bulmacayı oynar — coğrafi konumdan bağımsız.
const today = new Date();
const seed = today.getFullYear() * 10000
+ (today.getMonth() + 1) * 100
+ today.getDate();
const rng = mulberry32(seed);
const startCell = Math.floor(rng() * 100);
Performans Optimizasyonu
Algoritma birkaç optimizasyon kullanır:
- Bitset state: 100 hücreli grid 100-bit bitset olarak temsil edilir (iki Uint32). applyMove ve isVisited kontrolleri bit operasyonu hızında.
- Hamle önbellek: Her karenin 8 olası hedef karesi pre-computed. Run-time'da hesaplanmaz.
- Erken sonlandırma: Bir aday hamlenin ortalama skoru ilk 30 simülasyonda diğerlerinin altında kalırsa durdurulur (alpha-beta benzeri).
Pratikte 120 simülasyon mobil tarayıcıda 150ms civarı, masaüstünde 50ms altında biter.
Sınırlamalar ve Gelecek
Mevcut motor neredeyse her pozisyonda doğru cevabı verir ama bazı sınırları vardır:
- Çok dar pozisyonlarda (kalan 5-10 kare) Monte Carlo'nun varyansı doğruluğu zorlar; gerçek backtracking daha güvenli olur.
- Eşit ortalamalı iki adayda tie-breaking deterministik ama "matematiksel olarak optimal" değil.
- Simülasyon sayısı artırılırsa doğruluk artar ama lineer fayda azalır (diminishing returns).
Gelecek versiyonda kalan oyun 12 kareden az olduğunda saf backtracking'e geçilmesi planlanıyor. Bu hibrit, başlangıç-orta oyun simülasyonu + son oyun aramasıyla ipucu kalitesini ispatlanabilir optimum'a yaklaştırabilir.
Kaynak Kodu
Yüz Yüze tek dosyalık vanilla JavaScript uygulamasıdır. Motor ana index.html dosyasının içine inline gömülüdür — IIFE içinde, dış bağımlılık yok. Build adımı yok, derleme yok. Tarayıcıda doğrudan çalışır.
Bu seçim bilinçli: bağımlılıksız bir oyun yıllarca çalışmaya devam eder. NPM paketleri eskimez, framework'ler değişmez, sürüm uyumluluğu sorun olmaz.