Files

203 lines
7.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ==========================================================================
main.js — Bootstrap katmanı (Numex Okey).
Sorumluluklar:
1) DOM referanslarını ve oyun durumunu hazırla (UI.cacheRefs + Game.newGame)
2) Olay dinleyicilerini bağla (UI.bindEvents)
3) Tarayıcı-içi SELF-TEST çalıştır (deste/per/kazanma bütünlüğü)
4) Global hata yakalama (error boundary) — beyaz ekran yerine görünür mesaj
5) Görünürlük değişince oyunu duraklat/devam ettir (sekme arka plandayken CPU yakma)
Kırılganlık ilkesi: bootstrap tek bir try/catch içinde; herhangi bir modül
eksik/bozuksa kullanıcı SESSİZ beyaz ekran yerine NET hata görür.
========================================================================== */
(function (root) {
'use strict';
var Game = root.OkeyGame;
var UI = root.OkeyUI;
var Rules = root.OkeyRules;
var Tiles = root.OkeyTiles;
var BOOT_FLAG = '__numexOkeyBooted';
var PAUSED = false;
/* ------------------------------------------------------------------ */
/* HATA GÖRÜNÜRLÜĞÜ (error boundary) */
/* ------------------------------------------------------------------ */
/** Durum çubuğuna görünür hata yazar; konsola da düşer. */
function showFatal(msg, err) {
try {
if (UI && typeof UI.setStatus === 'function') {
UI.setStatus('⚠ ' + msg);
} else {
var el = document.getElementById('status-msg');
if (el) el.textContent = '⚠ ' + msg;
}
} catch (e) { /* UI bile bozuksa sessiz kal */ }
console.error('[Okey] ' + msg, err || '');
}
/** Yakalanmamış hataları ve reddedilen promise'leri görünür yap. */
function installErrorBoundary() {
if (typeof root.addEventListener !== 'function') return;
root.addEventListener('error', function (ev) {
var msg = (ev && ev.message) ? ev.message : 'Bilinmeyen hata';
showFatal('Beklenmeyen hata: ' + msg, ev && ev.error);
});
root.addEventListener('unhandledrejection', function (ev) {
var r = ev && ev.reason;
showFatal('İşlenmeyen promise hatası: ' + (r && r.message ? r.message : r), r);
});
}
/* ------------------------------------------------------------------ */
/* SELF-TEST */
/* ------------------------------------------------------------------ */
/**
* Tarayıcı-içi sağlık kontrolü: modüller yüklendi mi, deste tutarlı mı,
* per/kazanma mantığı beklenen sonucu veriyor mu?
* Hata FIRLATMAZ; sonucu döner ve konsola yazar (oyunu kilitlemesin).
*/
function runSelfTest(state) {
var sonuc = { gecti: 0, kaldi: 0, satirlar: [] };
function kontrol(ad, kosul) {
if (kosul) {
sonuc.gecti++;
sonuc.satirlar.push(' ✓ ' + ad);
} else {
sonuc.kaldi++;
sonuc.satirlar.push(' ✗ ' + ad);
console.warn('[Okey self-test] BAŞARISIZ: ' + ad);
}
}
try {
var toplamElde = state.hands[0].length + state.hands[1].length +
state.hands[2].length + state.hands[3].length;
kontrol('Deste 106 taş olmalı (elde+kapalı)',
toplamElde + state.deck.length === 106);
kontrol('Başlangıç oyuncusu 15 taş', state.hands[0].length === 15);
kontrol('Diğerleri 14 taş',
state.hands[1].length === 14 &&
state.hands[2].length === 14 &&
state.hands[3].length === 14);
kontrol('Gösterge atandı', !!state.indicator);
kontrol('Okey sırası geçerli (1..13)',
state.okeyRank >= 1 && state.okeyRank <= 13);
kontrol('Okey rengi geçerli', !!state.okeyColor);
kontrol('Sahte okey mevcut', !!state.fakeOkey);
kontrol('Sıra 0..3 aralığında',
state.currentPlayer >= 0 && state.currentPlayer <= 3);
kontrol('Atık yığını dizisi', Array.isArray(state.discardPile));
// Kurallar modülü akıl sağlığı (saf fonksiyonlar)
if (Rules && typeof Rules.isJoker === 'function') {
kontrol('Rules.isJoker erişilebilir', true);
kontrol('Sahte okey daima joker',
Rules.isJoker(state.fakeOkey, state.indicator) === true);
} else {
kontrol('Rules modülü yüklü', false);
}
if (Tiles && typeof Tiles.isRealOkey === 'function') {
kontrol('Tiles.isRealOkey erişilebilir', true);
} else {
kontrol('Tiles modülü yüklü', false);
}
} catch (e) {
sonuc.kaldi++;
sonuc.satirlar.push(' ✗ self-test istisnası: ' + e.message);
console.error('[Okey self-test hata]', e);
}
console.log('[Okey self-test] ' + sonuc.gecti + ' geçti / ' +
sonuc.kaldi + ' kaldı');
for (var i = 0; i < sonuc.satirlar.length; i++) console.log(sonuc.satirlar[i]);
return sonuc;
}
/* ------------------------------------------------------------------ */
/* GÖRÜNÜRLÜK (sekme arka plan) */
/* ------------------------------------------------------------------ */
function installVisibilityGuard(state) {
if (typeof document.addEventListener !== 'function') return;
document.addEventListener('visibilitychange', function () {
PAUSED = document.hidden === true;
var el = document.getElementById('status-msg');
if (PAUSED && el) {
el.textContent = 'Oyun duraklatıldı (sekme arka planda) — geri dönünce devam eder.';
} else if (!PAUSED) {
try { UI.render(); } catch (e) { /* yoksay */ }
}
});
}
/* ------------------------------------------------------------------ */
/* BAŞLATMA */
/* ------------------------------------------------------------------ */
function init() {
// Çift bootstrap koruması (script bir kez daha yüklenirse oyun sıfırlanmasın)
if (root[BOOT_FLAG]) return;
root[BOOT_FLAG] = true;
// Modül sözleşmesi kontrolü — erken ve NET hata
if (!Game || !UI) {
showFatal('Modüller yüklenemedi (OkeyGame/OkeyUI eksik). ' +
'index.html script sırasını kontrol edin.');
return;
}
installErrorBoundary();
try {
UI.cacheRefs();
var state = Game.newGame();
UI.state = state;
UI.bindEvents();
// İlk sıra insan (0) — botlar hemen oynamaz.
if (typeof Game.autoPlayBots === 'function') Game.autoPlayBots(state);
UI.render();
var test = runSelfTest(state);
installVisibilityGuard(state);
// Başlangıç bilgisi durum çubuğunda
if (typeof UI.setStatus === 'function') {
UI.setStatus('Yeni oyun hazır. Gösterge: ' + state.indicator.color + ' ' +
state.indicator.rank + ' → Okey: ' + state.okeyColor + ' ' +
state.okeyRank + (test.kaldi ? ' (self-test: ' + test.kaldi + ' uyarı)'
: ' (self-test: tamam)'));
}
console.log('[Okey] Oyun başlatıldı. Gösterge:', state.indicator,
'| Okey:', state.okeyColor, state.okeyRank);
} catch (e) {
showFatal('Oyun başlatılamadı: ' + e.message, e);
}
}
/* ------------------------------------------------------------------ */
/* KAYIT */
/* ------------------------------------------------------------------ */
if (typeof document === 'undefined' || !document.addEventListener) return;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
// DOM zaten hazır (script gövde sonunda yüklendiyse)
init();
}
}(typeof self !== 'undefined' ? self : this));