User prompt
Oyunu hiç bozmadan, dokunmadan hataları düzelt.
User prompt
Bu modumu seçmek istiyorsun diye uyarı veren yerde Evet veya Hayır'a tıklayınca tepki vermiyor.
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'yesBtn.down = function (x, y, obj) {' Line Number: 397
User prompt
Bir Zorluk Modu Seçince Bu Zorluk Modunu Mu Seçmek İstiyorsun Diye Uyarsın
User prompt
kolay, normal ve zor düğmelerin altında blok olsun renk yanıyor
User prompt
Oyun oynarken bazı yerlere tıklayınca algılamıyor, bir boşluğa tıklayınca hepsini algılasın. Hataları düzelt.
User prompt
kolay, normal ve zor modlar arasında boşluklar olsun yoksa yanlışla yanlış modu seçebiliyoruz
User prompt
Yapay zeka modunda bazı yerleri kendimiz koyamıyoruz.
User prompt
yapay zeka modunu seçince kolay, normal ve zor modlar olsun
User prompt
Yapay ZK'ya daha çok taktik öğret.
User prompt
Algılama sistemini ve hataları düzelt.
User prompt
Yapay Zeka Hep Aynı Hareketleri Yapmasın Aynı Stratejileri Yapmasın Farklı Farklı
User prompt
Yapay zeka, bizim tıkladığımız yere göre hep belirli yerlere tıklıyor. Farklı yerlere ama mantıklı, saçma yerlere dokunmadan düzgün bir oyun oynasın. Bizim tıkladığımız yere göre belirli yerlere dokunmadan.
User prompt
Bazən bizim tıxladığımız yerə yapay zeka qoyuyor. O yüzden bizim tıxladığımız yerlə yapay zekanın tıxladığı yeri algıla və doğru konumlandır.
User prompt
Bazen oyundaki düğmeler çalışmıyor.
User prompt
Oyun oynarken arada küçük donmalar kesilmeler oluyor.
User prompt
oyuna ilk girdiğimizde küçük bir donma yaşanıyor o yüzden tıklayamıyoruz
User prompt
Oyun bazen yapay zekayı ilk oyuncu olarak görüyor bu yüzden ilk yapay zekanın tıklamasına izin veriyor ama ilk bizim tıklamamız gerekiyor.
User prompt
oyuna girdiğimizde menüde yani oyunun içerisinde tıklamak için bekleme süresi aşırı uzun yapay zekayı etkilemeyecek şekilde
User prompt
ekrana çok hızlı tıklayarak yapay zekanın yapay zekayı da kontrol edebiliyoruz yapay zekanın yerine bir yere bir şey koyabiliyoruz
User prompt
kazandıktan sonra çıkan çizgi oyunu baştan başlatsak bile duruyor
User prompt
oyunda fark ettiğin hataları düzelt
User prompt
çizgileri eşit karelere böl ve 9 boşluk olsun yani oyunu bozmadan çizgileri eşite böl
User prompt
Oyundan herhangi bir şey çıkarmadan hataları düzelt.
User prompt
çıkış tuşunu biraz büyüt ve biraz daha sağa çek
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Cell = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.value = 0; // 0 = empty, 1 = X (blue), 2 = O (red)
var cellBg = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.01 // Make almost invisible but still interactive
});
// Make the entire cell area interactive
self.interactive = true;
self.hitArea = new Rectangle(-290, -290, 580, 580);
self.marker = null;
// Add hover effect to show clickable area
self.move = function (x, y, obj) {
if (!gameReady || gameOver || self.value !== 0 || gameMode === 'menu') return;
if (isAIMode && currentPlayer !== 1) return;
cellBg.alpha = 0.2; // Show cell is hoverable
};
// Reset hover effect when mouse leaves
self.up = function (x, y, obj) {
if (self.value === 0) {
cellBg.alpha = 0.01; // Reset to almost invisible
}
};
self.placeMarker = function (type) {
if (self.value !== 0) return false;
self.value = type;
if (type === 1) {
// Blue X
self.marker = self.attachAsset('xMarker', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
} else {
// Red O
self.marker = self.attachAsset('oMarker', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
LK.getSound('place').play();
return true;
};
self.down = function (x, y, obj) {
// Basic validation checks
if (!gameReady || gameOver || gameMode === 'menu') return;
if (self.value !== 0) return; // Cell already occupied
// In AI mode, only allow player clicks during player's turn (currentPlayer === 1)
if (isAIMode && currentPlayer !== 1) return;
if (aiProcessing) return; // Prevent clicks while AI is processing
// Immediately place the marker for the player
if (self.placeMarker(currentPlayer)) {
checkWin();
if (!gameOver) {
if (isAIMode && currentPlayer === 1) {
// AI mode - player played, now AI plays
currentPlayer = 2;
updateTurnDisplay();
// Add a flag to prevent AI from moving while processing
aiProcessing = true;
LK.setTimeout(function () {
aiProcessing = false;
makeAIMove();
}, 100); // Small delay to ensure UI updates
} else if (isAIMode && currentPlayer === 2) {
// This shouldn't happen in AI mode since AI doesn't click
currentPlayer = 1;
updateTurnDisplay();
} else {
// Two player mode - switch players normally
currentPlayer = currentPlayer === 1 ? 2 : 1;
updateTurnDisplay();
}
}
}
};
return self;
});
var WinLine = Container.expand(function () {
var self = Container.call(this);
self.line = self.attachAsset('winLine', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0
});
self.showWinLine = function (startX, startY, endX, endY, color) {
var deltaX = endX - startX;
var deltaY = endY - startY;
var angle = Math.atan2(deltaY, deltaX);
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
self.x = startX + deltaX / 2;
self.y = startY + deltaY / 2;
self.line.rotation = angle;
self.line.tint = color;
self.line.width = distance;
tween(self.line, {
alpha: 1,
scaleX: 1
}, {
duration: 500,
easing: tween.easeOut
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var grid = [];
var currentPlayer = 1; // 1 = Blue X, 2 = Red O
var gameOver = false;
var winLine = null;
var gameMode = 'menu'; // 'menu', 'ai', 'twoPlayer', 'difficulty'
var isAIMode = false;
var aiDifficulty = 'normal'; // 'easy', 'normal', 'hard'
var aiProcessing = false; // Flag to prevent AI from interfering with player moves
var currentLanguage = storage.language || 'tr'; // 'tr' for Turkish, 'en' for English
var selectedDifficulty = ''; // Store selected difficulty for confirmation
var languageTexts = {
tr: {
blueTurn: 'Sıra: Mavinin',
redTurn: 'Sıra: Kırmızının',
blueWin: 'MAVİ TAKIM KAZANDI!',
redWin: 'KIRMIZI TAKIM KAZANDI!',
draw: 'BERABERE!',
playAgain: 'Tekrar Oyna',
language: 'Türkçe',
vsAI: 'Yapay Zeka ile Oyna',
twoPlayer: 'İki Kişilik Oyna',
selectMode: 'Oyun Modunu Seçin',
back: '← Geri',
exit: 'Çıkış',
selectDifficulty: 'Zorluk Seçin',
easy: 'Kolay',
normal: 'Normal',
hard: 'Zor',
confirmEasy: 'Kolay modu seçmek istiyor musunuz?',
confirmNormal: 'Normal modu seçmek istiyor musunuz?',
confirmHard: 'Zor modu seçmek istiyor musunuz?',
yes: 'Evet',
no: 'Hayır'
},
en: {
blueTurn: 'Turn: Blue',
redTurn: 'Turn: Red',
blueWin: 'BLUE TEAM WON!',
redWin: 'RED TEAM WON!',
draw: 'DRAW!',
playAgain: 'Play Again',
language: 'English',
vsAI: 'Play vs AI',
twoPlayer: 'Two Player',
selectMode: 'Select Game Mode',
back: '← Back',
exit: 'Exit',
selectDifficulty: 'Select Difficulty',
easy: 'Easy',
normal: 'Normal',
hard: 'Hard',
confirmEasy: 'Do you want to select Easy mode?',
confirmNormal: 'Do you want to select Normal mode?',
confirmHard: 'Do you want to select Hard mode?',
yes: 'Yes',
no: 'No'
}
};
// Game setup
var gameBoard = game.addChild(new Container());
gameBoard.x = 2048 / 2;
gameBoard.y = 2732 / 2;
gameBoard.scaleX = 1.2;
gameBoard.scaleY = 1.2;
gameBoard.alpha = 0; // Hidden initially
// Create background
var background = gameBoard.attachAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Create grid lines
var verticalLine1 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
height: 1800
});
var verticalLine2 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
height: 1800
});
var horizontalLine1 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
y: -300,
width: 1800,
height: 8
});
var horizontalLine2 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
y: 300,
width: 1800,
height: 8
});
// Create cells
for (var row = 0; row < 3; row++) {
grid[row] = [];
for (var col = 0; col < 3; col++) {
var cell = gameBoard.addChild(new Cell(row, col));
cell.x = (col - 1) * 600;
cell.y = (row - 1) * 600;
grid[row][col] = cell;
}
}
// UI Elements
var blueTurnText = new Text2(languageTexts[currentLanguage].blueTurn, {
size: 120,
fill: 0x00AAFF
});
blueTurnText.anchor.set(0.5, 0);
LK.gui.top.addChild(blueTurnText);
blueTurnText.y = 150;
var redTurnText = new Text2(languageTexts[currentLanguage].redTurn, {
size: 120,
fill: 0xff0000
});
redTurnText.anchor.set(0.5, 0);
LK.gui.top.addChild(redTurnText);
redTurnText.y = 150;
var languageBtn = new Text2(languageTexts[currentLanguage === 'tr' ? 'en' : 'tr'].language, {
size: 60,
fill: 0xFFFFFF
});
languageBtn.anchor.set(0.5, 0);
LK.gui.top.addChild(languageBtn);
languageBtn.y = 80;
var statusText = new Text2('', {
size: 100,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(statusText);
statusText.y = 400;
var playAgainBtn = new Text2(languageTexts[currentLanguage].playAgain, {
size: 80,
fill: 0xFFFFFF
});
playAgainBtn.anchor.set(0.5, 0.5);
LK.gui.center.addChild(playAgainBtn);
playAgainBtn.y = 550;
playAgainBtn.alpha = 0;
// Menu UI elements
var menuTitle = new Text2(languageTexts[currentLanguage].selectMode, {
size: 120,
fill: 0xFFFFFF
});
menuTitle.anchor.set(0.5, 0.5);
LK.gui.center.addChild(menuTitle);
menuTitle.y = -200;
// AI Difficulty selection elements
var difficultyTitle = new Text2(languageTexts[currentLanguage].selectDifficulty, {
size: 100,
fill: 0xFFFFFF
});
difficultyTitle.anchor.set(0.5, 0.5);
LK.gui.center.addChild(difficultyTitle);
difficultyTitle.y = -200;
difficultyTitle.alpha = 0;
// Create background blocks for difficulty buttons
var easyBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0x44FF44,
alpha: 0.3
});
LK.gui.center.addChild(easyBlock);
easyBlock.y = -100;
easyBlock.alpha = 0;
var normalBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0xFFAA00,
alpha: 0.3
});
LK.gui.center.addChild(normalBlock);
normalBlock.y = 50;
normalBlock.alpha = 0;
var hardBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0xFF4444,
alpha: 0.3
});
LK.gui.center.addChild(hardBlock);
hardBlock.y = 200;
hardBlock.alpha = 0;
var easyBtn = new Text2(languageTexts[currentLanguage].easy, {
size: 90,
fill: 0x44FF44
});
easyBtn.anchor.set(0.5, 0.5);
LK.gui.center.addChild(easyBtn);
easyBtn.y = -100;
easyBtn.alpha = 0;
var normalBtn = new Text2(languageTexts[currentLanguage].normal, {
size: 90,
fill: 0xFFAA00
});
normalBtn.anchor.set(0.5, 0.5);
LK.gui.center.addChild(normalBtn);
normalBtn.y = 50;
normalBtn.alpha = 0;
var hardBtn = new Text2(languageTexts[currentLanguage].hard, {
size: 90,
fill: 0xFF4444
});
hardBtn.anchor.set(0.5, 0.5);
LK.gui.center.addChild(hardBtn);
hardBtn.y = 200;
hardBtn.alpha = 0;
// Confirmation dialog elements
var confirmationBg = LK.getAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5,
width: 1200,
height: 600,
tint: 0x000000,
alpha: 0.8
});
LK.gui.center.addChild(confirmationBg);
confirmationBg.alpha = 0;
var confirmationText = new Text2('', {
size: 80,
fill: 0xFFFFFF
});
confirmationText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(confirmationText);
confirmationText.y = -50;
confirmationText.alpha = 0;
var yesBtn = new Text2(languageTexts[currentLanguage].yes, {
size: 80,
fill: 0x44FF44
});
yesBtn.anchor.set(0.5, 0.5);
yesBtn.interactive = true;
LK.gui.center.addChild(yesBtn);
yesBtn.x = -150;
yesBtn.y = 100;
yesBtn.alpha = 0;
var noBtn = new Text2(languageTexts[currentLanguage].no, {
size: 80,
fill: 0xFF4444
});
noBtn.anchor.set(0.5, 0.5);
noBtn.interactive = true;
LK.gui.center.addChild(noBtn);
noBtn.x = 150;
noBtn.y = 100;
noBtn.alpha = 0;
// Add hit areas to confirmation dialog buttons
yesBtn.hitArea = new Rectangle(-100, -40, 200, 80);
noBtn.hitArea = new Rectangle(-100, -40, 200, 80);
// Confirmation dialog button handlers
yesBtn.down = function (x, y, obj) {
if (selectedDifficulty) {
aiDifficulty = selectedDifficulty;
hideConfirmationDialog();
startGame('ai');
}
};
noBtn.down = function (x, y, obj) {
hideConfirmationDialog();
};
// Add glowing animation to blocks
function animateDifficultyBlocks() {
tween(easyBlock, {
alpha: 0.5
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
tween(normalBlock, {
alpha: 0.5
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true,
delay: 333
});
tween(hardBlock, {
alpha: 0.5
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true,
delay: 666
});
}
function showConfirmationDialog(difficulty) {
selectedDifficulty = difficulty;
gameMode = 'confirmation';
var confirmText = '';
if (difficulty === 'easy') {
confirmText = languageTexts[currentLanguage].confirmEasy;
} else if (difficulty === 'normal') {
confirmText = languageTexts[currentLanguage].confirmNormal;
} else if (difficulty === 'hard') {
confirmText = languageTexts[currentLanguage].confirmHard;
}
confirmationText.setText(confirmText);
// Show confirmation elements
tween(confirmationBg, {
alpha: 0.8
}, {
duration: 200
});
tween(confirmationText, {
alpha: 1
}, {
duration: 200
});
tween(yesBtn, {
alpha: 1
}, {
duration: 200
});
tween(noBtn, {
alpha: 1
}, {
duration: 200
});
}
function hideConfirmationDialog() {
gameMode = 'difficulty';
selectedDifficulty = '';
// Hide confirmation elements
tween(confirmationBg, {
alpha: 0
}, {
duration: 200
});
tween(confirmationText, {
alpha: 0
}, {
duration: 200
});
tween(yesBtn, {
alpha: 0
}, {
duration: 200
});
tween(noBtn, {
alpha: 0
}, {
duration: 200
});
}
var vsAIBtn = new Text2(languageTexts[currentLanguage].vsAI, {
size: 100,
fill: 0x00AAFF
});
vsAIBtn.anchor.set(0.5, 0.5);
LK.gui.center.addChild(vsAIBtn);
vsAIBtn.y = 0;
var twoPlayerBtn = new Text2(languageTexts[currentLanguage].twoPlayer, {
size: 100,
fill: 0xFF4444
});
twoPlayerBtn.anchor.set(0.5, 0.5);
LK.gui.center.addChild(twoPlayerBtn);
twoPlayerBtn.y = 150;
var backBtn = new Text2(languageTexts[currentLanguage].back, {
size: 80,
fill: 0xFFFFFF
});
backBtn.anchor.set(0.5, 0.5);
LK.gui.center.addChild(backBtn);
backBtn.x = -800;
backBtn.y = -300;
backBtn.alpha = 0;
var exitBtn = new Text2(languageTexts[currentLanguage].exit, {
size: 80,
fill: 0xFF0000
});
exitBtn.anchor.set(0.5, 0);
LK.gui.top.addChild(exitBtn);
exitBtn.y = 80;
exitBtn.x = 450;
exitBtn.alpha = 0;
// Language toggle functionality
languageBtn.down = function (x, y, obj) {
// Always allow language switching regardless of game state
currentLanguage = currentLanguage === 'tr' ? 'en' : 'tr';
storage.language = currentLanguage;
updateLanguageTexts();
};
// Menu button handlers
vsAIBtn.down = function (x, y, obj) {
if (gameMode === 'menu') {
showDifficultySelection();
}
};
twoPlayerBtn.down = function (x, y, obj) {
if (gameMode === 'menu') {
startGame('twoPlayer');
}
};
// Difficulty button handlers
easyBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('easy');
}
};
normalBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('normal');
}
};
hardBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('hard');
}
};
backBtn.down = function (x, y, obj) {
if (gameMode === 'confirmation') {
hideConfirmationDialog();
} else if (gameMode === 'difficulty') {
showMenu();
} else if (gameMode !== 'menu') {
resetGame();
showMenu();
}
};
exitBtn.down = function (x, y, obj) {
if (gameMode !== 'menu') {
resetGame();
showMenu();
}
};
function updateLanguageTexts() {
blueTurnText.setText(languageTexts[currentLanguage].blueTurn);
redTurnText.setText(languageTexts[currentLanguage].redTurn);
playAgainBtn.setText(languageTexts[currentLanguage].playAgain);
languageBtn.setText(languageTexts[currentLanguage === 'tr' ? 'en' : 'tr'].language);
menuTitle.setText(languageTexts[currentLanguage].selectMode);
vsAIBtn.setText(languageTexts[currentLanguage].vsAI);
twoPlayerBtn.setText(languageTexts[currentLanguage].twoPlayer);
backBtn.setText(languageTexts[currentLanguage].back);
exitBtn.setText(languageTexts[currentLanguage].exit);
difficultyTitle.setText(languageTexts[currentLanguage].selectDifficulty);
easyBtn.setText(languageTexts[currentLanguage].easy);
normalBtn.setText(languageTexts[currentLanguage].normal);
hardBtn.setText(languageTexts[currentLanguage].hard);
yesBtn.setText(languageTexts[currentLanguage].yes);
noBtn.setText(languageTexts[currentLanguage].no);
}
// Start in menu mode
showMenu();
function updateTurnDisplay() {
if (gameMode === 'menu' || gameOver) {
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
} else if (currentPlayer === 1) {
blueTurnText.alpha = 1;
redTurnText.alpha = 0;
} else {
blueTurnText.alpha = 0;
redTurnText.alpha = 1;
}
}
function showMenu() {
gameMode = 'menu';
gameBoard.alpha = 0;
menuTitle.alpha = 1;
vsAIBtn.alpha = 1;
twoPlayerBtn.alpha = 1;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
statusText.alpha = 0;
playAgainBtn.alpha = 0;
backBtn.alpha = 0;
exitBtn.alpha = 0;
// Hide difficulty selection
difficultyTitle.alpha = 0;
easyBtn.alpha = 0;
normalBtn.alpha = 0;
hardBtn.alpha = 0;
// Hide blocks
easyBlock.alpha = 0;
normalBlock.alpha = 0;
hardBlock.alpha = 0;
// Hide confirmation dialog
confirmationBg.alpha = 0;
confirmationText.alpha = 0;
yesBtn.alpha = 0;
noBtn.alpha = 0;
}
function showDifficultySelection() {
gameMode = 'difficulty';
// Hide main menu
menuTitle.alpha = 0;
vsAIBtn.alpha = 0;
twoPlayerBtn.alpha = 0;
// Show difficulty selection
difficultyTitle.alpha = 1;
easyBtn.alpha = 1;
normalBtn.alpha = 1;
hardBtn.alpha = 1;
backBtn.alpha = 1;
// Show and animate blocks
easyBlock.alpha = 0.3;
normalBlock.alpha = 0.3;
hardBlock.alpha = 0.3;
animateDifficultyBlocks();
}
function startGame(mode) {
gameMode = mode;
isAIMode = mode === 'ai';
gameBoard.alpha = 1;
menuTitle.alpha = 0;
vsAIBtn.alpha = 0;
twoPlayerBtn.alpha = 0;
// Hide difficulty selection
difficultyTitle.alpha = 0;
easyBtn.alpha = 0;
normalBtn.alpha = 0;
hardBtn.alpha = 0;
// Hide blocks
easyBlock.alpha = 0;
normalBlock.alpha = 0;
hardBlock.alpha = 0;
// Hide confirmation dialog
confirmationBg.alpha = 0;
confirmationText.alpha = 0;
yesBtn.alpha = 0;
noBtn.alpha = 0;
backBtn.alpha = 1;
exitBtn.alpha = 1;
// In AI mode, player (1) always starts first
if (isAIMode) {
currentPlayer = 1;
} else {
// In two player mode, random start
currentPlayer = Math.random() < 0.5 ? 1 : 2;
}
updateTurnDisplay();
}
function checkWin() {
var winner = 0;
var winPositions = [];
// Check rows
for (var row = 0; row < 3; row++) {
if (grid[row][0].value !== 0 && grid[row][0].value === grid[row][1].value && grid[row][1].value === grid[row][2].value) {
winner = grid[row][0].value;
winPositions = [{
row: row,
col: 0
}, {
row: row,
col: 1
}, {
row: row,
col: 2
}];
break;
}
}
// Check columns
if (winner === 0) {
for (var col = 0; col < 3; col++) {
if (grid[0][col].value !== 0 && grid[0][col].value === grid[1][col].value && grid[1][col].value === grid[2][col].value) {
winner = grid[0][col].value;
winPositions = [{
row: 0,
col: col
}, {
row: 1,
col: col
}, {
row: 2,
col: col
}];
break;
}
}
}
// Check diagonals
if (winner === 0) {
if (grid[0][0].value !== 0 && grid[0][0].value === grid[1][1].value && grid[1][1].value === grid[2][2].value) {
winner = grid[0][0].value;
winPositions = [{
row: 0,
col: 0
}, {
row: 1,
col: 1
}, {
row: 2,
col: 2
}];
} else if (grid[0][2].value !== 0 && grid[0][2].value === grid[1][1].value && grid[1][1].value === grid[2][0].value) {
winner = grid[0][2].value;
winPositions = [{
row: 0,
col: 2
}, {
row: 1,
col: 1
}, {
row: 2,
col: 0
}];
}
}
if (winner !== 0) {
gameOver = true;
showWinner(winner, winPositions);
return;
}
// Check for draw
var isDraw = true;
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (grid[r][c].value === 0) {
isDraw = false;
break;
}
}
if (!isDraw) break;
}
if (isDraw) {
gameOver = true;
showDraw();
}
}
function showWinner(winner, positions) {
LK.getSound('win').play();
var winnerText = winner === 1 ? languageTexts[currentLanguage].blueWin : languageTexts[currentLanguage].redWin;
var winnerColor = 0x000000; // Black color
statusText.setText(winnerText);
statusText.fill = winnerColor;
statusText.alpha = 1;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
// Show win line
winLine = gameBoard.addChild(new WinLine());
var startPos = grid[positions[0].row][positions[0].col];
var endPos = grid[positions[2].row][positions[2].col];
var lineColor = winner === 1 ? 0x00aaff : 0xff4444;
winLine.showWinLine(startPos.x, startPos.y, endPos.x, endPos.y, lineColor);
// Show play again button
tween(playAgainBtn, {
alpha: 1
}, {
duration: 500
});
}
function showDraw() {
statusText.setText(languageTexts[currentLanguage].draw);
statusText.fill = 0x000000; // Black color
statusText.alpha = 1;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
// Show play again button
tween(playAgainBtn, {
alpha: 1
}, {
duration: 500
});
}
function makeAIMove() {
if (gameOver || currentPlayer !== 2 || aiProcessing) return;
// Variable thinking time based on difficulty
var minTime, maxTime;
if (aiDifficulty === 'easy') {
minTime = 100;
maxTime = 400;
} else if (aiDifficulty === 'normal') {
minTime = 200;
maxTime = 800;
} else {
// hard
minTime = 300;
maxTime = 1200;
}
var thinkingTime = minTime + Math.floor(Math.random() * (maxTime - minTime));
// Use setTimeout to yield frame and prevent blocking
LK.setTimeout(function () {
// Recheck game state after timeout
if (gameOver || currentPlayer !== 2 || aiProcessing) return;
// Simple AI strategy: try to win, block player, or play randomly
var bestMove = findBestMove();
if (bestMove && bestMove.value === 0) {
// Validate coordinates are within bounds
if (bestMove.row >= 0 && bestMove.row < 3 && bestMove.col >= 0 && bestMove.col < 3) {
// Double check the cell is still valid before AI places marker
var targetCell = grid[bestMove.row][bestMove.col];
if (targetCell && targetCell.value === 0) {
if (targetCell.placeMarker(2)) {
checkWin();
if (!gameOver) {
currentPlayer = 1;
updateTurnDisplay();
}
}
}
}
}
}, thinkingTime);
}
function findBestMove() {
var emptyCells = [];
var winningMoves = [];
var blockingMoves = [];
var forkMoves = [];
var blockForkMoves = [];
var cornerCells = [];
var edgeCells = [];
var validCells = [];
// Collect all valid empty cells
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = grid[row][col];
if (cell && cell.value === 0) {
emptyCells.push(cell);
validCells.push(cell);
// Categorize cell positions
if ((row === 0 || row === 2) && (col === 0 || col === 2)) {
cornerCells.push(cell);
} else if (row === 1 && col === 1) {
// Center cell - handled separately
} else {
edgeCells.push(cell);
}
}
}
}
// Early exit if no valid moves
if (validCells.length === 0) {
return null;
}
// Advanced tactic evaluation functions
function countWinningLines(row, col, player) {
var count = 0;
// Check row
var rowCount = 0;
for (var c = 0; c < 3; c++) {
if (grid[row][c].value === player || c === col) {
rowCount++;
} else if (grid[row][c].value !== 0) {
rowCount = -10; // Blocked
break;
}
}
if (rowCount === 3) count++;
// Check column
var colCount = 0;
for (var r = 0; r < 3; r++) {
if (grid[r][col].value === player || r === row) {
colCount++;
} else if (grid[r][col].value !== 0) {
colCount = -10; // Blocked
break;
}
}
if (colCount === 3) count++;
// Check diagonals
if (row === 0 && col === 0 || row === 1 && col === 1 || row === 2 && col === 2) {
var diagCount = 0;
for (var i = 0; i < 3; i++) {
if (grid[i][i].value === player || i === row && i === col) {
diagCount++;
} else if (grid[i][i].value !== 0) {
diagCount = -10; // Blocked
break;
}
}
if (diagCount === 3) count++;
}
if (row === 0 && col === 2 || row === 1 && col === 1 || row === 2 && col === 0) {
var antiDiagCount = 0;
for (var i = 0; i < 3; i++) {
if (grid[i][2 - i].value === player || i === row && 2 - i === col) {
antiDiagCount++;
} else if (grid[i][2 - i].value !== 0) {
antiDiagCount = -10; // Blocked
break;
}
}
if (antiDiagCount === 3) count++;
}
return count;
}
// Evaluate move position strength
function evaluatePosition(cell) {
var score = 0;
var row = cell.row;
var col = cell.col;
// Center is most valuable
if (row === 1 && col === 1) score += 4;
// Corners are second most valuable
else if ((row === 0 || row === 2) && (col === 0 || col === 2)) score += 3;
// Edges are least valuable
else score += 1;
// Check potential winning lines
var potentialLines = countWinningLines(row, col, 2);
score += potentialLines * 2;
return score;
}
// Check for forks (moves that create two winning threats)
function checkForFork(player) {
var forkCells = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = player;
var winningLineCount = 0;
// Count how many winning moves this creates
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = player;
if (checkWinCondition(player)) {
winningLineCount++;
}
testCell.value = 0;
}
}
cell.value = 0;
if (winningLineCount >= 2) {
forkCells.push(cell);
}
}
return forkCells;
}
// Adjust strategy based on difficulty
var aiPersonality = Math.floor(Math.random() * 8);
var randomnessFactor = Math.random();
// Difficulty-based mistake chances
var winMissChance, blockMissChance, strategyQuality;
if (aiDifficulty === 'easy') {
winMissChance = 0.15; // 15% chance to miss winning move
blockMissChance = 0.25; // 25% chance to miss blocking
strategyQuality = 0.3; // Low quality strategic moves
aiPersonality = Math.random() < 0.7 ? Math.floor(Math.random() * 3) : aiPersonality; // Favor simpler personalities
} else if (aiDifficulty === 'normal') {
winMissChance = 0.02; // 2% chance to miss winning move
blockMissChance = 0.05; // 5% chance to miss blocking
strategyQuality = 0.6; // Medium quality strategic moves
} else {
// hard
winMissChance = 0; // Never miss winning move
blockMissChance = 0.01; // 1% chance to miss blocking
strategyQuality = 0.9; // High quality strategic moves
aiPersonality = Math.random() < 0.7 ? Math.floor(Math.random() * 3) + 5 : aiPersonality; // Favor advanced personalities
}
// Priority 1: Check if AI can win immediately
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
if (checkWinCondition(2)) {
cell.value = 0;
winningMoves.push(cell);
}
cell.value = 0;
}
// Take winning move based on difficulty
if (winningMoves.length > 0 && randomnessFactor > winMissChance) {
return winningMoves[Math.floor(Math.random() * winningMoves.length)];
}
// Priority 2: Block player from winning
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 1;
if (checkWinCondition(1)) {
cell.value = 0;
blockingMoves.push(cell);
}
cell.value = 0;
}
// Block based on difficulty
if (blockingMoves.length > 0 && randomnessFactor > blockMissChance) {
return blockingMoves[Math.floor(Math.random() * blockingMoves.length)];
}
// Priority 3: Check for fork opportunities (based on difficulty)
if (aiDifficulty !== 'easy' && randomnessFactor < strategyQuality) {
forkMoves = checkForFork(2);
if (forkMoves.length > 0 && randomnessFactor > 1 - strategyQuality) {
return forkMoves[Math.floor(Math.random() * forkMoves.length)];
}
}
// Priority 4: Block player forks (based on difficulty)
if (aiDifficulty !== 'easy' && randomnessFactor < strategyQuality) {
blockForkMoves = checkForFork(1);
if (blockForkMoves.length > 0 && randomnessFactor > 1 - strategyQuality) {
// Force player to defend instead of creating fork
return blockForkMoves[Math.floor(Math.random() * blockForkMoves.length)];
}
}
// Priority 5: Advanced tactical personalities
var moveChoices = [];
var moveScores = [];
if (aiPersonality === 0) {
// Perfect player - uses optimal strategy
if (emptyCells.length === 9) {
// First move: prefer corner
moveChoices = cornerCells.slice();
} else if (emptyCells.length === 8) {
// Second move response
if (grid[1][1].value === 1) {
// Player took center, take corner
moveChoices = cornerCells.slice();
} else {
// Player took corner or edge, take center
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
}
}
} else {
// Evaluate all positions
for (var i = 0; i < emptyCells.length; i++) {
var score = evaluatePosition(emptyCells[i]);
moveScores.push({
cell: emptyCells[i],
score: score
});
}
moveScores.sort(function (a, b) {
return b.score - a.score;
});
// Take top scoring moves
var topScore = moveScores[0].score;
for (var i = 0; i < moveScores.length; i++) {
if (moveScores[i].score >= topScore - 1) {
moveChoices.push(moveScores[i].cell);
}
}
}
} else if (aiPersonality === 1) {
// Trap setter - tries to create winning patterns
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]); // Double weight
}
// Look for L-shaped patterns
if (grid[0][0].value === 2 && grid[2][2].value === 0 && !grid[2][2].isPlayerReserved) {
moveChoices.push(grid[2][2]);
}
if (grid[0][2].value === 2 && grid[2][0].value === 0 && !grid[2][0].isPlayerReserved) {
moveChoices.push(grid[2][0]);
}
// Add corners for trap potential
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
} else if (aiPersonality === 2) {
// Defensive player - blocks and controls center
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]); // Triple weight for center
}
// Prefer moves that block multiple lines
for (var i = 0; i < emptyCells.length; i++) {
var blockCount = countWinningLines(emptyCells[i].row, emptyCells[i].col, 1);
if (blockCount >= 2) {
moveChoices.push(emptyCells[i]);
}
}
if (moveChoices.length === 0 && cornerCells.length > 0) {
moveChoices = cornerCells.slice();
}
} else if (aiPersonality === 3) {
// Mirror player - plays symmetrically
var playerMoves = [];
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (grid[r][c].value === 1) {
playerMoves.push({
row: r,
col: c
});
}
}
}
if (playerMoves.length > 0) {
var lastMove = playerMoves[playerMoves.length - 1];
// Try to mirror across center
var mirrorRow = 2 - lastMove.row;
var mirrorCol = 2 - lastMove.col;
if (grid[mirrorRow][mirrorCol].value === 0 && !grid[mirrorRow][mirrorCol].isPlayerReserved) {
moveChoices.push(grid[mirrorRow][mirrorCol]);
moveChoices.push(grid[mirrorRow][mirrorCol]); // Double weight
}
}
// Add strategic positions
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices.push(cornerCells[Math.floor(Math.random() * cornerCells.length)]);
}
} else if (aiPersonality === 4) {
// Edge control player - unusual but effective
if (edgeCells.length > 0) {
// Prefer edges that connect to existing pieces
for (var i = 0; i < edgeCells.length; i++) {
var edge = edgeCells[i];
var adjacentAI = 0;
// Check adjacent cells
var checkPositions = [{
r: edge.row - 1,
c: edge.col
}, {
r: edge.row + 1,
c: edge.col
}, {
r: edge.row,
c: edge.col - 1
}, {
r: edge.row,
c: edge.col + 1
}];
for (var j = 0; j < checkPositions.length; j++) {
var pos = checkPositions[j];
if (pos.r >= 0 && pos.r < 3 && pos.c >= 0 && pos.c < 3) {
if (grid[pos.r][pos.c].value === 2) {
adjacentAI++;
}
}
}
if (adjacentAI > 0) {
moveChoices.push(edge);
moveChoices.push(edge); // Double weight for connected edges
}
}
if (moveChoices.length === 0) {
moveChoices = edgeCells.slice();
}
}
// Sometimes take center
if (Math.random() < 0.3 && grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
}
} else if (aiPersonality === 5) {
// Chaos player - creates complex board states
var complexityScore = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
// Calculate how many lines this move affects
var linesAffected = 0;
if (true) linesAffected++; // Row
if (true) linesAffected++; // Column
if (cell.row === cell.col || cell.row + cell.col === 2) {
linesAffected++; // Diagonal
}
complexityScore.push({
cell: cell,
complexity: linesAffected
});
}
// Prefer high complexity moves
complexityScore.sort(function (a, b) {
return b.complexity - a.complexity;
});
for (var i = 0; i < Math.min(3, complexityScore.length); i++) {
moveChoices.push(complexityScore[i].cell);
}
} else if (aiPersonality === 6) {
// Pattern player - follows specific winning patterns
var patterns = [
// Corner-opposite-corner
[{
r: 0,
c: 0
}, {
r: 2,
c: 2
}], [{
r: 0,
c: 2
}, {
r: 2,
c: 0
}],
// L-shapes
[{
r: 0,
c: 0
}, {
r: 0,
c: 2
}], [{
r: 0,
c: 0
}, {
r: 2,
c: 0
}], [{
r: 2,
c: 2
}, {
r: 2,
c: 0
}], [{
r: 2,
c: 2
}, {
r: 0,
c: 2
}]];
for (var p = 0; p < patterns.length; p++) {
var pattern = patterns[p];
var hasFirst = grid[pattern[0].r][pattern[0].c].value === 2;
var secondEmpty = grid[pattern[1].r][pattern[1].c].value === 0 && !grid[pattern[1].r][pattern[1].c].isPlayerReserved;
if (hasFirst && secondEmpty) {
moveChoices.push(grid[pattern[1].r][pattern[1].c]);
moveChoices.push(grid[pattern[1].r][pattern[1].c]); // Double weight
}
}
// Default to smart positions
if (moveChoices.length === 0) {
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
}
} else {
// Adaptive player - changes strategy based on game state
var gamePhase = 9 - emptyCells.length; // 0-8, higher = later
if (gamePhase <= 2) {
// Early game: control key positions
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
} else if (gamePhase <= 5) {
// Mid game: create threats
for (var i = 0; i < emptyCells.length; i++) {
var threatLevel = countWinningLines(emptyCells[i].row, emptyCells[i].col, 2);
if (threatLevel >= 1) {
moveChoices.push(emptyCells[i]);
if (threatLevel >= 2) {
moveChoices.push(emptyCells[i]); // Extra weight for multi-threats
}
}
}
} else {
// Late game: optimize winning chances
for (var i = 0; i < emptyCells.length; i++) {
moveChoices.push(emptyCells[i]);
}
}
}
// Add calculated randomness
if (Math.random() < 0.1) {
// 10% chance to add unexpected move
if (validCells.length > 0) {
var randomCell = validCells[Math.floor(Math.random() * validCells.length)];
moveChoices.push(randomCell);
}
}
// If we have strategic choices, pick from them
if (moveChoices.length > 0) {
// Sometimes pick the most frequent choice (if duplicates exist)
var choiceFrequency = {};
for (var i = 0; i < moveChoices.length; i++) {
var key = moveChoices[i].row + ',' + moveChoices[i].col;
choiceFrequency[key] = (choiceFrequency[key] || 0) + 1;
}
// Create weighted selection
var weightedChoices = [];
for (var i = 0; i < moveChoices.length; i++) {
weightedChoices.push(moveChoices[i]);
}
return weightedChoices[Math.floor(Math.random() * weightedChoices.length)];
}
// Easy mode: sometimes make random moves instead of strategic ones
if (aiDifficulty === 'easy' && Math.random() < 0.4) {
// 40% chance to make completely random move in easy mode
if (validCells.length > 0) {
return validCells[Math.floor(Math.random() * validCells.length)];
}
}
// Final fallback: intelligent selection
var fallbackChoices = [];
// Prioritize based on position value (less strategic in easy mode)
if (aiDifficulty !== 'easy' || Math.random() < 0.5) {
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
fallbackChoices.push(grid[1][1]);
}
}
if (cornerCells.length > 0 && (aiDifficulty !== 'easy' || Math.random() < 0.6)) {
fallbackChoices = fallbackChoices.concat(cornerCells);
}
if (edgeCells.length > 0 && (aiDifficulty === 'easy' || Math.random() < 0.3)) {
fallbackChoices.push(edgeCells[Math.floor(Math.random() * edgeCells.length)]);
}
if (fallbackChoices.length === 0) {
fallbackChoices = validCells;
}
if (fallbackChoices.length > 0) {
return fallbackChoices[Math.floor(Math.random() * fallbackChoices.length)];
}
return null;
}
function checkWinCondition(player) {
// Check rows
for (var row = 0; row < 3; row++) {
if (grid[row][0].value === player && grid[row][1].value === player && grid[row][2].value === player) {
return true;
}
}
// Check columns
for (var col = 0; col < 3; col++) {
if (grid[0][col].value === player && grid[1][col].value === player && grid[2][col].value === player) {
return true;
}
}
// Check diagonals
if (grid[0][0].value === player && grid[1][1].value === player && grid[2][2].value === player) {
return true;
}
if (grid[0][2].value === player && grid[1][1].value === player && grid[2][0].value === player) {
return true;
}
return false;
}
function resetGame() {
gameOver = false;
aiProcessing = false;
// Start according to game mode
if (gameMode === 'ai') {
currentPlayer = 1; // Player always starts in AI mode
isAIMode = true;
} else if (gameMode === 'twoPlayer') {
currentPlayer = Math.random() < 0.5 ? 1 : 2;
isAIMode = false;
} else {
// Menu mode
currentPlayer = 1;
isAIMode = false;
}
// Clear grid
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = grid[row][col];
cell.value = 0;
if (cell.marker) {
cell.marker.destroy();
cell.marker = null;
}
}
}
// Clear UI
statusText.setText('');
statusText.alpha = 0;
playAgainBtn.alpha = 0;
// Remove win line
if (winLine) {
// Reset line properties before destroying
winLine.line.alpha = 0;
winLine.line.scaleX = 0;
winLine.destroy();
winLine = null;
}
updateTurnDisplay();
}
// Save current version function
function saveCurrentVersion() {
storage.savedVersion = {
timestamp: Date.now(),
version: 'TicTacToe_TurkishEnglish_v1.0'
};
}
// Play again button handler
playAgainBtn.down = function (x, y, obj) {
if (gameOver) {
resetGame();
}
};
// Save the current version on game initialization
saveCurrentVersion();
// Add small delay to prevent initial freeze when entering game
var gameReady = false;
LK.setTimeout(function () {
gameReady = true;
}, 50); // Reduced delay for better responsiveness ===================================================================
--- original.js
+++ change.js
@@ -405,8 +405,11 @@
LK.gui.center.addChild(noBtn);
noBtn.x = 150;
noBtn.y = 100;
noBtn.alpha = 0;
+// Add hit areas to confirmation dialog buttons
+yesBtn.hitArea = new Rectangle(-100, -40, 200, 80);
+noBtn.hitArea = new Rectangle(-100, -40, 200, 80);
// Confirmation dialog button handlers
yesBtn.down = function (x, y, obj) {
if (selectedDifficulty) {
aiDifficulty = selectedDifficulty;