User prompt
Oyun esnasında bağlantım koparsa ya da oyundan çıkarsam falan tekrar oyuna girdiğimde kaldığım oyun yerinden devam edebilmek istiyorum o yüzden bu bilgileri de kaydetmeliyiz geçici olarak her oyun başına. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
Code edit (2 edits merged)
Please save this source code
User prompt
Fakat şöyle bir durum fark ettim: Ben tüm zarları seçip masada zar kalmadığı zaman DEVAM tuşuna bastığım zaman zar atılıyor (6 tane zar), zar atılma sesi de çalıyor ama zarların dönme animasyonunu göremiyorum, zarların kendilerini de göremiyorum, 2 saniyelik animasyon bittiği zaman zarların sonuçlarını görebiliyorum sadece. Oyunun işleyişini bozmuyor çünkü sonuçları görebiliyorum ve o sonuçlardaki zarları da eğer uygunsa seçebiliyorum ya da uygun değilse iflas edebiliyorum fakat buradaki mesele ben tüm zarları seçmişken masada 0 zar kalmışken DEVAM diyip tekrar zar attığım zaman atılan zarın animasyonunu göremiyor olmam ve zarların sonuç belli olana kadar görünmez kalması. Bunun nedeni ne? Nasıl düzeltebilirim? Düzelt!
User prompt
Yükleme ekranı sırasında arkaplanda yuklemeEkraniArkaplani olduğu süre boyunca Oyunu Başlat ve Hesabı Sıfırla butonları dahil ekrandaki hiçbir yer ve hiçbir şey tıklanabilir olmamalı yani bu esnada ekrandaki her şey tıklanamaz olmalı. Yükleme ekranı kaybolduktan sonra artık butonlar ve diğer şeyler tıklanabilir olmalı.
User prompt
Oyun müziği çalmaya başladı şu anda fakat yükleme ekranı hala gözükmeye devam ediyor kaybolmadı! Yükleme ekranında ilk önce yuklemeEkraniSesi çalacak 1 kere, sonrasında döngüsel olarak oyunEkraniMuzigi çalacak her yerde ve bu müzik çalmaya başladığı an yükleme ekranı yok olacak, ana menü ekranına gelmiş olacağım. Ayrıca yükleme ekranı sırasında Oyunu Başlat ve Hesabı Sıfırla butonları tıklanamaz olmalı.
User prompt
Şu anda yükleme ekranı sesi yarıda kesiliyor, sonuna kadar çalmıyor. Ayrıca yükleme ekranı sesinden sonra oyun müziği çalmaya başlayınca da yükleme ekranı kaybolmuyor hala gözükmeye devam ediyor.
User prompt
Şu anda oyun müziği çalmaya başlamadan, en azından ben sesini duymaya başlamadan önce yükleme ekranı kayboluyor. Ayrıca Oyun müziği, yükleme ekranı sesi çalıp bittikten sonra yani yaklaşık 5 saniye sonra çalmaya başlayacak. Bu şekilde düzeltmen lazım kodu.
User prompt
Yükleme ekranının kaybolma zamanı oyunEkraniMuzigi müziğinin çalmaya başladığı zaman olsun. Yani oyunEkraniMuzigi çalmaya başladığı zaman yükleme ekranı kaybolsun ana menüye geleyim.
User prompt
Please fix the bug: 'yuklemeEkraniSesi is not defined' in or related to this line: 'if (!yuklemeEkraniSesi || typeof yuklemeEkraniSesi.isPlaying !== "function" && typeof yuklemeEkraniSesi.playing !== "boolean") {' Line Number: 3484
Code edit (2 edits merged)
Please save this source code
User prompt
Şu anda yükleme ekranında yuklemeEkraniSesi çalmadı hiç fakat fakat yükleme ekranı kayboldu ve ana menüye geldim. yuklemeEkraniSesi çalmadığı sürece 1 kere, yükleme ekranı ekranını görmeye devam etmem gerekiyor.
User prompt
Yükleme ekranı geldiğinde yuklemeEkraniSesi çalmıyor, yuklemeEkraniSesi çalıp bitemeden yükleme ekranı kayboluyor. yuklemeEkraniSesi çalıp bitmeden yükleme ekranı kaybolmasın. yuklemeEkraniSesi çalmayı bitirdikten sonra 1 saniye daha dursun ve sonrasında kaybolsun ve ana menü ekranına geleyim.
User prompt
Yükleme ekranı gelince (yükleme ekranında) "yuklemeEkraniSesi" çalsın 1 kere. Bu ses bitmeden oyunEkraniMuzigi devreye giremez olmalı.
User prompt
Yükleme ekranı gelince (yükleme ekranında) "yuklemeEkraniSesi" çalsın 1 kere. Bu ses bitmeden oyunEkraniMuzigi devreye giremez olmalı.
User prompt
Yükleme ekranı gelince (yükleme ekranında) "yuklemeEkraniSesi" çalsın 1 kere. Bu ses bitmeden oyunEkraniMuzigi devreye giremez olmalı.
User prompt
Kazanma oranı ve oynanan oyun sayısını gösteren yazı yükleme ekranı sırasında gözükmesin, sonrasında ana menü ekranında da oyun ekranında da oyun sonu ekranında da gözükmeye devam edebilir.
Code edit (5 edits merged)
Please save this source code
User prompt
Ana menü ekranında (sadece ana menü ekranında) "instaText.anchor.set(0.5, 0); instaText.x = langBtn.x - 586; instaText.y = langBtn.y + 1040;" pozisyonunda kırmızı renkle "Instagram: ugurcanyardim_" yazsın. "betaText.anchor.set(0, 0); // left-top betaText.x = instaText.x + 1274; betaText.y = instaText.y;" pozisyonunda sarı renkle "Erken Erişim" yazsın.
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: npcBustFlow is not defined' in or related to this line: 'npcBustFlow(); // Mevcut iflas akışınızı fonksiyonlaştırdıysanız' Line Number: 218
Code edit (10 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: allCombos is not defined' in or related to this line: 'bestMove = allCombos.reduce(function (max, c) {' Line Number: 2274
Code edit (7 edits merged)
Please save this source code
User prompt
Ama şu anda bu yazı ana menü ekranında da yükleme ekranında da oyun sonu ekranında da gözüküyor. Bu yazının yalnızca oyun ekranında gözüküyor olması gerekiyor. Ayrıca oradaki sayılar ben sadece TAMAM dediğim zaman güncelleniyor. Oradaki yazıların ben her zar attığımda gelen zar değerlerine göre güncelleniyor olması gerekiyor bastığım tuşlardan bağımsız olarak. Yani oradaki sayıların değerleri benim attığım zarların sonucunda gelen zarların sonuçlarını gösteriyor aslında yani attığım zarlar sonucunda kaç tane 1,2,3,4,5,6 ya da joker geldiğini gösteriyor.
User prompt
Ama şu anda zar2, zar3... falan görsel assetleri yok, yazıları yazıyor. Ben görsel assetleri olsun istemiştim.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // geri düş: ms cinsinden epoch // Konfeti Parçacığı Sınıfı var ConfettiParticle = Container.expand(function () { var self = Container.call(this); // Rastgele renk ve şekil seç function randomColor() { // Canlı, pastel ve koyu renkler karışık var palette = [[255, 59, 59], // kırmızı [59, 255, 59], // yeşil [59, 59, 255], // mavi [255, 224, 102], // sarı [102, 224, 255], // açık mavi [255, 102, 224], // pembe [255, 255, 255], // beyaz [255, 165, 0], // turuncu [0, 230, 230], // cam göbeği [142, 68, 173], // mor [46, 204, 64], // koyu yeşil [243, 156, 18], // altın sarısı [231, 76, 60], // canlı kırmızı [22, 160, 133], // teal [52, 73, 94], // koyu mavi [255, 192, 203], // pastel pembe [173, 216, 230], // pastel mavi [255, 255, 153], // pastel sarı [204, 255, 204], // pastel yeşil [255, 153, 204] // pastel fuşya ]; var idx = Math.floor(Math.random() * palette.length); var rgb = palette[idx]; // RGB to hex return (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]; } var color = randomColor(); var shapeType = Math.random() < 0.5 ? 'box' : 'ellipse'; // Rastgele boyut var size = 32 + Math.floor(Math.random() * 32); // Asset oluştur // 'confettiShape' adında bir shape asset'i kullanıyoruz (id önemli değil, motor otomatik oluşturur) var asset = self.attachAsset('confettiShape', { width: size, height: size, anchorX: .5, anchorY: .5 }); asset.tint = color; // Başlangıç pozisyonu: X rastgele, Y üstte self.x = 80 + Math.random() * (2048 - 160); self.y = -40 - Math.random() * 80; // Rastgele hız ve açı self.vy = 3 + Math.random() * 3; // Düşme hızı self.vx = -2 + Math.random() * 4; // Sağa/sola savrulma self.spin = -0.05 + Math.random() * 0.1; // Hafif dönme // Hafifçe şeffaflık asset.alpha = 0.85 + Math.random() * 0.15; // Hafifçe farklı ölçek asset.scaleX = 0.8 + Math.random() * 0.6; asset.scaleY = 0.8 + Math.random() * 0.6; // Dönme açısı asset.rotation = Math.random() * Math.PI * 2; // Son pozisyonları takip et (gerekirse) self.lastY = self.y; // Her frame güncelle self.update = function () { self.x += self.vx; self.y += self.vy; asset.rotation += self.spin; // Hafifçe sağa/sola dalgalanma self.vx += -0.1 + Math.random() * 0.2; // Ekran dışına çıktıysa yok et if (self.y > 2732 + 60) { if (self.parent) { self.parent.removeChild(self); } self._destroyed = true; } }; return self; }); /**** * Initialize Game ****/ /*********************************************************** * 1. KISIM — VARLIKLAR, GENEL TANIMLAR, Dice SINIFI ************************************************************/ /* --- Zar sınıfı --- */ // Joker zarı için (zar6 ile aynı görsel, gerekirse farklı id ile değiştir) // Kanvas boyutları /* --- Oyun nesnesi --- */ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ /* === AI globals & stats ================================= */ var NPC_STEP_DELAY = 1000; // 1 saniye function applyFinalDecision() { // BANK mi DEVAM mı zaten bestMoveBank değişkeninde if (bestMoveBank) { var _LK$getSound; (_LK$getSound = LK.getSound('tutVeTuruSonlandirSesi')) === null || _LK$getSound === void 0 || _LK$getSound.play(); // 1 sn boyunca seçili zarlar ekranda kalsın LK.setTimeout(function () { var _bestMove$score, _bestMove; selectedScores[NPC] = (_bestMove$score = (_bestMove = bestMove) === null || _bestMove === void 0 ? void 0 : _bestMove.score) !== null && _bestMove$score !== void 0 ? _bestMove$score : 0; tempScores[NPC] += selectedScores[NPC]; scores[NPC] += tempScores[NPC]; tempScores[NPC] = selectedScores[NPC] = 0; updateHUD(); endTurn(); }, NPC_STEP_DELAY); } else { var _LK$getSound2, _bestMove$score2, _bestMove2; (_LK$getSound2 = LK.getSound('tutVeDevamEtSesi')) === null || _LK$getSound2 === void 0; // Skoru hemen hesapla ama zarları SİLMEYİ 1 sn sonra yap selectedScores[NPC] = (_bestMove$score2 = (_bestMove2 = bestMove) === null || _bestMove2 === void 0 ? void 0 : _bestMove2.score) !== null && _bestMove$score2 !== void 0 ? _bestMove$score2 : 0; tempScores[NPC] += selectedScores[NPC]; selectedScores[NPC] = 0; updateHUD(); LK.setTimeout(function () { // Zarları kaldır + devam et dice = dice.filter(function (d) { return !d.selected; }); selectedDiceIdx = []; renumberDice(); if (dice.length === 0) { resetDice(6); } else { dice.forEach(function (d) { d.selected = false; d.setValue(1 + Math.random() * 6 | 0); }); } updateDicePositions(); updateHUD(); // Bust kontrolü vs. eski kodun geri kalanı var leftVals = dice.map(function (d) { return d.value; }); if (!canMakeAnyScore(leftVals)) { npcBustFlow(); // Mevcut iflas akışınızı fonksiyonlaştırdıysanız } else { npcTurn(); // Yeni tur } }, NPC_STEP_DELAY); } } var lastCombos = null; // --- 1A) Oyunun MCTS için serileştirilmiş hali --- function _createForOfIteratorHelper4(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray4(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n4 = 0, F = function F() {}; return { s: F, n: function n() { return _n4 >= r.length ? { done: !0 } : { done: !1, value: r[_n4++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) { throw o; } } } }; } function _unsupportedIterableToArray4(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray4(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray4(r, a) : void 0; } } function _arrayLikeToArray4(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } function _typeof3(o) { "@babel/helpers - typeof"; return _typeof3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof3(o); } function _typeof2(o) { "@babel/helpers - typeof"; return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof2(o); } function _classCallCheck2(a, n) { if (!(a instanceof n)) { throw new TypeError("Cannot call a class as a function"); } } function __defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey2(o.key), o); } } function _createClass2(e, r, t) { return r && __defineProperties(e.prototype, r), t && __defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey2(t) { var i = _toPrimitive2(t, "string"); return "symbol" == _typeof2(i) ? i : i + ""; } function _toPrimitive2(t, r) { if ("object" != _typeof2(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof2(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function makeState() { return { diceVals: dice.map(function (d) { return d.value; }), // ör: [1,5,5,3,2,1] diceLeft: dice.length, selScore: tempScores[NPC], // NPC’nin tur içi biriktirdikleri banked: scores.slice(), // [player, npc] riskTol: riskTolerance // karar sırasında kullanılan eşik }; } // --- 1B) Tüm mümkün hamleleri çıkar ---- function legalMoves(state) { // basit: tüm geçerli kombolar + “BANK” var combos = []; for (var k = 1; k <= state.diceVals.length; k++) { getCombinations(state.diceVals, k).forEach(function (c) { if (isValidSelection(c)) { combos.push({ type: 'KEEP', dice: c }); } }); } combos.push({ type: 'BANK' }); return combos; } // --- 2) MCTS Node sınıfı --------------------------------- var Node = /*#__PURE__*/function () { function Node(state) { var parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var move = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; _classCallCheck2(this, Node); this.state = state; this.parent = parent; this.move = move; // bu düğüme gelirken yapılan hamle this.children = []; this.N = 0; // ziyaret this.W = 0; // toplam ödül } return _createClass2(Node, [{ key: "uct", value: function uct() { var c = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1.4; if (this.N === 0) { return Infinity; } return this.W / this.N + c * Math.sqrt(Math.log(this.parent.N + 1) / this.N); } }, { key: "isLeaf", value: function isLeaf() { return this.children.length === 0; } }, { key: "select", value: function select() { var node = this; while (!node.isLeaf()) { node = node.children.reduce(function (a, b) { return a.uct() > b.uct() ? a : b; }); } if (node.N > 0) { node.expand(); } return node; } }, { key: "expand", value: function expand() { var _this2 = this; // keep the local alias var moves = legalMoves(this.state); moves.forEach(function (mv) { var next = applyMove(_this2.state, mv); var child = new Node(next, _this2, mv); _this2.children.push(child); // ► use _this2 instead of this2 }); } }, { key: "backprop", value: function backprop(reward) { var n = this; while (n) { n.N++; n.W += reward; n = n.parent; } } }, { key: "bestChild", value: function bestChild() { return this.children.reduce(function (a, b) { return a.N > b.N ? a : b; }); } }]); }(); // --- 2B) Hamleyi uygula (basitleştirilmiş) --------------- // utils.js ya da dosyanın başına ekleyin function cloneState(src) { return { diceVals: src.diceVals.slice(), // Array kopyası diceLeft: src.diceLeft, selScore: src.selScore, banked: src.banked.slice(), // Array kopyası riskTol: src.riskTol }; } function applyMove(state, move) { state = cloneState(state); // ← Güvenli ve hızlı kopya if (move.type === 'BANK') { state.banked[1] += state.selScore; // NPC bankladı state.selScore = 0; state.diceVals = []; // tur bitti → roll 6 state.diceLeft = 6; } else { // KEEP var score = calcScoreFarkle(move.dice).score; state.selScore += score; // seçilen zarları listeden at move.dice.forEach(function (v) { var idx = state.diceVals.indexOf(v); if (idx > -1) { state.diceVals.splice(idx, 1); } }); state.diceLeft = state.diceVals.length === 0 ? 6 : state.diceVals.length; } return state; } // --- 2C) Rollout (hedefe ulaşana veya limit tur sayısına kadar random) ---- function rollout(state) { // ► Heuristik: rastgele yerine beklenen skor var quickEval = function quickEval(s) { return s.banked[1] + s.selScore + exactFarkleTable[s.diceLeft].expected * (1 - exactFarkleTable[s.diceLeft].bust); }; var turns = 0; while (turns < 3 && state.banked[1] + state.selScore < TARGET_SCORE) { var moves = legalMoves(state); var mv = moves[Math.random() * moves.length | 0]; state = applyMove(state, mv); // eğer BANK yaptıysak sıra oyuncuya geçti gibi düşünebiliriz turns++; } return quickEval(state); } function mctsDecision(startState) { var millis = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1200; var root = new Node(startState); root.expand(); // ilk katmanı oluştur var t0 = perfNow(); while (perfNow() - t0 < millis) { var leaf = root.select(); var reward = rollout(leaf.state); leaf.backprop(reward); } return root.bestChild(); // .move da içerir } var bestMove = null, bestMoveBank = false, bestMoveScore = -Infinity; var perfNow = typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now.bind(performance) : function () { return Date.now(); }; // yüksek çözünürlüklü süre /* --- Arama parametreleri --- */ var _memo = Object.create(null); // look-ahead önbellek var _startTime = 0; // bu NPC turunun başlangıcı var TIME_BUDGET = 40; // ms – tek arama “dilimi” (progressive deepening) var HARD_LIMIT = 2000; // ms – tur başına mutlak sınır var MAX_TIME_MS = 3000; // düşünme zamanı var MCTS_BUDGET_MS = 60; // (yeni) bir turda MCTS’e ayıracağımız süre var MAX_COMBO_EVAL = 4; // (yeni) en iyi 4 kombinasyonu derin incele var riskTolerance = 0.65; /* === Online Q-table (risk learner) ====================== */ var qTable = {}; // key: “diff|turn#” val: riskTol var alpha = .3; // öğrenme hızı var gama = .9; // discount function stateKey() { var diff = scores[NPC] - scores[PLAYER]; return Math.round(diff / 500) + "|" + turnNumber; } function getRisk() { var _qTable$k; var k = stateKey(); return (_qTable$k = qTable[k]) !== null && _qTable$k !== void 0 ? _qTable$k : 0.35; // varsayılan } function updateQ(reward) { var _qTable$k2; var k = stateKey(); var old = (_qTable$k2 = qTable[k]) !== null && _qTable$k2 !== void 0 ? _qTable$k2 : 0.35; qTable[k] = old + alpha * (reward + gama * old - old); // basit TD(0) → reward pozitifse risk artar riskTolerance = qTable[k]; // canlı güncelle } var playerTurnCount = 0; var playerBankCount = 0; // Konfeti renkleri (dilediğin kadar ekleyebilirsin) // --- Konfeti Efekti için Global Değişkenler ve Sınıf --- // Music for each screen var CONFETTI_COLORS = [0xff3b3b, 0x3bff3b, 0x3b3bff, 0xffe066, 0x66e0ff, 0xff66e0, 0xffffff, 0xffa500, 0x00e6e6]; // Konfeti parçacıklarını tutan dizi var confettiParticles = []; // Konfeti efektinin interval referansı var confettiInterval = null; // utils.js – script’in başına ekle function enumerateRolls(n, buf, out) { buf = buf || []; out = out || []; if (buf.length === n) { out.push(buf.slice()); return out; } for (var v = 1; v <= 6; v++) { buf.push(v); enumerateRolls(n, buf, out); buf.pop(); } return out; } // Küçük bir cache – aynı n için tekrar hesaplamasın var _rollCache = {}; function getAllRolls(n) { return _rollCache[n] || (_rollCache[n] = enumerateRolls(n)); } function depthFor(n, hotDice) { // daha sığ – CPU harcamasını %30 ↓ if (hotDice) { return 8; } return n <= 2 ? 7 : n === 3 ? 6 : n === 4 ? 5 : 4; } /* 1-6 zar için tam simetrik permütasyon kümesi – 7776’dan ≈ 1 020 satıra iner */ var _symTable = {}; function getSymmetricRolls(n) { if (_symTable[n]) { return _symTable[n]; } var uniq = Object.create(null), arr = []; function rec(pos, buf) { if (pos === n) { uniq[buf.join('')] = buf.slice(); return; } for (var v = 1; v <= 6; v++) { buf[pos] = v; rec(pos + 1, buf); } } rec(0, new Array(n)); /* anahtar sırası önemli değil */ for (var k in uniq) { arr.push(uniq[k]); } return _symTable[n] = arr; } /* --- Zar sınıfı --- */ // Joker zarı için (zar6 ile aynı görsel, gerekirse farklı id ile değiştir) function _createForOfIteratorHelper3(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray3(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n3 = 0, F = function F() {}; return { s: F, n: function n() { return _n3 >= r.length ? { done: !0 } : { done: !1, value: r[_n3++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) { throw o; } } } }; } function _unsupportedIterableToArray3(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray3(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray3(r, a) : void 0; } } function _arrayLikeToArray3(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } function _createForOfIteratorHelper2(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray2(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n2 = 0, F = function F() {}; return { s: F, n: function n() { return _n2 >= r.length ? { done: !0 } : { done: !1, value: r[_n2++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) { throw o; } } } }; } function _unsupportedIterableToArray2(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray2(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray2(r, a) : void 0; } } function _arrayLikeToArray2(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) { throw o; } } } }; } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) { return; } f = !1; } else { for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0) { ; } } } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) { return; } } finally { if (o) { throw n; } } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) { return r; } } function _classCallCheck(a, n) { if (!(a instanceof n)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) { return e; } if (void 0 !== e) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(t); } function _assertThisInitialized(e) { if (void 0 === e) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return e; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) { throw new TypeError("Super expression must either be null or a function"); } t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } var W = 2048, H = 2732; var Dice = /*#__PURE__*/function (_Container) { function Dice() { var _this; _classCallCheck(this, Dice); _this = _callSuper(this, Dice); /** Zar yüzü (1-6) */ _this.value = 1; /** Seçili mi? */ _this.selected = false; // Zar yüzü asset'i (her değer için ayrı) _this.face = _this.attachAsset('zar1', { anchorX: .5, anchorY: .5 }); _this.updateFace = function () { // Eski asset'i kaldır if (_this.face && _this.face.parent) { _this.face.parent.removeChild(_this.face); } // Yeni asset'i ekle var assetName = 'zar' + _this.value; _this.face = _this.attachAsset(assetName, { anchorX: .5, anchorY: .5 }); }; // Başlangıçta 1 ile başlat _this.value = 1; _this.selected = false; _this.updateFace(); return _this; } /** Değeri ayarla + yüzü güncelle */ _inherits(Dice, _Container); return _createClass(Dice, [{ key: "setValue", value: function setValue(v) { this.value = v; this.updateFace(); } }]); }(Container); /* --- Global durum --- */ var PLAYER = 0, NPC = 1; var scores = [0, 0], turnScore = 0, current = PLAYER, gameOver = false; var dice = []; // Aktif zarlar var selectedDiceIdx = []; // Seçili zar indeksleri var diceGroup = null, selectedDiceGroup = null; /* --- Diziyi yeniden numaralandır + doğru tıklama --- */ function renumberDice() { for (var i = 0; i < dice.length; i++) { var d = dice[i]; d.idx = i; // güncel indis d.down = function () { toggleSelect(this.idx); }; // <— closure sorunu yok } } /*********************************************************** * 2. KISIM — SKOR HESABI ve KOMBİNASYON YARDIMCILARI ************************************************************/ /* Farkle puan tablosu */ function calcScoreFarkle(vals) { var cnt = Array(7).fill(0); vals.forEach(function (v) { return cnt[v]++; }); var score = 0, used = []; /* Full straight 1-6 */ if (vals.length === 6 && [1, 2, 3, 4, 5, 6].every(function (v) { return cnt[v] === 1; })) { return { score: 1500, used: [0, 1, 2, 3, 4, 5] }; } /* Partial straight 1-5 */ if (vals.length === 5 && [1, 2, 3, 4, 5].every(function (v) { return cnt[v]; })) { return { score: 500, used: [0, 1, 2, 3, 4] }; } /* Partial straight 2-6 */ if (vals.length === 5 && [2, 3, 4, 5, 6].every(function (v) { return cnt[v]; })) { return { score: 750, used: [0, 1, 2, 3, 4] }; } /* 3-6 aynı zar kümeleri */ for (var v = 1; v <= 6; v++) { if (cnt[v] >= 3) { var base = v === 1 ? 1000 : v * 100; var factor = [1, 2, 4, 8][cnt[v] - 3]; score += base * factor; var need = cnt[v]; vals.forEach(function (val, i) { if (val === v && need) { used.push(i); need--; } }); cnt[v] = 0; // tekil sayılmasın } } /* Tekil 1 & 5 */ vals.forEach(function (v, i) { if (used.includes(i)) { return; } if (v === 1) { score += 100; used.push(i); } if (v === 5) { score += 50; used.push(i); } }); return { score: score, used: used }; } /***************************************************************** * Eksiksiz olasılık tablosu – oyun açılışında bir kez hesaplanır *****************************************************************/ var exactFarkleTable = {}; // diceLeft → {bust, expected} (function buildExactTable() { for (var diceLeft = 1; diceLeft <= 6; diceLeft++) { var total = 0; // 6^n var bustCount = 0; var scoreSum = 0; // yalnızca skor alınan durumlarda toplanır var faces = Array(diceLeft).fill(0); // kartesyen ürün: 6^diceLeft kombinasyonu tek tek dolaş (function dfs(pos) { if (pos === diceLeft) { total++; var r = calcScoreFarkle(faces); if (r.score === 0) { bustCount++; } else { scoreSum += r.score; } // en yüksek skora göre return; } for (var f = 1; f <= 6; f++) { faces[pos] = f; dfs(pos + 1); } })(0); var bustProb = bustCount / total; var expectedWhenScore = scoreSum / Math.max(1, total - bustCount); // skorlu durumda ort. exactFarkleTable[diceLeft] = { bust: bustProb, expected: expectedWhenScore }; } })(); /* Seçim geçerli mi? */ function isValidSelection(selVals) { var r = calcScoreFarkle(selVals); return r.score > 0 && r.used.length === selVals.length; } /* Belirli uzunlukta kombinasyonları döndür */ function getCombinations(arr, k) { var out = []; (function helper(start, path) { if (path.length === k) { out.push(path.slice()); return; } for (var i = start; i < arr.length; i++) { path.push(arr[i]); helper(i + 1, path); path.pop(); } })(0, []); return out; } /* Kalan zarlarla **hiç** skor yapılabilir mi? */ function canMakeAnyScore(vals) { if (!vals.length) { return false; } for (var i = 1; i <= vals.length; i++) { var combs = getCombinations(vals, i); var _iterator = _createForOfIteratorHelper(combs), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var c = _step.value; if (isValidSelection(c)) { return true; } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } return false; } /*********************************************************** * 3. KISIM — GUI, HUD ve ZAR YÖNETİMİ ************************************************************/ /* --- Butonlar --- */ // TUT ve DEVAM ET butonu var rollBtn = new Container(); rollBtn.attachAsset('tutVeDevamEtButonuGorseli', { anchorX: .5, anchorY: .5 }); var rollTxt = new Text2('DEVAM', { size: 80, fill: '#fff' }); rollTxt.anchor.set(.5, .5); rollTxt.y = 40; rollBtn.addChild(rollTxt); LK.gui.bottom.addChild(rollBtn); rollBtn.x = -500; rollBtn.y = -160; // TUT ve TURU SONLANDIR butonu var bankBtn = new Container(); bankBtn.attachAsset('tutVeTuruSonlandirButonuGorseli', { anchorX: .5, anchorY: .5 }); var bankTxt = new Text2('TAMAM', { size: 80, fill: '#fff' }); bankTxt.anchor.set(.5, .5); bankTxt.y = 40; bankBtn.addChild(bankTxt); LK.gui.bottom.addChild(bankBtn); bankBtn.x = 0; bankBtn.y = -160; // PAS GEÇ butonu var passBtn = new Container(); passBtn.attachAsset('pasGecButonuGorseli', { anchorX: .5, anchorY: .5 }); var passTxt = new Text2('PAS', { size: 80, fill: '#fff' }); passTxt.anchor.set(.5, .5); passTxt.y = 40; passBtn.addChild(passTxt); LK.gui.bottom.addChild(passBtn); // PAS GEÇ butonunu TUT ve TURU SONLANDIR butonunun sağına yerleştir passBtn.x = 500; passBtn.y = -160; /* --- Reset & Pozisyon --- */ function resetDice() { var n = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 6; var randomize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (diceGroup) { diceGroup.destroy(); } if (selectedDiceGroup) { selectedDiceGroup.destroy(); } dice = []; selectedDiceIdx = []; diceGroup = new Container(); selectedDiceGroup = new Container(); game.addChild(diceGroup); game.addChild(selectedDiceGroup); var diceSpacing = 280; var startX = W / 2 - (n - 1) * diceSpacing / 2; var y = H / 2; for (var i = 0; i < n; i++) { var d = new Dice(); d.x = startX + i * diceSpacing; d.y = y; if (randomize) { d.setValue(1 + (Math.random() * 6 | 0)); } diceGroup.addChild(d); dice.push(d); } renumberDice(); updateDicePositions(); updateHUD(); } /* Seç/Aç seçimi */ function toggleSelect(idx) { if (gameOver || current !== PLAYER) { return; } var d = dice[idx]; if (d.selected) { d.selected = false; selectedDiceIdx = selectedDiceIdx.filter(function (i) { return i !== idx; }); // Play zarBirakmaSesi when deselecting var birakmaSesi = LK.getSound && LK.getSound('zarBirakmaSesi'); if (birakmaSesi && birakmaSesi.play) { birakmaSesi.play(); } } else { d.selected = true; if (!selectedDiceIdx.includes(idx)) { selectedDiceIdx.push(idx); } // Play zarSecmeSesi when selecting var secmeSesi = LK.getSound && LK.getSound('zarSecmeSesi'); if (secmeSesi && secmeSesi.play) { secmeSesi.play(); } } updateDicePositions(); updateHUD(); } /* Konumları güncelle */ function updateDicePositions() { if (!diceGroup || !selectedDiceGroup) { return; } diceGroup.removeChildren(); selectedDiceGroup.removeChildren(); // YENİ: her iki oyuncu için d.selected bayrağını kullan var sel = [], unsel = []; for (var i = 0; i < dice.length; i++) { var d = dice[i]; if (!d) { continue; } // güvenlik if (d.selected) { sel.push(i); selectedDiceGroup.addChild(d); } else { unsel.push(i); diceGroup.addChild(d); } } /* Seçili zarlar aşağıda (hem PLAYER hem de NPC için) */ // 2. oyuncu (NPC) için de seçili zarlar aşağıda dizilecek var diceSpacing = 280; var selStart = W / 2 - (sel.length - 1) * diceSpacing / 2; var selY = H / 2 + 280; sel.forEach(function (idx, i) { var d = dice[idx]; d.x = selStart + i * diceSpacing; d.y = selY; d.face.alpha = .6; }); /* Diğer zarlar ortada */ var unStart = W / 2 - (unsel.length - 1) * diceSpacing / 2, y = H / 2; unsel.forEach(function (idx, i) { var d = dice[idx]; d.x = unStart + i * diceSpacing; d.y = y; d.face.alpha = 1; }); } /**** ZAR DÖNDÜRME ANİMASYONU ****/ function animateRoll(onFinish) { var playSfx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (game._rolling) { return; } // Çifte animasyonu engelle game._rolling = true; if (playSfx) { var s = LK.getSound && LK.getSound('tutVeDevamEtSesi'); s === null || s === void 0 || s.play(); } rollBtn.interactive = bankBtn.interactive = passBtn.interactive = false; dice.forEach(function (d) { return d.down = function () {}; }); // Zarlar seçilemesin var rollDuration = 2000, step = 60; var elapsed = 0; (function tick() { dice.forEach(function (d) { if (!d.selected) { d.setValue(1 + Math.random() * 6 | 0); } }); updateDicePositions(); if ((elapsed += step) < rollDuration) { LK.setTimeout(tick, step); } else { game._rolling = false; rollBtn.interactive = bankBtn.interactive = passBtn.interactive = true; renumberDice(); // Zarlar yeniden seçilebilir // --- Zar istatistiklerini güncelle (sadece oyuncu için) --- if (current === PLAYER) { var playerDiceVals = dice.filter(function (d) { return !d.selected; }).map(function (d) { return d.value; }); updateZarStatsForPlayerDice(playerDiceVals); refreshZarStatsTxt(); } onFinish === null || onFinish === void 0 || onFinish(); // Animasyon tamam callback } })(); } /*********************************************************** * 4. KISIM — OYUN DÖNGÜSÜ, NPC, HUD, BAŞLAT ************************************************************/ /* --- HUD --- */ // Skor tablosu için Text2 objeleri var scoreTableRows = [null, null, null, null]; var turnTxt; var TARGET_SCORE = 8000; // Hedef puan var BANK_BIAS = TARGET_SCORE * 2; /* vuruş anında daha agresif banklama */ var _INFTY = 1e12; // alpha-beta için pratik sonsuz // Geçici ve seçilen skorlar için yeni değişkenler var tempScores = [0, 0]; // Geçici skorlar (her oyuncu için) var selectedScores = [0, 0]; // Seçilen skorlar (her oyuncu için) var turnNumber = 1; // Tur sayısı function updateHUD() { // --- Buton aktifliği --- var selVals = selectedDiceIdx.map(function (i) { return dice[i].value; }); var valid = isValidSelection(selVals); rollBtn.alpha = bankBtn.alpha = valid ? 1 : 0.4; rollBtn.interactive = bankBtn.interactive = valid && current === PLAYER && !gameOver; // --- Skor tablosu ilk kez oluşturuluyorsa ekle --- if (!scoreTableRows[0]) { // --- Zar kombinasyonları ve puan tablosu --- // Zar assetlerini göstermek için fonksiyon var createDiceRow = function createDiceRow(diceArr, text, size, gap) { var row = new Container(); var x = 0; for (var i = 0; i < diceArr.length; i++) { var asset = LK.getAsset(diceArr[i], { anchorX: 0.5, anchorY: 0.5, width: size, height: size }); asset.x = x; asset.y = 0; row.addChild(asset); x += size + (gap || 10); } if (text) { var txt = new Text2(text, { size: size * 0.6, fill: '#fff' }); txt.anchor.set(0, 0.5); txt.x = x - 25; txt.y = 0; row.addChild(txt); } return row; }; // Tabloyu oluştur // --- Kazanma oranı göstergesi --- // storage'dan toplam oyun ve kazanılan oyun sayısını al var totalGames = typeof storage.totalGames === "number" ? storage.totalGames : 0; var winGames = typeof storage.winGames === "number" ? storage.winGames : 0; if (!window.winRateTxt) { window.winRateTxt = new Text2("", { size: 48, fill: '#ffe066', fontWeight: 'bold' }); window.winRateTxt.anchor.set(0.5, 0); LK.gui.top.addChild(window.winRateTxt); } var winRateStr = "% ?"; if (totalGames > 0) { var rate = Math.round(winGames / totalGames * 100); winRateStr = "%" + rate; } var oyunSayisiStr = totalGames > 0 ? totalGames : "?"; window.winRateTxt.setText("Kazanma Oranı: " + winRateStr + " | Oynanan Oyun Sayısı: " + oyunSayisiStr); window.winRateTxt.x = 0; window.winRateTxt.y = 20; // 1. satır: başlıklar var playerNameDisplay = typeof playerName === "string" && playerName.length > 0 ? playerName : "1. Oyuncu"; scoreTableRows[0] = new Text2(playerNameDisplay + " | Hedef | Yapay Zeka", { size: 54, fill: '#fff', fontWeight: 'bold' }); scoreTableRows[0].anchor.set(0.5, 0); LK.gui.top.addChild(scoreTableRows[0]); // Skor tablosunu ekranın tam ortasına yerleştir // Tüm satırları ve sıra göstergesini tam ekranın ortasına hizala var centerX = 0; scoreTableRows[0].x = centerX; scoreTableRows[0].y = 80; // 2. satır: ana skorlar ve hedef scoreTableRows[1] = new Text2("", { size: 54, fill: '#fff' }); scoreTableRows[1].anchor.set(0.5, 0); LK.gui.top.addChild(scoreTableRows[1]); scoreTableRows[1].x = centerX; scoreTableRows[1].y = scoreTableRows[0].y + 60; // 3. satır: geçici skorlar ve tur scoreTableRows[2] = new Text2("", { size: 48, fill: '#ffe066' }); scoreTableRows[2].anchor.set(0.5, 0); LK.gui.top.addChild(scoreTableRows[2]); scoreTableRows[2].x = centerX; scoreTableRows[2].y = scoreTableRows[1].y + 54; // 4. satır: seçilen skorlar scoreTableRows[3] = new Text2("", { size: 44, fill: '#b3e6ff' }); scoreTableRows[3].anchor.set(0.5, 0); LK.gui.top.addChild(scoreTableRows[3]); scoreTableRows[3].x = centerX; scoreTableRows[3].y = scoreTableRows[2].y + 48; // Sıra göstergesi turnTxt = new Text2('', { size: 54, fill: '#ffe066', fontWeight: 'bold' }); turnTxt.anchor.set(0.5, 0); LK.gui.top.addChild(turnTxt); turnTxt.x = centerX; turnTxt.y = scoreTableRows[3].y + 60; var scoreTableContainer = new Container(); scoreTableContainer.x = 0; scoreTableContainer.y = turnTxt.y + 90; var rowY = 0; var rowGap = 70; var diceSize = 60; var bigGap = 80; // 1. satır var row1a = createDiceRow(['zar1'], "= 100", diceSize); var row1b = createDiceRow(['zar1', 'zar1', 'zar1'], "= 1000", diceSize); row1a.x = -400; row1b.x = 200; row1a.y = row1b.y = rowY + 10; scoreTableContainer.addChild(row1a); scoreTableContainer.addChild(row1b); rowY += rowGap; // 2. satır var row2a = createDiceRow(['zar5'], "= 50", diceSize); var row2b = createDiceRow(['zar2', 'zar2', 'zar2'], "= 200", diceSize); row2a.x = -400; row2b.x = 200; row2a.y = row2b.y = rowY + 10; scoreTableContainer.addChild(row2a); scoreTableContainer.addChild(row2b); rowY += rowGap; // 3. satır var row3a = createDiceRow(['zar1', 'zar2', 'zar3', 'zar4', 'zar5'], "= 500", diceSize); var row3b = createDiceRow(['zar3', 'zar3', 'zar3'], "= 300", diceSize); row3a.x = -400; row3b.x = 200; row3a.y = row3b.y = rowY + 10; ; scoreTableContainer.addChild(row3a); scoreTableContainer.addChild(row3b); rowY += rowGap; // 4. satır var row4a = createDiceRow(['zar2', 'zar3', 'zar4', 'zar5', 'zar6'], "= 750", diceSize); var row4b = createDiceRow(['zar4', 'zar4', 'zar4'], "= 400", diceSize); row4a.x = -400; row4b.x = 200; row4a.y = row4b.y = rowY + 10; ; scoreTableContainer.addChild(row4a); scoreTableContainer.addChild(row4b); rowY += rowGap; // 5. satır var row5a = createDiceRow(['zar1', 'zar2', 'zar3', 'zar4', 'zar5', 'zar6'], "= 1500", diceSize); var row5b = createDiceRow(['zar5', 'zar5', 'zar5'], "= 500", diceSize); row5a.x = -400; row5b.x = 200; row5a.y = row5b.y = rowY + 10; ; scoreTableContainer.addChild(row5a); scoreTableContainer.addChild(row5b); rowY += rowGap; // 6. satır var row6a = createDiceRow(['zarJoker'], "= Joker", diceSize); var row6b = createDiceRow(['zar6', 'zar6', 'zar6'], "= 600", diceSize); row6a.x = -400; row6b.x = 200; row6a.y = row6b.y = rowY + 10; ; scoreTableContainer.addChild(row6a); scoreTableContainer.addChild(row6b); rowY += rowGap; // Ortala scoreTableContainer.x = 0; scoreTableContainer.y = turnTxt.y + 90; scoreTableContainer.pivot.x = 0; scoreTableContainer.pivot.y = 0; scoreTableContainer.anchorX = 0.5; scoreTableContainer.anchorY = 0; scoreTableContainer.x = 0; // GUI'ye ekle (top bölgesine, skor tablosunun altına) LK.gui.top.addChild(scoreTableContainer); scoreTableContainer.x = 0; scoreTableContainer.y = turnTxt.y + 90; // Altına gri açıklama yazısı ekle if (!window._farkleScoreInfoTxt) { var infoTxt = new Text2("3'ten sonraki her ilave zar değerini iki katına çıkarır.", { size: 38, fill: '#b0b0b0' }); infoTxt.anchor.set(0.5, 0); infoTxt.x = 0; infoTxt.y = scoreTableContainer.y + scoreTableContainer.height; LK.gui.top.addChild(infoTxt); window._farkleScoreInfoTxt = infoTxt; } else { // Her update'te pozisyonunu güncelle window._farkleScoreInfoTxt.x = 0; window._farkleScoreInfoTxt.y = scoreTableContainer.y + scoreTableContainer.height + 20; } // Tablonun referansını sakla (gerekirse erişmek için) window._farkleScoreTable = scoreTableContainer; } // --- Skor tablosunu güncelle --- scoreTableRows[1].setText("Ana Skor: " + scores[PLAYER] + " | " + TARGET_SCORE + " | " + "Ana Skor: " + scores[NPC]); scoreTableRows[2].setText("Geçici Skor: " + tempScores[PLAYER] + " | Tur: " + turnNumber + " | Geçici Skor: " + tempScores[NPC]); // Seçilen Skor'u canlı olarak güncelle (her iki oyuncu için) var liveSelectedScorePlayer = 0; var liveSelectedScoreNPC = 0; if (current === PLAYER && selectedDiceIdx.length > 0) { var selValsLive = selectedDiceIdx.map(function (i) { return dice[i].value; }); if (isValidSelection(selValsLive)) { liveSelectedScorePlayer = calcScoreFarkle(selValsLive).score; } } if (current === NPC && dice.length > 0) { // NPC'nin seçili zarlarını bul var selValsLiveNPC = []; for (var i = 0; i < dice.length; i++) { if (dice[i].selected) { selValsLiveNPC.push(dice[i].value); } } if (selValsLiveNPC.length > 0 && isValidSelection(selValsLiveNPC)) { liveSelectedScoreNPC = calcScoreFarkle(selValsLiveNPC).score; } } scoreTableRows[3].setText("Seçilen Skor: " + (current === PLAYER ? liveSelectedScorePlayer : selectedScores[PLAYER]) + " | Seçilen | Seçilen Skor: " + (current === NPC ? liveSelectedScoreNPC : selectedScores[NPC])); turnTxt.setText(current === PLAYER ? 'Sıra: 1. Oyuncuda' : 'Sıra: 2. Oyuncuda'); } // --- Zar istatistikleri: her oyuncuya gelen zarların adedi --- // storage'da saklanacak anahtarlar: zarStats = { zar1: 0, zar2: 0, ... } var diceStatKeys = ['zar2', 'zar3', 'zar4', 'zar5', 'zar6', 'zar1', 'zarJoker']; var defaultZarStats = { zar1: 0, zar2: 0, zar3: 0, zar4: 0, zar5: 0, zar6: 0, zarJoker: 0 }; if (_typeof3(storage.zarStats) !== "object" || !storage.zarStats) { storage.zarStats = Object.assign({}, defaultZarStats); } var zarStats = storage.zarStats; // --- Zar istatistiklerini güncelleyen fonksiyon --- // Bu fonksiyon, oyuncuya yeni zarlar geldiğinde çağrılmalı function updateZarStatsForPlayerDice(diceArr) { var changed = false; for (var i = 0; i < diceArr.length; i++) { var v = diceArr[i]; var key = "zar" + v; if (key === "zar0" || key === "zarundefined" || key === "zarNaN") { continue; } if (zarStats.hasOwnProperty(key)) { zarStats[key]++; changed = true; } } // Joker zarları da say (ör: value==7 veya value==0 ise zarJoker) for (var i = 0; i < diceArr.length; i++) { if (diceArr[i] === 0 || diceArr[i] === 7) { zarStats["zarJoker"]++; changed = true; } } if (changed) { storage.zarStats = zarStats; } } // --- Zar istatistiklerini gösteren görsel satır (dice assetleri + sayı) --- // Sadece bir kez oluşturulacak, sonra güncellenecek if (!window.zarStatsRow) { // Ana container var statsRow = new Container(); // Sıralama: zar2, zar3, zar4, zar5, zar6, zar1, zarJoker var diceKeys = diceStatKeys; var diceSize = 100; var gap = 20; var totalWidth = diceKeys.length * diceSize + (diceKeys.length - 1) * gap; var startX = -totalWidth / 2 + diceSize / 2; statsRow.diceAssets = []; statsRow.countTexts = []; for (var i = 0; i < diceKeys.length; i++) { var key = diceKeys[i]; // Zar görseli var asset = LK.getAsset(key, { anchorX: 0.5, anchorY: 1, width: diceSize, height: diceSize }); asset.x = startX + i * (diceSize + gap); asset.y = 0; statsRow.addChild(asset); statsRow.diceAssets.push(asset); // Altına sayı var count = zarStats[key] || 0; var countTxt = new Text2(count + "", { size: 36, fill: 0xFFE066, fontWeight: "bold" }); countTxt.anchor.set(0.5, 0); countTxt.x = asset.x; countTxt.y = 8; statsRow.addChild(countTxt); statsRow.countTexts.push(countTxt); } // 'tutVeTuruSonlandirButonuGorseli' assetinin biraz üstünde olacak şekilde konumlandır statsRow.x = bankBtn.x; statsRow.y = bankBtn.y - 200; LK.gui.bottom.addChild(statsRow); window.zarStatsRow = statsRow; } // --- Zar istatistiklerini güncelleyen fonksiyon (görsel) --- function refreshZarStatsTxt() { // Sıralama: zar2, zar3, zar4, zar5, zar6, zar1, zarJoker if (!window.zarStatsRow) { return; } for (var i = 0; i < diceStatKeys.length; i++) { var key = diceStatKeys[i]; var val = zarStats[key] || 0; if (window.zarStatsRow.countTexts[i]) { window.zarStatsRow.countTexts[i].setText(val + ""); } } } // --- Oyun başında ve her zar atışında güncelle refreshZarStatsTxt(); /**** --- Tur Aksiyonları --- */ function rollAll() { if (gameOver || current !== PLAYER) { return; } dice.forEach(function (d) { if (!d.selected) { d.setValue(1 + Math.floor(Math.random() * 6)); } }); // --- Zar istatistiklerini güncelle (sadece oyuncu için) --- if (current === PLAYER) { var playerDiceVals = dice.filter(function (d) { return !d.selected; }).map(function (d) { return d.value; }); updateZarStatsForPlayerDice(playerDiceVals); refreshZarStatsTxt(); } updateDicePositions(); updateHUD(); var unselVals = dice.filter(function (d) { return !d.selected; }).map(function (d) { return d.value; }); // Eğer oyuncu zar attıktan sonra hiçbir şekilde kombinasyon yapılamıyorsa otomatik olarak turu rakibe geçir if (!canMakeAnyScore(unselVals)) { // Kırmızı ekranı daha uzun göster (ör: 1200ms) LK.effects.flashScreen(0xff0000, 1200); // "İflas!" yazısı ekle var iflasTxt = new Text2('İflas!', { size: 180, fill: '#fff' }); iflasTxt.anchor.set(0.5, 0.5); iflasTxt.x = W / 2; iflasTxt.y = H / 2; iflasTxt.alpha = 1; game.addChild(iflasTxt); // İflas sesi (ben) var iflasBenSesi = LK.getSound && LK.getSound('iflasBenSesi'); if (iflasBenSesi && iflasBenSesi.play) { iflasBenSesi.play(); } // 1 saniye boyunca göster, sonra yavaşça kaybolsun LK.setTimeout(function () { tween(iflasTxt, { alpha: 0 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { if (iflasTxt && iflasTxt.parent) { iflasTxt.parent.removeChild(iflasTxt); } tempScores[current] = 0; selectedScores[current] = 0; turnScore = 0; updateHUD(); endTurn(); } }); }, 1000); } } function keepAndContinue() { if (gameOver || current !== PLAYER) { return; } var selVals = selectedDiceIdx.map(function (i) { return dice[i].value; }); if (!isValidSelection(selVals)) { return; } // Seçilen skor hesapla ve ekle var selScore = calcScoreFarkle(selVals).score; selectedScores[current] = selScore; tempScores[current] += selectedScores[current]; selectedScores[current] = 0; // Seçilen skor sıfırlanır // turnScore artık kullanılmıyor, backward compatibility için güncelle turnScore = tempScores[current]; // Seçili zarları kaldır dice = dice.filter(function (d, i) { return !selectedDiceIdx.includes(i); }).map(function (d) { return d; }); selectedDiceIdx = []; if (dice.length === 0) { resetDice(6); // --- Zar istatistiklerini güncelle (hot dice: yeni 6 zar geldi) --- if (current === PLAYER) { var playerDiceVals = []; for (var i = 0; i < dice.length; i++) { playerDiceVals.push(dice[i].value); } updateZarStatsForPlayerDice(playerDiceVals); refreshZarStatsTxt(); } } else { dice.forEach(function (d) { d.selected = false; // sadece seçimi temizle }); renumberDice(); updateDicePositions(); } updateHUD(); var unselVals = dice.map(function (d) { return d.value; }); // Eğer kalan zarlarla hiçbir şekilde kombinasyon yapılamıyorsa otomatik olarak turu rakibe geçir if (!canMakeAnyScore(unselVals)) { LK.effects.flashScreen(0xff0000, 1200); var iflasTxt = new Text2('İflas!', { size: 180, fill: '#fff' }); iflasTxt.anchor.set(0.5, 0.5); iflasTxt.x = W / 2; iflasTxt.y = H / 2; iflasTxt.alpha = 1; game.addChild(iflasTxt); // İflas sesi (ben) var iflasBenSesi = LK.getSound && LK.getSound('iflasBenSesi'); if (iflasBenSesi && iflasBenSesi.play) { iflasBenSesi.play(); } LK.setTimeout(function () { tween(iflasTxt, { alpha: 0 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { if (iflasTxt && iflasTxt.parent) { iflasTxt.parent.removeChild(iflasTxt); } tempScores[current] = 0; selectedScores[current] = 0; turnScore = 0; updateHUD(); endTurn(); } }); }, 1000); } } function keepAndEndTurn() { if (gameOver || current !== PLAYER) { return; } var selVals = selectedDiceIdx.map(function (i) { return dice[i].value; }); if (!isValidSelection(selVals)) { return; } // Seçilen skor hesapla ve ekle var selScore = calcScoreFarkle(selVals).score; selectedScores[current] = selScore; // Ana skora ekle: geçici skor + seçilen skor scores[current] += tempScores[current] + selectedScores[current]; // Sıfırla tempScores[current] = 0; selectedScores[current] = 0; turnScore = 0; updateHUD(); // --- Zar istatistiklerini güncelle (tur sonunda kalan zarlar) --- if (current === PLAYER) { var playerDiceVals = []; for (var i = 0; i < dice.length; i++) { playerDiceVals.push(dice[i].value); } updateZarStatsForPlayerDice(playerDiceVals); refreshZarStatsTxt(); } endTurn(); } function endTurn() { updateQ(scores[NPC] - scores[PLAYER]); // pozitif fark = cesaret // Kazanan kontrolü if (scores[current] >= TARGET_SCORE) { showWinner(); return; } _memo = Object.create(null); // yeni dal için taze DP // Sırayı değiştir var prevCurrent = current; /* --- oyuncu banklama istatistiği --- */ if (prevCurrent === PLAYER) { playerTurnCount++; // ‘bankladı’ demek: temp+selected scoru sıfırlanıp ana skora eklendi if (scores[PLAYER] > 0 && tempScores[PLAYER] === 0 && selectedScores[PLAYER] === 0) { playerBankCount++; } } current = current === PLAYER ? NPC : PLAYER; // Sıra değişiminde uygun sesi çal if (prevCurrent === PLAYER && current === NPC) { var rakibinSirasiSesi = LK.getSound && LK.getSound('rakibinSirasiSesi'); if (rakibinSirasiSesi && rakibinSirasiSesi.play) { rakibinSirasiSesi.play(); } } else if (prevCurrent === NPC && current === PLAYER) { var siraSendeSesi = LK.getSound && LK.getSound('siraSendeSesi'); if (siraSendeSesi && siraSendeSesi.play) { siraSendeSesi.play(); } } // Yeni oyuncunun geçici ve seçilen skorlarını sıfırla tempScores[current] = 0; selectedScores[current] = 0; turnScore = 0; // Tur sayısını sadece 1. oyuncuya geçerken artır if (current === PLAYER) { turnNumber++; } resetDice(6, current === PLAYER); updateHUD(); // --- HATA DÜZELTME: Zarlar otomatik atıldığında hiçbir kombinasyon yapılamıyorsa otomatik iflas ve sıra geçişi --- // Sadece yeni tur başında, zarlar atıldıktan hemen sonra kontrol et var unselVals = dice.map(function (d) { return d.value; }); if (!canMakeAnyScore(unselVals)) { // Ekranı kırmızıya flash et LK.effects.flashScreen(0xff0000, 1200); // "İflas!" yazısı ekle var iflasTxt = new Text2('İflas!', { size: 180, fill: '#fff' }); iflasTxt.anchor.set(0.5, 0.5); iflasTxt.x = W / 2; iflasTxt.y = H / 2; iflasTxt.alpha = 1; game.addChild(iflasTxt); // Sesi çal (oyuncuya göre) var iflasSesi = null; if (current === PLAYER) { iflasSesi = LK.getSound && LK.getSound('iflasBenSesi'); } else { iflasSesi = LK.getSound && LK.getSound('iflasRakipSesi'); } if (iflasSesi && iflasSesi.play) { iflasSesi.play(); } LK.setTimeout(function () { tween(iflasTxt, { alpha: 0 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { if (iflasTxt && iflasTxt.parent) { iflasTxt.parent.removeChild(iflasTxt); } tempScores[current] = 0; selectedScores[current] = 0; turnScore = 0; updateHUD(); // Sırayı tekrar değiştir (sonsuz döngüye girmemesi için current bir kez daha değişecek) // Not: endTurn fonksiyonu tekrar çağrılırsa, bir sonraki oyuncuya geçer endTurn(); } }); }, 1000); return; // Diğer kodları çalıştırma } if (current === NPC) { npcTurn(); // hemen animasyon } else { animateRoll(); // oyuncu turu başladı } /* risk eşiğini güncelle */ riskTolerance = getRisk(); } /* --- NPC Basit AI --- */ function npcTurn() { // Oyunun bittiğini veya sıranın NPC’de olmadığını kontrol et if (gameOver || current !== NPC) { return; } /* Önce tüm zarları seçimsiz hâle getir ve güncelle */ var _iterator3 = _createForOfIteratorHelper2(dice), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var d = _step3.value; d.selected = false; } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } updateDicePositions(); /* 2 sn’lik animasyon → bittikten SONRA hamleyi başlat (hemen düşün) */ animateRoll(function () { // — reset — bestMove = null; bestMoveBank = false; bestMoveScore = -Infinity; // düşünme zaman damgası _startTime = perfNow(); // 100 ms sonra düşünmeye başla → dilim dilim arama LK.setTimeout(function tickAI() { var keepGoing = npcThinkAfterRoll(); if (keepGoing) { LK.setTimeout(tickAI, TIME_BUDGET); } }, 100); }); } /**** NPC animasyon sonrası hamle ****/ function npcThinkAfterRoll() { /* TRUE ⇒ hâlâ zaman var, bir sonraki dilimde tekrar gel. FALSE ⇒ karar verildi, icraata geçildi */ if (perfNow() - _startTime > HARD_LIMIT) { // Zaman bitti; eğer hiç hamle yoksa İflas!, varsa hamleyi uygula if (bestMove && bestMove.score) { decideAndAct(); } else { // hiç skor yapılamıyorsa zaten iflas akışı var LK.effects.flashScreen(0xff0000, 1200); endTurn(); } return false; } // --- Süper Zeki, Yenilmez NPC AI --- // 1) Tüm olası geçerli kombinasyonları bul ve puanlarını hesapla var vals = dice.map(function (d) { return d.value; }); // -- Hız optimizasyonu: aynı yüzlerden // oluşan kombinasyonları tek örneğe indir function uniqByValue(arrOfArr) { var seen = Object.create(null), out = []; var _iterator2 = _createForOfIteratorHelper4(arrOfArr), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var a = _step2.value; var key = a.slice().sort().join(''); if (!seen[key]) { seen[key] = 1; out.push(a); } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return out; } /* 1) – Tüm geçerli kombinasyonları topla */ var allCombos = []; for (var len = 1; len <= vals.length; len++) { var combs = uniqByValue(getCombinations(vals, len)); for (var k = 0; k < combs.length; k++) { if (isValidSelection(combs[k])) { allCombos.push({ combo: combs[k], score: calcScoreFarkle(combs[k]).score }); } } } // Puanına göre sırala allCombos.sort(function (a, b) { return b.score - a.score; }); // Sıradan SONRA buda var MAX_COMBOS = 10; allCombos = allCombos.slice(0, MAX_COMBOS); // Derin inceleme için tekrar kısalt allCombos = allCombos.slice(0, MAX_COMBO_EVAL); lastCombos = allCombos; /* --- 3) Tam olasılık tablosuna dayalı yardımcılar --- */ function bustProbability(remaining) { if (remaining === 0) { return 0; } // 0 zar → 6 zarla atacağız, bust yok return exactFarkleTable[remaining].bust; } /* 4) Skor çıktığında beklenen puan */ function expectedScore(remaining) { if (remaining === 0) { remaining = 6; } return exactFarkleTable[remaining].expected; } // 5) Derinlikli arama (lookahead): Tüm olası hamleleri ve devamlarını simüle et function perfectPlayLookahead(diceVals, tempScore, depth, maxDepth, alpha) { var localAlpha = alpha; // çağıranın en iyi skoru if (perfNow() - _startTime > MAX_TIME_MS) { return { expected: tempScore, bust: 1 }; // acele karar } // ---- Memo anahtarı ---- var key = depth + "|" + tempScore + "|" + diceVals.sort().join(''); if (_memo[key]) { return _memo[key]; } // -- Çok küçük farklarda derin aranmasın -- if (maxDepth > 6 && TARGET_SCORE - (scores[NPC] + tempScore) < 2000) { maxDepth = 6; // sonlara doğru 6 ply yeter } // Taban durum: derinlik bitti veya hiç hamle yoksa if (diceVals.length === 0) { return { expected: tempScore, bust: 0 }; // 0 zar → 6 zar atılacak } // Tüm geçerli kombinasyonları bul var combos = []; for (var i = 1; i <= diceVals.length; i++) { var combs = getCombinations(diceVals, i); for (var j = 0; j < combs.length; j++) { var comb = combs[j]; if (isValidSelection(comb)) { var scoreObj = calcScoreFarkle(comb); combos.push({ combo: comb, score: scoreObj.score, used: scoreObj.used }); } } } combos.sort(function (a, b) { return b.score - a.score; }); if (combos.length === 0) { // Hiç hamle yoksa iflas return { expected: 0, bust: 1 }; } var bestExpected = -Infinity; var bestBust = 1; for (var c = 0; c < combos.length; c++) { var combo = combos[c]; var leftDice = diceVals.length - combo.combo.length; // Eğer tüm zarlar seçildiyse, 6 zarla tekrar atılır var nextDice = leftDice === 0 ? 6 : leftDice; // Simülasyon: devam etsem ortalama ne olur? var simAvg = expectedScore(nextDice); var simBust = bustProbability(nextDice); // Bir sonraki adımda lookahead var look = { expected: 0, bust: 1 }; if (depth < maxDepth) { // Tüm olası zar atışlarını dene (her zar için 1-6) var totalExp = 0, totalBust = 0, tries = 0; var all = getSymmetricRolls(nextDice); for (var r = 0; r < all.length; r++) { var res = perfectPlayLookahead(all[r], tempScore + combo.score, depth + 1, maxDepth, bestExpected); totalExp += res.expected; totalBust += res.bust; } tries = all.length; look.expected = totalExp / tries; look.bust = totalBust / tries; } else { look.expected = simAvg + tempScore + combo.score; look.bust = simBust; } // Bank ve devam seçeneklerini karşılaştır var bankScore = tempScore + combo.score; var continueScore = look.expected * (1 - look.bust); var expected = Math.max(bankScore, continueScore); if (expected > bestExpected) { bestExpected = expected; localAlpha = Math.max(localAlpha, bestExpected); bestBust = look.bust; if (bestExpected >= alpha) { break; } // ---- PRUNE ---- } if (localAlpha > _INFTY / 2) { break; } // pratikte yeterli } return _memo[key] = { expected: bestExpected, bust: bestBust }; } // 6) Kombinasyonlardan en iyi hamleyi seç (lookahead ile) var leftDiceGlobal = dice.length; // kaç zar elimde var hot = leftDiceGlobal === 0; // tüm zarlar seçildiyse var maxLookaheadDepth = depthFor(leftDiceGlobal, hot); // ── yalnızca *bir* defa MCTS yap ── var mctsResult = mctsDecision(makeState(), MCTS_BUDGET_MS); var bestChildMCTS = mctsResult.move; var mctsEV = mctsResult.W / Math.max(1, mctsResult.N); for (var c = 0; c < allCombos.length; c++) { var combo = allCombos[c]; var leftDice = dice.length - combo.combo.length; var nextDice = leftDice === 0 ? 6 : leftDice; // Lookahead ile devam etsem ne olur? var look = perfectPlayLookahead(function () { // Kalan zarları bul var valsCopy = vals.slice(); for (var i = 0; i < combo.combo.length; i++) { var idx = valsCopy.indexOf(combo.combo[i]); if (idx !== -1) { valsCopy.splice(idx, 1); } } return leftDice === 0 ? [1, 2, 3, 4, 5, 6] : valsCopy; }(), tempScores[NPC] + combo.score, 1, maxLookaheadDepth, -Infinity); // Bank ve devam seçeneklerini karşılaştır var bankScore = tempScores[NPC] + combo.score; var continueScore = look.expected * (1 - look.bust); var currentState = makeState(); // Karmaya kat: var expected = 0.8 * Math.max(bankScore, continueScore) + 0.2 * mctsEV; // hot-dice banklama engeli bu döngüde kullanılamaz, // perfectPlayLookahead içinde değerlendiriliyor. // Eğer skorla kazanıyorsa, bank zorunlu var willBank = scores[NPC] + tempScores[NPC] + combo.score >= TARGET_SCORE; // Dinamik risk: riskTolerance arttıkça daha riskli hamleler seçilir // saf beklenen kazanç = bank / devam olasılık-ağır basanı var riskScore = expected * (1 - look.bust * (1 - riskTolerance)); if (willBank) { riskScore += BANK_BIAS; } if (riskScore > bestMoveScore) { bestMoveScore = riskScore; bestMove = combo; bestMoveBank = bestChildMCTS.type === 'BANK' || willBank || bankScore >= continueScore; } } /* ------------------------------------------------- * ZORUNLU RİSK KURALLARIMIZ * ------------------------------------------------ */ if (bestMove && bestMove.combo) { var singleSmall = bestMove.combo.length === 1 && (bestMove.combo[0] === 1 || bestMove.combo[0] === 5); var hasBetterThanSingle = allCombos.some(function (c) { return c.score > (bestMove.combo[0] === 1 ? 100 : 50); }); var rolledSixAtStart = dice.length === 6; var hotDice = bestMove.combo.length === dice.length; if (singleSmall && !hasBetterThanSingle && rolledSixAtStart || hotDice) { bestMoveBank = false; // ► MUTLAKA DEVAM ET } } /* >>>>>> 4-5-6 zar için ‘tek 1/5 seç + devam’ kuralı <<<<<< */ if (dice.length >= 4 && dice.length <= 6) { // Elimizde 1 var mı, yoksa 5 var mı? var forcedVal = vals.includes(1) ? 1 : vals.includes(5) ? 5 : null; if (forcedVal !== null) { var forcedScore = forcedVal === 1 ? 100 : 50; /* Eğer zaten bundan yüksek puanlı bir hamle seçmediysek veya yüksek puanlı hamle olsa bile sizin kuralınız mutlaka uygulanacaksa aşağıdaki satırı yorumsuz bırakın. */ if (!bestMove || bestMove.score <= forcedScore) { bestMove = { combo: [forcedVal], // tek zar tut score: forcedScore }; bestMoveBank = false; // kesinlikle DEVAM bestMoveScore = forcedScore; } } } /* <<<<<< sonu */ /* progressive deepening: eğer yeterli zaman varsa derinliği +1 yapıp geri dön */ if (perfNow() - _startTime + TIME_BUDGET < HARD_LIMIT && maxLookaheadDepth < 8) { maxLookaheadDepth++; // artık 8 ply tavan return true; } // 7) Hiç puan yoksa bust if (!bestMove || bestMove.score === 0) { LK.effects.flashScreen(0xff0000, 1200); var iflasTxt = new Text2('İflas!', { size: 180, fill: '#fff' }); iflasTxt.anchor.set(0.5, 0.5); iflasTxt.x = W / 2; iflasTxt.y = H / 2; iflasTxt.alpha = 1; game.addChild(iflasTxt); var iflasRakipSesi = LK.getSound && LK.getSound('iflasRakipSesi'); if (iflasRakipSesi && iflasRakipSesi.play) { iflasRakipSesi.play(); } LK.setTimeout(function () { tween(iflasTxt, { alpha: 0 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { if (iflasTxt && iflasTxt.parent) { iflasTxt.parent.removeChild(iflasTxt); } tempScores[NPC] = selectedScores[NPC] = turnScore = 0; updateHUD(); endTurn(); } }); }, 1000); return; } return decideAndAct(); } function decideAndAct() { // Hiç geçerli hamle yoksa veya hesaplama yetişmediyse => sıra geçsin if (!bestMove || !bestMove.combo || !bestMove.combo.length) { tempScores[NPC] = selectedScores[NPC] = 0; // güvenli sıfırlama updateHUD(); endTurn(); return; } /* ------------------------------ * HOT-DICE ≠ OYUNU BİTİREN SKOR * ------------------------------ */ var willWin = scores[NPC] // şu ana kadar banklı skor + tempScores[NPC] // tur içi birikmiş skor + bestMove.score // seçtiği kombinasyon skoru >= TARGET_SCORE; // → hedefi geçiyor mu? if (bestMove.combo.length === dice.length // hot-dice && !willWin) { // ama bitirmiyorsa bestMoveBank = false; // ► mutlaka devam et } // 8) Zarları adım adım seçip (görsel animasyon) /* Eğer banklanacaksa, önce en yüksek skorlu komboyu seç */ if (bestMoveBank) { if (lastCombos && lastCombos.length) { bestMove = lastCombos.reduce(function (max, c) { return c.score > max.score ? c : max; }, bestMove); } } /* npcSelectOrder dizisini hazırla */ var npcSelectOrder = []; var used = []; // Defensive: check bestMove and bestMove.combo before iterating if (bestMove && bestMove.combo && Array.isArray(bestMove.combo)) { for (var i = 0; i < dice.length; i++) { var v = dice[i].value; for (var j = 0; j < bestMove.combo.length; j++) { if (!used[j] && bestMove.combo[j] === v) { npcSelectOrder.push(i); used[j] = true; break; } } } } var idxSel = 0; function npcSelectNextDie() { if (idxSel < npcSelectOrder.length) { var _LK$getSound4; var idx = npcSelectOrder[idxSel++]; var snd = dice[idx].selected ? 'zarBirakmaSesi' : 'zarSecmeSesi'; dice[idx].selected = true; // güvenli: hep seç (_LK$getSound4 = LK.getSound(snd)) === null || _LK$getSound4 === void 0 || _LK$getSound4.play(); updateDicePositions(); updateHUD(); LK.setTimeout(npcSelectNextDie, NPC_STEP_DELAY); return; } // Tüm zarlar seçildi → bank / devam kararı LK.setTimeout(applyFinalDecision, NPC_STEP_DELAY); } npcSelectNextDie(); } /* --- Kazanan ekranı --- */ function showWinner() { gameOver = true; // Kazanma oranı güncellemesi var totalGames = typeof storage.totalGames === "number" ? storage.totalGames : 0; var winGames = typeof storage.winGames === "number" ? storage.winGames : 0; totalGames += 1; if (current === PLAYER) { winGames += 1; } storage.totalGames = totalGames; storage.winGames = winGames; // HUD'daki oranı ve oyun sayısını hemen güncelle if (window.winRateTxt) { var winRateStr = "% ?"; if (totalGames > 0) { var rate = Math.round(winGames / totalGames * 100); winRateStr = "%" + rate; } var oyunSayisiStr = totalGames > 0 ? totalGames : "?"; window.winRateTxt.setText("Kazanma Oranım: " + winRateStr + " | Oynanan Oyun Sayısı: " + oyunSayisiStr); } var winnerText = current === PLAYER ? 'Kazandın!' : 'Kaybettin...'; showGameOverScreen(winnerText); } /* --- Buton Olayları --- */ rollBtn.down = function () { var _LK$getSound3; if (gameOver || current !== PLAYER) { return; } // sesi zaten burada çalıyoruz (_LK$getSound3 = LK.getSound('tutVeDevamEtSesi')) === null || _LK$getSound3 === void 0 || _LK$getSound3.play(); /* Zarları döndür, ses O Z A M A N oynatıldı—o yüzden 2. parametre: false */ animateRoll(keepAndContinue, false); }; bankBtn.down = function () { if (current === PLAYER) { var tutTuruSonlandirSesi = LK.getSound && LK.getSound('tutVeTuruSonlandirSesi'); if (tutTuruSonlandirSesi && tutTuruSonlandirSesi.play) { tutTuruSonlandirSesi.play(); } keepAndEndTurn(); } }; // PAS GEÇ butonu olayı passBtn.down = function () { if (current === PLAYER && !gameOver) { var pasButonuSesi = LK.getSound && LK.getSound('pasButonuSesi'); if (pasButonuSesi && pasButonuSesi.play) { pasButonuSesi.play(); } // Sıramı pas geç, turu rakibe geçir tempScores[current] = 0; selectedScores[current] = 0; turnScore = 0; updateHUD(); endTurn(); } }; /* --- Başlat --- */ function startGame() { scores = [0, 0]; tempScores = [0, 0]; selectedScores = [0, 0]; turnScore = 0; turnNumber = 1; current = PLAYER; gameOver = false; // Set oyunEkraniArkaplani as background if (game._oyunBg) { game._oyunBg.destroy(); game._oyunBg = null; } var oyunBg = LK.getAsset('oyunEkraniArkaplani', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: W, height: H }); game.addChildAt(oyunBg, 0); game._oyunBg = oyunBg; // Müzik sadece loading ekranı kalkınca başlatılacak, burada tekrar başlatılmıyor resetDice(6); updateHUD(); var ilkSenBasliyorsunSesi = LK.getSound && LK.getSound('ilkSenBasliyorsunSesi'); if (ilkSenBasliyorsunSesi && ilkSenBasliyorsunSesi.play) { ilkSenBasliyorsunSesi.play(); } animateRoll(); } // --- Ana Menü ve Oyun Sonu Ekranları --- var mainMenuContainer = null; var gameOverContainer = null; // Oyuncu adı global değişkeni var playerName = storage.playerName || null; // Oyuncu adı giriş penceresi için referanslar var playerNameDialog = null; // Hesabı Sıfırla onay penceresi function showResetAccountDialog() { // Önce varsa eski dialog'u kaldır if (playerNameDialog) { playerNameDialog.destroy(); playerNameDialog = null; } playerNameDialog = new Container(); playerNameDialog.width = 900; playerNameDialog.height = 600; playerNameDialog.x = W / 2 - 450; playerNameDialog.y = H / 2 - 300; // Arkaplan kutusu var bg = LK.getAsset('loadingBgRed', { anchorX: 0, anchorY: 0, color: 0x222222 }); playerNameDialog.addChild(bg); // Başlık var info = new Text2("Bu işlemden emin misin?", { size: 54, fill: 0xFFE066 }); info.anchor.set(0.5, 0); info.x = 450; info.y = 60; playerNameDialog.addChild(info); // Input kutusu var resetInput = new Text2("", { size: 80, fill: "#fff", background: "#444", padding: 24 }); resetInput.anchor.set(0.5, 0); resetInput.x = 450; resetInput.y = info.y + 70; resetInput.interactive = true; resetInput.text = ""; playerNameDialog.addChild(resetInput); // Sanal klavye (yalnızca harfler, DEL, GERİ, TAMAM) var isCaps = true; var maxLen = 8; var keyboardRows = [["E", "V", "E", "T"], ["DEL", "GERI", "TAMAM"]]; var keyW = 170, keyH = 170, keyGap = 20; var kbStartX = (900 - (4 * keyW + 3 * keyGap)) / 2; var kbStartY = 320; for (var row = 0; row < keyboardRows.length; row++) { for (var col = 0; col < keyboardRows[row].length; col++) { (function (row, col) { var k = keyboardRows[row][col]; var isWideKey = k === "GERI" || k === "TAMAM"; var thisKeyW = isWideKey ? 360 : keyW; var thisKeyH = keyH; var keyBtn = new Container(); keyBtn.attachAsset('klavyeTusuGorseli', { anchorX: 0.5, anchorY: 0.5, width: thisKeyW, height: thisKeyH }); var labelText = ""; if (k === "DEL") { labelText = "Sil"; } else if (k === "GERI") { labelText = "Geri"; } else if (k === "TAMAM") { labelText = "Tamam"; } else { labelText = k; } var keyTxt = new Text2(labelText, { size: 40, fill: "#fff" }); keyBtn.label = keyTxt; keyTxt.anchor.set(0.5, 0.5); keyBtn.addChild(keyTxt); // Konumlandırma var sumW = 0; if (row === 1) { for (var c = 0; c < col; c++) { sumW += keyboardRows[row][c] === "GERI" || keyboardRows[row][c] === "TAMAM" ? 360 + keyGap : keyW + keyGap; } keyBtn.x = kbStartX + sumW + thisKeyW / 2; } else { keyBtn.x = kbStartX + col * (keyW + keyGap) + thisKeyW / 2; } keyBtn.y = kbStartY + row * (keyH + keyGap) + thisKeyH / 2; keyBtn.interactive = true; keyBtn.down = function () { var klavyeTusunaBasmaSesi = LK.getSound && LK.getSound('klavyeTusunaBasmaSesi'); if (klavyeTusunaBasmaSesi && klavyeTusunaBasmaSesi.play) { klavyeTusunaBasmaSesi.play(); } // DEL tuşu if (k === "DEL") { resetInput.text = resetInput.text.slice(0, -1); resetInput.setText(resetInput.text); return; } // GERİ tuşu if (k === "GERI") { if (playerNameDialog) { playerNameDialog.destroy(); playerNameDialog = null; } return; } // TAMAM tuşu if (k === "TAMAM") { var val = resetInput.text.trim(); if (val.toLocaleUpperCase('tr-TR') === "EVET") { // Tüm verileri sıfırla storage.playerName = null; storage.totalGames = 0; storage.winGames = 0; storage.zarStats = Object.assign({}, defaultZarStats); if (window.zarStatsTxt) { window.zarStatsTxt.setText("zar2 = 0 zar3 = 0 zar4 = 0 zar5 = 0 zar6 = 0 zar1 = 0 zarJoker = 0"); } // Diğer olası veriler de burada sıfırlanabilir // Dialog'u kapat if (playerNameDialog) { playerNameDialog.destroy(); playerNameDialog = null; } // Ana menüyü güncelle (isim sorulacak) showMainMenu(); } return; } // Harf tuşları if (resetInput.text.length < maxLen && k.length === 1) { var harf = isCaps ? k.toLocaleUpperCase('tr-TR') : k.toLocaleLowerCase('tr-TR'); resetInput.text += harf; resetInput.setText(resetInput.text); } }; keyBtn._isKeyBtn = true; keyBtn._row = row; keyBtn._col = col; playerNameDialog.addChild(keyBtn); })(row, col); } } // Ekrana ekle game.addChild(playerNameDialog); } // Oyuncu adı giriş penceresini göster function showPlayerNameDialog(onComplete) { if (playerNameDialog) { playerNameDialog.destroy(); playerNameDialog = null; } playerNameDialog = new Container(); playerNameDialog.width = 900; playerNameDialog.height = 600; playerNameDialog.x = W / 2 - 450; playerNameDialog.y = H / 2 - 300; // Arkaplan kutusu var bg = LK.getAsset('loadingBgRed', { anchorX: 0, anchorY: 0, color: 0x222222 }); playerNameDialog.addChild(bg); // Başlık var title = new Text2("Oyuncu Adı", { size: 80, fill: "#fff" }); title.anchor.set(0.5, 0); title.x = 450; title.y = 40; playerNameDialog.addChild(title); // Oyuncu adı başlığının hemen altına, 15px aşağıda gösterilecek şekilde input kutusu ve yazı var playerNameInput = new Text2("", { size: 80, fill: "#fff", background: "#444", padding: 24 }); playerNameInput.anchor.set(0.5, 0); // Oyuncu Adı başlığının y'si 40, yüksekliği 80. 15px aşağıda olacak şekilde: playerNameInput.x = 450; playerNameInput.y = 40 + 80 + 15; // title.y + title.height + 15 playerNameInput.interactive = true; playerNameInput.text = ""; playerNameDialog.addChild(playerNameInput); // --- Sanal klavye: çoklu karakter, boşluk, caps lock desteği ve özel arkaplanlar --- var isCaps = true; var maxLen = 24; // Klavye tuşları ve ek fonksiyon tuşları aynı sırada olacak şekilde var keyboardRows = [["A", "B", "C", "Ç", "D", "E", "F", "G", "Ğ"], ["H", "I", "İ", "J", "K", "L", "M", "N", "O"], ["Ö", "P", "R", "S", "Ş", "T", "U", "Ü", "V"], ["Y", "Z", "SPACE", "DEL", "CAPS", "GERI", "TAMAM"]]; // Klavye arkaplanı var keyboardBg = LK.getAsset('klavyeArkaplani', { anchorX: 0, anchorY: 0, x: -415, y: 300 }); playerNameDialog.addChild(keyboardBg); // Tuş boyutları ve konumlar var keyW = 170, keyH = 170, keyGap = 20; var keysPerRow = keyboardRows[0].length; // 9 var kbStartX = (900 - (keysPerRow * keyW + (keysPerRow - 1) * keyGap)) / 2; var kbStartY = 320; // Tuşları sırayla çiz for (var row = 0; row < keyboardRows.length; row++) { for (var col = 0; col < keyboardRows[row].length; col++) { (function (row, col) { var k = keyboardRows[row][col]; // GERI ve TAMAM tuşları için özel boyut var isWideKey = k === "GERI" || k === "TAMAM"; var thisKeyW = isWideKey ? 360 : keyW; var thisKeyH = keyH; var keyBtn = new Container(); // Tüm tuşlar aynı görselde, sadece label farklı keyBtn.attachAsset('klavyeTusuGorseli', { anchorX: 0.5, anchorY: 0.5, width: thisKeyW, height: thisKeyH }); // Label var labelText = ""; if (k === "SPACE") { labelText = "Boşluk"; } else if (k === "DEL") { labelText = "Sil"; } else if (k === "CAPS") { labelText = isCaps ? "Caps: A" : "Caps: a"; } else if (k === "GERI") { labelText = "Geri"; } else if (k === "TAMAM") { labelText = "Tamam"; } else { labelText = isCaps ? k : k.toLowerCase(); } var keyTxt = new Text2(labelText, { size: 40, fill: "#fff" }); keyBtn.label = keyTxt; // <-- etiket referansı keyTxt.anchor.set(0.5, 0.5); keyBtn.addChild(keyTxt); // Konumlandırma // GERI ve TAMAM tuşları için x pozisyonunu ayarlamak gerekiyor var xOffset = 0; if (isWideKey) { // GERI ve TAMAM tuşları son satırda, 3. ve 4. sütun // 4. satırda: ["Y", "Z", "SPACE", "DEL", "CAPS", "GERI", "TAMAM"] // GERI: col==5, TAMAM: col==6 // 5. ve 6. tuşun başı, önceki tuşların toplam genişliği + gap'leri kadar sağda olmalı // 0-4 arası normal, 5 ve 6 geniş // 0-4: keyW, 5-6: 260 // GERI'nin x'i: kbStartX + (5 * (keyW + keyGap)) + 260/2 + (col-5)*((260-keyW)/2) // TAMAM'ın x'i: kbStartX + (5 * (keyW + keyGap)) + (1 * (260 + keyGap)) + 260/2 // Hesaplamayı daha basit yapalım: // Her tuşun başı: kbStartX + sum(width+gap) + width/2 // 0-4: keyW, 5-6: 260 var sumW = 0; for (var c = 0; c < col; c++) { if (keyboardRows[row][c] === "GERI" || keyboardRows[row][c] === "TAMAM") { sumW += 360 + keyGap; } else { sumW += keyW + keyGap; } } keyBtn.x = kbStartX + sumW + thisKeyW / 2; } else { keyBtn.x = kbStartX + col * (keyW + keyGap) + thisKeyW / 2; } keyBtn.y = kbStartY + row * (keyH + keyGap) + thisKeyH / 2; keyBtn.interactive = true; keyBtn.down = function () { var klavyeTusunaBasmaSesi = LK.getSound && LK.getSound('klavyeTusunaBasmaSesi'); if (klavyeTusunaBasmaSesi && klavyeTusunaBasmaSesi.play) { klavyeTusunaBasmaSesi.play(); } // DEL tuşu if (k === "DEL") { playerNameInput.text = playerNameInput.text.slice(0, -1); playerNameInput.setText(playerNameInput.text); return; } // SPACE tuşu if (k === "SPACE") { if (playerNameInput.text.length < maxLen) { playerNameInput.text = playerNameInput.text + " "; playerNameInput.setText(playerNameInput.text); } return; } // CAPS tuşu if (k === "CAPS") { isCaps = !isCaps; playerNameDialog.children.forEach(function (btn) { if (!btn._isKeyBtn || !btn.label) { return; } var code = keyboardRows[btn._row][btn._col]; if (code === "CAPS") { btn.label.setText(isCaps ? "Caps: A" : "Caps: a"); } else if (code.length === 1) { // Harf tuşu btn.label.setText(isCaps ? code.toLocaleUpperCase("tr-TR") : code.toLocaleLowerCase("tr-TR")); } }); return; } // GERİ tuşu if (k === "GERI") { if (playerNameDialog) { playerNameDialog.destroy(); playerNameDialog = null; } return; } // TAMAM tuşu if (k === "TAMAM") { var name = playerNameInput.text.trim(); if (name.length < 2) { return; } playerName = name; storage.playerName = name; if (playerNameDialog) { playerNameDialog.destroy(); playerNameDialog = null; } if (typeof onComplete === "function") { onComplete(); } return; } // Harf tuşları if (playerNameInput.text.length < maxLen && k.length === 1) { var harf = isCaps ? k.toLocaleUpperCase('tr-TR') // büyük harf modu : k.toLocaleLowerCase('tr-TR'); // küçük harf modu playerNameInput.text += harf; playerNameInput.setText(playerNameInput.text); } }; // Tuşun tipini sakla (caps güncellemesi için) keyBtn._isKeyBtn = true; keyBtn._row = row; keyBtn._col = col; playerNameDialog.addChild(keyBtn); })(row, col); } } // Ekrana ekle game.addChild(playerNameDialog); } // Ana Menü Ekranını Göster function showMainMenu() { // Temizle if (mainMenuContainer) { mainMenuContainer.destroy(); mainMenuContainer = null; } if (gameOverContainer) { gameOverContainer.destroy(); gameOverContainer = null; } // Oyun alanını temizle if (diceGroup) { diceGroup.destroy(); diceGroup = null; } if (selectedDiceGroup) { selectedDiceGroup.destroy(); selectedDiceGroup = null; } dice = []; selectedDiceIdx = []; // Skor tablosunu gizle for (var i = 0; i < scoreTableRows.length; i++) { if (scoreTableRows[i]) { scoreTableRows[i].visible = false; } } if (turnTxt) { turnTxt.visible = false; } // Ana menüde puan tablosu ve açıklama görünmesin if (window._farkleScoreTable) { window._farkleScoreTable.visible = false; } if (window._farkleScoreInfoTxt) { window._farkleScoreInfoTxt.visible = false; } // Zar istatistik satırını gizle (sadece oyun ekranında görünür) if (window.zarStatsRow) { window.zarStatsRow.visible = false; } // --- Kazanma Oranı etiketi --- if (!window.winRateTxt) { // daha önce hiç oluşturulmamışsa burada yarat window.winRateTxt = new Text2("", { size: 48, fill: '#ffe066', fontWeight: 'bold' }); window.winRateTxt.anchor.set(0.5, 0); LK.gui.top.addChild(window.winRateTxt); } // değerleri güncelle ve görünür yap var totalGames = typeof storage.totalGames === "number" ? storage.totalGames : 0; var winGames = typeof storage.winGames === "number" ? storage.winGames : 0; var oran = totalGames > 0 ? Math.round(winGames / totalGames * 100) + "%" : "% ?"; var oyunStr = totalGames > 0 ? totalGames : "?"; window.winRateTxt.setText("Kazanma Oranı: " + oran + " | Oynanan Oyun Sayısı: " + oyunStr); window.winRateTxt.x = 0; window.winRateTxt.y = 20; window.winRateTxt.visible = true; // Butonları pasifleştir rollBtn.visible = false; bankBtn.visible = false; if (typeof passBtn !== "undefined") { passBtn.visible = false; } // Remove oyun ekranı arkaplanı if exists if (game._oyunBg) { game._oyunBg.destroy(); game._oyunBg = null; } // Ana Menü Container mainMenuContainer = new Container(); mainMenuContainer.width = W; mainMenuContainer.height = H; // Arkaplan (anaMenuEkraniArkaplani) var bg = LK.getAsset('anaMenuEkraniArkaplani', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: W, height: H }); mainMenuContainer.addChild(bg); // Müzik sadece loading ekranı kalkınca başlatılacak, burada tekrar başlatılmıyor // "Oyunu Başlat" Butonu var startBtn = new Container(); startBtn.attachAsset('oyunuBaslatButonuGorseli', { anchorX: 0.5, anchorY: 0.5 }); var startTxt = new Text2('Oyunu Başlat', { size: 124, fill: '#fff' }); startTxt.anchor.set(0.5, 0.5); startTxt.y = 40; startBtn.addChild(startTxt); startBtn.x = W / 2; startBtn.y = H / 2 - 230; startBtn.interactive = true; startBtn.down = function () { var oyunuBaslatButonuSesi = LK.getSound && LK.getSound('oyunuBaslatButonuSesi'); if (oyunuBaslatButonuSesi && oyunuBaslatButonuSesi.play) { oyunuBaslatButonuSesi.play(); } // Oyuncu adı yoksa önce sor, varsa direkt başlat if (!storage.playerName) { showPlayerNameDialog(function () { hideMainMenu(); startGame(); }); } else { playerName = storage.playerName; hideMainMenu(); startGame(); } }; mainMenuContainer.addChild(startBtn); // --- HESABI SIFIRLA BUTONU --- // Buton görseli ve metni var sifirlaBtn = new Container(); sifirlaBtn.attachAsset('tamamButonuGorseli', { anchorX: 0.5, anchorY: 0.5 }); var sifirlaTxt = new Text2('Hesabı Sıfırla', { size: 124, fill: '#fff' }); sifirlaTxt.anchor.set(0.5, 0.5); sifirlaTxt.y = 40; sifirlaBtn.addChild(sifirlaTxt); // Konum: Başlat butonunun hemen altında, arada 80px boşluk sifirlaBtn.x = W / 2; sifirlaBtn.y = H / 2 + 230; sifirlaBtn.interactive = true; sifirlaBtn.down = function () { var hesabiSifirlaButonuSesi = LK.getSound && LK.getSound('hesabiSifirlaButonuSesi'); if (hesabiSifirlaButonuSesi && hesabiSifirlaButonuSesi.play) { hesabiSifirlaButonuSesi.play(); } // Sıfırlama onay penceresini göster showResetAccountDialog(); }; mainMenuContainer.addChild(sifirlaBtn); game.addChild(mainMenuContainer); // --- Instagram ve Erken Erişim Yazıları (sadece ana menüde) --- if (!window.instaText) { // Instagram: ugurcanyardim_ var instaText = new Text2("Instagram: ugurcanyardim_", { size: 64, fill: 0xFF0000, // kırmızı fontWeight: "bold" }); instaText.anchor.set(0.5, 0); window.instaText = instaText; // Beta text var betaText = new Text2("Erken Erişim", { size: 64, fill: 0xFFE066, // sarı fontWeight: "bold" }); betaText.anchor.set(0, 0); // left-top window.betaText = betaText; } // Pozisyonları langBtn'a göre ayarla // langBtn yoksa, referans noktası olarak startBtn kullan var refBtn = typeof langBtn !== "undefined" && langBtn ? langBtn : startBtn; window.instaText.x = refBtn.x - 586; window.instaText.y = refBtn.y + 1500; window.betaText.x = window.instaText.x + 1194; window.betaText.y = window.instaText.y; // Sadece ana menüde göster window.instaText.visible = true; window.betaText.visible = true; mainMenuContainer.addChild(window.instaText); mainMenuContainer.addChild(window.betaText); // --- Konfeti efektini ve parçacıklarını temizle (ana menüye dönünce) --- if (confettiInterval) { LK.clearInterval(confettiInterval); confettiInterval = null; } for (var i = 0; i < confettiParticles.length; i++) { if (confettiParticles[i] && confettiParticles[i].parent) { confettiParticles[i].parent.removeChild(confettiParticles[i]); } } confettiParticles = []; // Olası update fonksiyonunu da temizle if (gameOverContainer && gameOverContainer.update) { gameOverContainer.update = null; } } // Ana Menü Ekranını Gizle function hideMainMenu() { if (mainMenuContainer) { mainMenuContainer.destroy(); mainMenuContainer = null; } // Skor tablosunu göster for (var i = 0; i < scoreTableRows.length; i++) { if (scoreTableRows[i]) { scoreTableRows[i].visible = true; } } if (turnTxt) { turnTxt.visible = true; } // Oyun ekranına dönünce puan tablosunu ve açıklamayı tekrar göster if (window._farkleScoreTable) { window._farkleScoreTable.visible = true; } if (window._farkleScoreInfoTxt) { window._farkleScoreInfoTxt.visible = true; } // Butonları göster rollBtn.visible = true; bankBtn.visible = true; if (typeof passBtn !== "undefined") { passBtn.visible = true; } // Zar istatistik satırını göster (sadece oyun ekranında) if (window.zarStatsRow) { window.zarStatsRow.visible = true; } } // Oyun Sonu Ekranını Göster function showGameOverScreen(winnerText) { // Temizle if (gameOverContainer) { gameOverContainer.destroy(); gameOverContainer = null; } if (mainMenuContainer) { mainMenuContainer.destroy(); mainMenuContainer = null; } // Oyun alanını temizle if (diceGroup) { diceGroup.destroy(); diceGroup = null; } if (selectedDiceGroup) { selectedDiceGroup.destroy(); selectedDiceGroup = null; } dice = []; selectedDiceIdx = []; // Skor tablosunu gizle for (var i = 0; i < scoreTableRows.length; i++) { if (scoreTableRows[i]) { scoreTableRows[i].visible = false; } } if (turnTxt) { turnTxt.visible = false; } // Oyun sonu ekranında puan tablosu görünmesin, sadece oyun ekranında görünsün if (window._farkleScoreTable) { window._farkleScoreTable.visible = false; } if (window._farkleScoreInfoTxt) { window._farkleScoreInfoTxt.visible = false; } // Zar istatistik satırını gizle (sadece oyun ekranında görünür) if (window.zarStatsRow) { window.zarStatsRow.visible = false; } // Kazanma oranı ve oyun sayısı yazısı oyun sonu ekranında da görünür olsun if (window.winRateTxt) { window.winRateTxt.visible = true; window.winRateTxt.x = 0; window.winRateTxt.y = 20; } // Butonları pasifleştir rollBtn.visible = false; bankBtn.visible = false; if (typeof passBtn !== "undefined") { passBtn.visible = false; } // Remove oyun ekranı arkaplanı if exists if (game._oyunBg) { game._oyunBg.destroy(); game._oyunBg = null; } // Oyun Sonu Container gameOverContainer = new Container(); gameOverContainer.width = W; gameOverContainer.height = H; // Arkaplan (oyunSonuEkraniArkaplani) var bg = LK.getAsset('oyunSonuEkraniArkaplani', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: W, height: H }); gameOverContainer.addChild(bg); // Oyun sonunda kazanan/kaybeden SFX çal if (typeof current !== "undefined") { if (current === PLAYER) { var senKazandinSesi = LK.getSound && LK.getSound('senKazandinSesi'); if (senKazandinSesi && senKazandinSesi.play) { senKazandinSesi.play(); } } else if (current === NPC) { var kaybettinSesi = LK.getSound && LK.getSound('kaybettinSesi'); if (kaybettinSesi && kaybettinSesi.play) { kaybettinSesi.play(); } } } // Müzik sadece loading ekranı kalkınca başlatılacak, burada tekrar başlatılmıyor // Kazanan/Kaybeden Metni var resultTxt = new Text2(winnerText || 'Oyun Bitti', { size: 140, fill: '#fff' }); resultTxt.anchor.set(0.5, 0.5); resultTxt.x = W / 2; resultTxt.y = H / 2 - 200; gameOverContainer.addChild(resultTxt); // "Ana Menüye Dön" Butonu var menuBtn = new Container(); menuBtn.attachAsset('anaMenuyeDonButonuGorseli', { anchorX: 0.5, anchorY: 0.5 }); var menuTxt = new Text2('Ana Menüye Dön', { size: 60, fill: '#fff' }); menuTxt.anchor.set(0.5, 0.5); menuTxt.y = 25; menuBtn.addChild(menuTxt); menuBtn.x = W / 2; menuBtn.y = H / 2; menuBtn.interactive = true; menuBtn.down = function () { var anaMenuyeDonButonuSesi = LK.getSound && LK.getSound('anaMenuyeDonButonuSesi'); if (anaMenuyeDonButonuSesi && anaMenuyeDonButonuSesi.play) { anaMenuyeDonButonuSesi.play(); } hideGameOverScreen(); showMainMenu(); }; gameOverContainer.addChild(menuBtn); game.addChild(gameOverContainer); // --- Konfeti Efekti: Sadece oyuncu kazandıysa başlat --- if (typeof current !== "undefined" && current === PLAYER) { // Önce varsa eski konfeti efektini temizle if (confettiInterval) { LK.clearInterval(confettiInterval); confettiInterval = null; } // Tüm eski konfeti parçacıklarını temizle for (var i = 0; i < confettiParticles.length; i++) { if (confettiParticles[i] && confettiParticles[i].parent) { confettiParticles[i].parent.removeChild(confettiParticles[i]); } } confettiParticles = []; // Konfeti efektini başlat: her 80ms'de yeni parçacık ekle confettiInterval = LK.setInterval(function () { // Her seferinde 2-4 yeni konfeti ekle var count = 2 + Math.floor(Math.random() * 3); for (var j = 0; j < count; j++) { var confetti = new ConfettiParticle(); gameOverContainer.addChild(confetti); confettiParticles.push(confetti); } }, 80); // Konfeti parçacıklarını güncellemek için gameOverContainer.update fonksiyonu gameOverContainer.update = function () { // Tüm konfeti parçacıklarını güncelle for (var i = confettiParticles.length - 1; i >= 0; i--) { var c = confettiParticles[i]; if (c && !c._destroyed && typeof c.update === "function") { c.update(); } // Yok edilenleri diziden çıkar if (c._destroyed) { confettiParticles.splice(i, 1); } } }; } else { // Kazanmadıysan konfeti efektini başlatma, varsa temizle if (confettiInterval) { LK.clearInterval(confettiInterval); confettiInterval = null; } for (var i = 0; i < confettiParticles.length; i++) { if (confettiParticles[i] && confettiParticles[i].parent) { confettiParticles[i].parent.removeChild(confettiParticles[i]); } } confettiParticles = []; if (gameOverContainer.update) { gameOverContainer.update = null; } } } // Oyun Sonu Ekranını Gizle function hideGameOverScreen() { if (gameOverContainer) { gameOverContainer.destroy(); gameOverContainer = null; } // Skor tablosunu göster for (var i = 0; i < scoreTableRows.length; i++) { if (scoreTableRows[i]) { scoreTableRows[i].visible = true; } } if (turnTxt) { turnTxt.visible = true; } // Oyun ekranına dönünce puan tablosunu tekrar göster if (window._farkleScoreTable) { window._farkleScoreTable.visible = true; } if (window._farkleScoreInfoTxt) { window._farkleScoreInfoTxt.visible = true; } // Butonları göster rollBtn.visible = true; bankBtn.visible = true; if (typeof passBtn !== "undefined") { passBtn.visible = true; } // Zar istatistik satırını göster (sadece oyun ekranında) if (window.zarStatsRow) { window.zarStatsRow.visible = true; } } // --- Kazanan ekranı override --- // Yükleme ekranı için sınıf ve gösterme fonksiyonu var loadingContainer = null; var loadingTimeout = null; var yuklemeEkraniSesi = null; var yuklemeEkraniSesiFinished = false; // Tween plugin import // Yükleme ekranını göster function showLoadingScreen() { // First, create the main menu in the background so resources can load showMainMenu(); // Hide winRateTxt during loading screen if (window.winRateTxt) { window.winRateTxt.visible = false; } // Müzik yükleme ekranında başlamasın, sadece loading kalkınca başlatacağız // (Burada playMusic çağrısı kaldırıldı) // --- Yükleme ekranı sesi kontrolü --- yuklemeEkraniSesi = LK.getSound && LK.getSound('yuklemeEkraniSesi'); var yuklemeSesi = yuklemeEkraniSesi; var yuklemeSesiBitti = false; /* ----------------------------------------------------------- Sesin bitişini yakala. Howler ⇒ 'end' event’i gönderir. Ses hiç çalmazsa en fazla 8 sn içinde yine kapatırız. ----------------------------------------------------------- */ var SES_EMNIYET_MS = 8000; var BITTIKTAN_SONRA_MS = 1000; // Remove loading screen only when oyunEkraniMuzigi actually starts playing (onPlay event) function removeLoadingScreenAndPlayMusic() { // Remove loading overlay if (loadingContainer !== null) { loadingContainer.destroy(); loadingContainer = null; } if (window.winRateTxt) { window.winRateTxt.visible = true; } // --- Enable Oyunu Başlat and Hesabı Sıfırla buttons after loading --- if (typeof mainMenuContainer !== "undefined" && mainMenuContainer !== null) { for (var i = 0; i < mainMenuContainer.children.length; i++) { var btn = mainMenuContainer.children[i]; if (btn && btn.down) { var hasStart = false, hasReset = false; for (var j = 0; j < btn.children.length; j++) { var child = btn.children[j]; if (child && child.setText && typeof child.text === "string") { if (child.text.indexOf("Oyunu Başlat") !== -1) hasStart = true; if (child.text.indexOf("Hesabı Sıfırla") !== -1) hasReset = true; } } if (hasStart || hasReset) { btn.interactive = true; btn.alpha = 1; } } } } } // Yeni: Müzik başlatma ve loading kaldırma, müzik başlama anında function playMusicAndRemoveLoadingScreen() { // Müzik başlat, loading ekranını ancak müzik çalmaya BAŞLADIĞINDA kaldır LK.playMusic('oyunEkraniMuzigi', { loop: true, onPlay: function onPlay() { removeLoadingScreenAndPlayMusic(); } }); } // Ses bitince 5sn bekle, sonra müziği başlat (ve loading ekranı müzik başlarken kalkacak) function sesSonrasiKapat() { if (yuklemeSesiBitti) { return; } yuklemeSesiBitti = true; yuklemeEkraniSesiFinished = true; /* +5 sn kuralı */ LK.setTimeout(playMusicAndRemoveLoadingScreen, 5000); } // --- YENİ: Yükleme ekranı sesi tam olarak bitene kadar loading ekranda kalacak, asla yarıda kesilmeyecek --- // Sadece bir kez çalacak ve bitişini bekleyecek if (yuklemeSesi && yuklemeSesi.play) { // Sesi baştan başlat, çalıyor ise durdur if (typeof yuklemeSesi.stop === "function") { yuklemeSesi.stop(); } /** oynat ve id'sini al (Howler geri id döndürür) */ var id = yuklemeSesi.play(); // Sadece bir kere dinle, bitince sesSonrasiKapat çağrılır if (typeof yuklemeSesi.once === "function") { yuklemeSesi.once('end', sesSonrasiKapat, id); } else if (typeof yuklemeSesi.on === "function") { yuklemeSesi.on('end', sesSonrasiKapat); } } // Ses hiç çalmaz ya da hata olursa azami 8 sn sonra kapat LK.setTimeout(sesSonrasiKapat, SES_EMNIYET_MS); // Temizle if (loadingContainer) { loadingContainer.destroy(); loadingContainer = null; } loadingContainer = new Container(); loadingContainer.width = W; loadingContainer.height = H; // Yükleme ekranı arkaplanı var bg = LK.getAsset('yuklemeEkraniArkaplani', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: W, height: H }); loadingContainer.addChild(bg); // Novatek logosu (ortada üstte) var logo = LK.getAsset('novatekLogosu', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1050 }); loadingContainer.addChild(logo); // "Loading..." yazısı var loadingTxt = new Text2('Yükleniyor...', { size: 90, fill: '#fff' }); loadingTxt.anchor.set(0.5, 0.5); loadingTxt.x = 1024; loadingTxt.y = 1366; loadingContainer.addChild(loadingTxt); // Alt açıklama yazısı var infoTxt = new Text2("En iyi oyun deneyimi için lütfen oyunun grafik ve ses kaynakları tamamen yüklenene kadar bekleyin. Unutmayın ki insanların %99'u büyük kazanamadan hemen önce oyunu bırakıyor! %1'e girebilecek misiniz?", { size: 36, fill: '#fff', wordWrap: true, wordWrapWidth: 1800, align: 'center' }); infoTxt.anchor.set(0.5, 0); infoTxt.x = 1024; infoTxt.y = 1460; loadingContainer.addChild(infoTxt); // Dönen yükleme çubuğu var spinner = LK.getAsset('yuklemeCubugu', { anchorX: 0.5, anchorY: 0.5, x: W / 2, y: infoTxt.y + infoTxt.height + 120 }); loadingContainer.addChild(spinner); // Spinner animasyonu (dönme) spinner.rotation = 0; var _spinTween = function spinTween() { tween(spinner, { rotation: spinner.rotation + Math.PI * 2 }, { duration: 1200, easing: tween.linear, onFinish: _spinTween }); }; _spinTween(); // Add loading screen on top of main menu game.addChild(loadingContainer); // --- Disable Oyunu Başlat and Hesabı Sıfırla buttons during loading --- if (typeof mainMenuContainer !== "undefined" && mainMenuContainer !== null) { // Find Oyunu Başlat and Hesabı Sıfırla buttons by traversing children for (var i = 0; i < mainMenuContainer.children.length; i++) { var btn = mainMenuContainer.children[i]; if (btn && btn.down && btn.visible !== false) { // Try to match by text var hasStart = false, hasReset = false; for (var j = 0; j < btn.children.length; j++) { var child = btn.children[j]; if (child && child.setText && typeof child.text === "string") { if (child.text.indexOf("Oyunu Başlat") !== -1) hasStart = true; if (child.text.indexOf("Hesabı Sıfırla") !== -1) hasReset = true; } } if (hasStart || hasReset) { btn.interactive = false; btn.alpha = 0.5; } } } } // Remove polling and delayed removal logic, always remove loading screen when oyunEkraniMuzigi starts // (All logic now handled in sesSonrasiKapat and removeLoadingScreenAndPlayMusic) } // Oyun başında yükleme ekranını göster showLoadingScreen(); /* --- Responsive HUD --- */ if (!window._frvr_gui_resize_hooked) { window._frvr_gui_resize_hooked = true; LK.on('resize', function () { var centerX = W / 2; // 2048/2 = 1024, ekranın tam ortası for (var i = 0; i < scoreTableRows.length; i++) { if (scoreTableRows[i]) { scoreTableRows[i].x = centerX; } } if (turnTxt) { turnTxt.x = centerX; } }); } // --- Fix: Define npcBustFlow for NPC bust handling --- function npcBustFlow() { // Show red flash and 'İflas!' text for NPC bust LK.effects.flashScreen(0xff0000, 1200); var iflasTxt = new Text2('İflas!', { size: 180, fill: '#fff' }); iflasTxt.anchor.set(0.5, 0.5); iflasTxt.x = W / 2; iflasTxt.y = H / 2; iflasTxt.alpha = 1; game.addChild(iflasTxt); // Play NPC bust sound var iflasRakipSesi = LK.getSound && LK.getSound('iflasRakipSesi'); if (iflasRakipSesi && iflasRakipSesi.play) { iflasRakipSesi.play(); } LK.setTimeout(function () { tween(iflasTxt, { alpha: 0 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { if (iflasTxt && iflasTxt.parent) { iflasTxt.parent.removeChild(iflasTxt); } tempScores[NPC] = selectedScores[NPC] = turnScore = 0; updateHUD(); endTurn(); } }); }, 1000); }
===================================================================
--- original.js
+++ change.js
@@ -3302,8 +3302,29 @@
}
if (window.winRateTxt) {
window.winRateTxt.visible = true;
}
+ // --- Enable Oyunu Başlat and Hesabı Sıfırla buttons after loading ---
+ if (typeof mainMenuContainer !== "undefined" && mainMenuContainer !== null) {
+ for (var i = 0; i < mainMenuContainer.children.length; i++) {
+ var btn = mainMenuContainer.children[i];
+ if (btn && btn.down) {
+ var hasStart = false,
+ hasReset = false;
+ for (var j = 0; j < btn.children.length; j++) {
+ var child = btn.children[j];
+ if (child && child.setText && typeof child.text === "string") {
+ if (child.text.indexOf("Oyunu Başlat") !== -1) hasStart = true;
+ if (child.text.indexOf("Hesabı Sıfırla") !== -1) hasReset = true;
+ }
+ }
+ if (hasStart || hasReset) {
+ btn.interactive = true;
+ btn.alpha = 1;
+ }
+ }
+ }
+ }
}
// Yeni: Müzik başlatma ve loading kaldırma, müzik başlama anında
function playMusicAndRemoveLoadingScreen() {
// Müzik başlat, loading ekranını ancak müzik çalmaya BAŞLADIĞINDA kaldır
@@ -3410,8 +3431,31 @@
};
_spinTween();
// Add loading screen on top of main menu
game.addChild(loadingContainer);
+ // --- Disable Oyunu Başlat and Hesabı Sıfırla buttons during loading ---
+ if (typeof mainMenuContainer !== "undefined" && mainMenuContainer !== null) {
+ // Find Oyunu Başlat and Hesabı Sıfırla buttons by traversing children
+ for (var i = 0; i < mainMenuContainer.children.length; i++) {
+ var btn = mainMenuContainer.children[i];
+ if (btn && btn.down && btn.visible !== false) {
+ // Try to match by text
+ var hasStart = false,
+ hasReset = false;
+ for (var j = 0; j < btn.children.length; j++) {
+ var child = btn.children[j];
+ if (child && child.setText && typeof child.text === "string") {
+ if (child.text.indexOf("Oyunu Başlat") !== -1) hasStart = true;
+ if (child.text.indexOf("Hesabı Sıfırla") !== -1) hasReset = true;
+ }
+ }
+ if (hasStart || hasReset) {
+ btn.interactive = false;
+ btn.alpha = 0.5;
+ }
+ }
+ }
+ }
// Remove polling and delayed removal logic, always remove loading screen when oyunEkraniMuzigi starts
// (All logic now handled in sesSonrasiKapat and removeLoadingScreenAndPlayMusic)
}
// Oyun başında yükleme ekranını göster
Yeşil casino masa arkaplanı. Dikdörtgen.
Casino oyunum için buton olarak kullanmalık dikdörtgen (köşeleri yumuşatılmış, edge). Yazısız.. In-Game asset. 2d. High contrast. No shadows
Bu sefer zar 1 yerine zar 2 olsun. Delik kırmızı değil siyah olsun.
Zar 2 değil 3 olsun.
Zar 4 olsun. Deliklerinin içi dolu siyah olsun.
Zar 2 değil, zar 5 olsun.
Zar 6 olsun. İçindeki deliklerin içi dolu siyah olsun.
Zar 6 değil, zar joker olsun. Yani zarın üstünde joker sembolü olsun.
Zar 4 değil, zar 1 olsun. İçi siyah değil kırmızı olsun.
Casino tarzında yatay dikdörtgen (köşeleri yumuşatılmış, edge). İçi sarı, dışında kırmızı şerit var. Sol üst köşesinde bir çift zar var. Yazısız.. In-Game asset. 2d. High contrast. No shadows. Casino
oyunEkraniMuzigi
Music
zarBirakmaSesi
Sound effect
zarSecmeSesi
Sound effect
tutVeDevamEtSesi
Sound effect
tutVeTuruSonlandirSesi
Sound effect
ilkSenBasliyorsunSesi
Sound effect
rakibinSirasiSesi
Sound effect
siraSendeSesi
Sound effect
iflasBenSesi
Sound effect
iflasRakipSesi
Sound effect
senKazandinSesi
Sound effect
kaybettinSesi
Sound effect
pasButonuSesi
Sound effect
klavyeTusunaBasmaSesi
Sound effect
oyunuBaslatButonuSesi
Sound effect
anaMenuyeDonButonuSesi
Sound effect
hesabiSifirlaButonuSesi
Sound effect
yuklemeEkraniSesi
Sound effect
ilkRakipBasliyorSesi
Sound effect