/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Dot = Container.expand(function (index) { var self = Container.call(this); var dotGraphics = self.attachAsset('dot', { anchorX: 0.5, anchorY: 0.5 }); self.index = index; self.stone = null; self.highlighted = false; self.down = function (x, y, obj) { if (gamePhase === 'placing' && self.stone === null) { // Find unplaced stone of current player var availableStone = null; if (currentPlayer === 'red') { for (var i = 0; i < redStones.length; i++) { if (!redStones[i].isPlaced) { availableStone = redStones[i]; break; } } } else { for (var i = 0; i < blueStones.length; i++) { if (!blueStones[i].isPlaced) { availableStone = blueStones[i]; break; } } } if (availableStone) { placeStone(availableStone, self.index); } } else if (gamePhase === 'moving' && selectedStone && self.stone === null) { if (canMoveTo(selectedStone.dotIndex, self.index)) { moveStone(selectedStone, self.index); } } }; return self; }); var Stone = Container.expand(function (color) { var self = Container.call(this); var stoneGraphics = self.attachAsset(color === 'red' ? 'redStone' : 'blueStone', { anchorX: 0.5, anchorY: 0.5 }); self.color = color; self.dotIndex = -1; self.isPlaced = false; self.down = function (x, y, obj) { if (gamePhase === 'placing') { if (!self.isPlaced && currentPlayer === self.color) { // Find closest empty dot to place stone var closestDot = findClosestEmptyDot(self.x, self.y); if (closestDot !== -1) { placeStone(self, closestDot); } } } else if (gamePhase === 'moving') { if (self.isPlaced && currentPlayer === self.color) { selectedStone = self; // Highlight possible moves highlightValidMoves(self.dotIndex); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F4F }); /**** * Game Code ****/ var gamePhase = 'placing'; // 'placing' or 'moving' var currentPlayer = 'red'; // 'red' or 'blue' var selectedStone = null; var redStones = []; var blueStones = []; var dots = []; var board; var lines = []; var redStonesPlaced = 0; var blueStonesPlaced = 0; var arrows = []; var redWins = 0; var blueWins = 0; // Dot positions on 3x3 grid var dotPositions = [{ x: 0, y: 0 }, // 0: top-left { x: 1, y: 0 }, // 1: top-center { x: 2, y: 0 }, // 2: top-right { x: 0, y: 1 }, // 3: middle-left { x: 1, y: 1 }, // 4: center { x: 2, y: 1 }, // 5: middle-right { x: 0, y: 2 }, // 6: bottom-left { x: 1, y: 2 }, // 7: bottom-center { x: 2, y: 2 } // 8: bottom-right ]; // Valid connections between dots var connections = [[1, 3, 4], // 0: connects to 1, 3, 4 [0, 2, 4], // 1: connects to 0, 2, 4 [1, 4, 5], // 2: connects to 1, 4, 5 [0, 4, 6], // 3: connects to 0, 4, 6 [0, 1, 2, 3, 5, 6, 7, 8], // 4: center connects to all [2, 4, 8], // 5: connects to 2, 4, 8 [3, 4, 7], // 6: connects to 3, 4, 7 [4, 6, 8], // 7: connects to 4, 6, 8 [4, 5, 7] // 8: connects to 4, 5, 7 ]; // Winning lines (indices of dots that form winning lines) var winningLines = [[0, 1, 2], // top row [3, 4, 5], // middle row [6, 7, 8], // bottom row [0, 3, 6], // left column [1, 4, 7], // center column [2, 5, 8], // right column [0, 4, 8], // diagonal [2, 4, 6] // diagonal ]; // Create board board = game.addChild(LK.getAsset('board', { anchorX: 0.5, anchorY: 0.5 })); board.x = 1024; board.y = 1366; // Create connecting lines createLines(); // Create dots var boardSize = 750; // Size of board area for dot placement var dotSpacing = boardSize / 1.25; for (var i = 0; i < 9; i++) { var dot = game.addChild(new Dot(i)); var pos = dotPositions[i]; dot.x = board.x + (pos.x - 1) * dotSpacing; dot.y = board.y + (pos.y - 1) * dotSpacing; dots.push(dot); } // Create stones with more spacing for (var i = 0; i < 3; i++) { var redStone = game.addChild(new Stone('red')); redStone.x = 150 + i * 180; redStone.y = 400; redStones.push(redStone); var blueStone = game.addChild(new Stone('blue')); blueStone.x = 1500 + i * 180; blueStone.y = 400; blueStones.push(blueStone); } // Create UI var turnText = new Text2('Red Player\'s Turn', { size: 60, fill: 0xFFFFFF }); turnText.anchor.set(0.5, 0); LK.gui.top.addChild(turnText); var phaseText = new Text2('Placing Phase', { size: 40, fill: 0xFFFFFF }); phaseText.anchor.set(0.5, 0); phaseText.y = 80; LK.gui.top.addChild(phaseText); // Create score display var scoreText = new Text2('Red: 0 Blue: 0', { size: 50, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); scoreText.y = 130; LK.gui.top.addChild(scoreText); function createLines() { var boardSize = 750; // Size of board area for dot placement var dotSpacing = boardSize / 1.25; // Horizontal lines for (var row = 0; row < 3; row++) { var line = game.addChild(LK.getAsset('line', { anchorX: 0.5, anchorY: 0.5 })); line.x = board.x; line.y = board.y + (row - 1) * dotSpacing; lines.push(line); } // Vertical lines for (var col = 0; col < 3; col++) { var line = game.addChild(LK.getAsset('line', { anchorX: 0.5, anchorY: 0.5 })); line.x = board.x + (col - 1) * dotSpacing; line.y = board.y; line.rotation = Math.PI / 2; lines.push(line); } // Diagonal lines var diag1 = game.addChild(LK.getAsset('diagonalLine', { anchorX: 0.5, anchorY: 0.5 })); diag1.x = board.x; diag1.y = board.y; diag1.rotation = Math.PI / 4; lines.push(diag1); var diag2 = game.addChild(LK.getAsset('diagonalLine', { anchorX: 0.5, anchorY: 0.5 })); diag2.x = board.x; diag2.y = board.y; diag2.rotation = -Math.PI / 4; lines.push(diag2); } function findClosestEmptyDot(x, y) { var minDistance = Infinity; var closestDot = -1; for (var i = 0; i < dots.length; i++) { if (dots[i].stone === null) { var dx = x - dots[i].x; var dy = y - dots[i].y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistance && distance < 100) { minDistance = distance; closestDot = i; } } } return closestDot; } function placeStone(stone, dotIndex) { stone.x = dots[dotIndex].x; stone.y = dots[dotIndex].y; stone.dotIndex = dotIndex; stone.isPlaced = true; dots[dotIndex].stone = stone; LK.getSound('placeStone').play(); if (stone.color === 'red') { redStonesPlaced++; } else { blueStonesPlaced++; } // Check if all stones are placed if (redStonesPlaced === 3 && blueStonesPlaced === 3) { gamePhase = 'moving'; phaseText.setText('Moving Phase'); selectedStone = null; currentPlayer = 'red'; // Reset to red for moving phase } // Check for win if (checkWin()) { return; } // Switch turn only if not all stones are placed yet if (gamePhase === 'placing') { currentPlayer = currentPlayer === 'red' ? 'blue' : 'red'; turnText.setText((currentPlayer === 'red' ? 'Red' : 'Blue') + ' Player\'s Turn'); } else { // In moving phase, keep same player for first move turnText.setText((currentPlayer === 'red' ? 'Red' : 'Blue') + ' Player\'s Turn'); } } function canMoveTo(fromIndex, toIndex) { return connections[fromIndex].indexOf(toIndex) !== -1; } function moveStone(stone, dotIndex) { // Clear old position dots[stone.dotIndex].stone = null; // Move to new position stone.x = dots[dotIndex].x; stone.y = dots[dotIndex].y; stone.dotIndex = dotIndex; dots[dotIndex].stone = stone; selectedStone = null; clearHighlights(); LK.getSound('moveStone').play(); // Check for win if (checkWin()) { return; } // Switch turn currentPlayer = currentPlayer === 'red' ? 'blue' : 'red'; turnText.setText((currentPlayer === 'red' ? 'Red' : 'Blue') + ' Player\'s Turn'); } function highlightValidMoves(fromIndex) { clearHighlights(); var validMoves = connections[fromIndex]; for (var i = 0; i < validMoves.length; i++) { var dotIndex = validMoves[i]; if (dots[dotIndex].stone === null) { dots[dotIndex].highlighted = true; tween(dots[dotIndex], { alpha: 0.5 }, { duration: 300 }); // Create arrow pointing to valid move var arrow = game.addChild(LK.getAsset('arrow', { anchorX: 0.5, anchorY: 0.5 })); // Position arrow between current stone and target dot var fromDot = dots[fromIndex]; var toDot = dots[dotIndex]; arrow.x = (fromDot.x + toDot.x) / 2; arrow.y = (fromDot.y + toDot.y) / 2; // Calculate rotation to point towards target var dx = toDot.x - fromDot.x; var dy = toDot.y - fromDot.y; arrow.rotation = Math.atan2(dy, dx); arrows.push(arrow); } } } function clearHighlights() { for (var i = 0; i < dots.length; i++) { if (dots[i].highlighted) { dots[i].highlighted = false; tween(dots[i], { alpha: 1 }, { duration: 300 }); } } // Clear all arrows for (var i = 0; i < arrows.length; i++) { arrows[i].destroy(); } arrows = []; } function checkWin() { for (var i = 0; i < winningLines.length; i++) { var line = winningLines[i]; var stones = []; for (var j = 0; j < line.length; j++) { var dotIndex = line[j]; if (dots[dotIndex].stone) { stones.push(dots[dotIndex].stone.color); } } if (stones.length === 3 && stones[0] === stones[1] && stones[1] === stones[2]) { // Win detected LK.getSound('winSound').play(); // Flash winning stones for (var k = 0; k < line.length; k++) { var winStone = dots[line[k]].stone; LK.effects.flashObject(winStone, 0xFFFF00, 1000); } // Show winner var winner = stones[0]; if (winner === 'red') { redWins++; } else { blueWins++; } scoreText.setText('Red: ' + redWins + ' Blue: ' + blueWins); turnText.setText((winner === 'red' ? 'Red' : 'Blue') + ' Player Wins!'); LK.setTimeout(function () { LK.showYouWin(); }, 2000); return true; } } return false; } game.update = function () { // Game logic handled by events };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Dot = Container.expand(function (index) {
var self = Container.call(this);
var dotGraphics = self.attachAsset('dot', {
anchorX: 0.5,
anchorY: 0.5
});
self.index = index;
self.stone = null;
self.highlighted = false;
self.down = function (x, y, obj) {
if (gamePhase === 'placing' && self.stone === null) {
// Find unplaced stone of current player
var availableStone = null;
if (currentPlayer === 'red') {
for (var i = 0; i < redStones.length; i++) {
if (!redStones[i].isPlaced) {
availableStone = redStones[i];
break;
}
}
} else {
for (var i = 0; i < blueStones.length; i++) {
if (!blueStones[i].isPlaced) {
availableStone = blueStones[i];
break;
}
}
}
if (availableStone) {
placeStone(availableStone, self.index);
}
} else if (gamePhase === 'moving' && selectedStone && self.stone === null) {
if (canMoveTo(selectedStone.dotIndex, self.index)) {
moveStone(selectedStone, self.index);
}
}
};
return self;
});
var Stone = Container.expand(function (color) {
var self = Container.call(this);
var stoneGraphics = self.attachAsset(color === 'red' ? 'redStone' : 'blueStone', {
anchorX: 0.5,
anchorY: 0.5
});
self.color = color;
self.dotIndex = -1;
self.isPlaced = false;
self.down = function (x, y, obj) {
if (gamePhase === 'placing') {
if (!self.isPlaced && currentPlayer === self.color) {
// Find closest empty dot to place stone
var closestDot = findClosestEmptyDot(self.x, self.y);
if (closestDot !== -1) {
placeStone(self, closestDot);
}
}
} else if (gamePhase === 'moving') {
if (self.isPlaced && currentPlayer === self.color) {
selectedStone = self;
// Highlight possible moves
highlightValidMoves(self.dotIndex);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F4F
});
/****
* Game Code
****/
var gamePhase = 'placing'; // 'placing' or 'moving'
var currentPlayer = 'red'; // 'red' or 'blue'
var selectedStone = null;
var redStones = [];
var blueStones = [];
var dots = [];
var board;
var lines = [];
var redStonesPlaced = 0;
var blueStonesPlaced = 0;
var arrows = [];
var redWins = 0;
var blueWins = 0;
// Dot positions on 3x3 grid
var dotPositions = [{
x: 0,
y: 0
},
// 0: top-left
{
x: 1,
y: 0
},
// 1: top-center
{
x: 2,
y: 0
},
// 2: top-right
{
x: 0,
y: 1
},
// 3: middle-left
{
x: 1,
y: 1
},
// 4: center
{
x: 2,
y: 1
},
// 5: middle-right
{
x: 0,
y: 2
},
// 6: bottom-left
{
x: 1,
y: 2
},
// 7: bottom-center
{
x: 2,
y: 2
} // 8: bottom-right
];
// Valid connections between dots
var connections = [[1, 3, 4],
// 0: connects to 1, 3, 4
[0, 2, 4],
// 1: connects to 0, 2, 4
[1, 4, 5],
// 2: connects to 1, 4, 5
[0, 4, 6],
// 3: connects to 0, 4, 6
[0, 1, 2, 3, 5, 6, 7, 8],
// 4: center connects to all
[2, 4, 8],
// 5: connects to 2, 4, 8
[3, 4, 7],
// 6: connects to 3, 4, 7
[4, 6, 8],
// 7: connects to 4, 6, 8
[4, 5, 7] // 8: connects to 4, 5, 7
];
// Winning lines (indices of dots that form winning lines)
var winningLines = [[0, 1, 2],
// top row
[3, 4, 5],
// middle row
[6, 7, 8],
// bottom row
[0, 3, 6],
// left column
[1, 4, 7],
// center column
[2, 5, 8],
// right column
[0, 4, 8],
// diagonal
[2, 4, 6] // diagonal
];
// Create board
board = game.addChild(LK.getAsset('board', {
anchorX: 0.5,
anchorY: 0.5
}));
board.x = 1024;
board.y = 1366;
// Create connecting lines
createLines();
// Create dots
var boardSize = 750; // Size of board area for dot placement
var dotSpacing = boardSize / 1.25;
for (var i = 0; i < 9; i++) {
var dot = game.addChild(new Dot(i));
var pos = dotPositions[i];
dot.x = board.x + (pos.x - 1) * dotSpacing;
dot.y = board.y + (pos.y - 1) * dotSpacing;
dots.push(dot);
}
// Create stones with more spacing
for (var i = 0; i < 3; i++) {
var redStone = game.addChild(new Stone('red'));
redStone.x = 150 + i * 180;
redStone.y = 400;
redStones.push(redStone);
var blueStone = game.addChild(new Stone('blue'));
blueStone.x = 1500 + i * 180;
blueStone.y = 400;
blueStones.push(blueStone);
}
// Create UI
var turnText = new Text2('Red Player\'s Turn', {
size: 60,
fill: 0xFFFFFF
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
var phaseText = new Text2('Placing Phase', {
size: 40,
fill: 0xFFFFFF
});
phaseText.anchor.set(0.5, 0);
phaseText.y = 80;
LK.gui.top.addChild(phaseText);
// Create score display
var scoreText = new Text2('Red: 0 Blue: 0', {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 130;
LK.gui.top.addChild(scoreText);
function createLines() {
var boardSize = 750; // Size of board area for dot placement
var dotSpacing = boardSize / 1.25;
// Horizontal lines
for (var row = 0; row < 3; row++) {
var line = game.addChild(LK.getAsset('line', {
anchorX: 0.5,
anchorY: 0.5
}));
line.x = board.x;
line.y = board.y + (row - 1) * dotSpacing;
lines.push(line);
}
// Vertical lines
for (var col = 0; col < 3; col++) {
var line = game.addChild(LK.getAsset('line', {
anchorX: 0.5,
anchorY: 0.5
}));
line.x = board.x + (col - 1) * dotSpacing;
line.y = board.y;
line.rotation = Math.PI / 2;
lines.push(line);
}
// Diagonal lines
var diag1 = game.addChild(LK.getAsset('diagonalLine', {
anchorX: 0.5,
anchorY: 0.5
}));
diag1.x = board.x;
diag1.y = board.y;
diag1.rotation = Math.PI / 4;
lines.push(diag1);
var diag2 = game.addChild(LK.getAsset('diagonalLine', {
anchorX: 0.5,
anchorY: 0.5
}));
diag2.x = board.x;
diag2.y = board.y;
diag2.rotation = -Math.PI / 4;
lines.push(diag2);
}
function findClosestEmptyDot(x, y) {
var minDistance = Infinity;
var closestDot = -1;
for (var i = 0; i < dots.length; i++) {
if (dots[i].stone === null) {
var dx = x - dots[i].x;
var dy = y - dots[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance && distance < 100) {
minDistance = distance;
closestDot = i;
}
}
}
return closestDot;
}
function placeStone(stone, dotIndex) {
stone.x = dots[dotIndex].x;
stone.y = dots[dotIndex].y;
stone.dotIndex = dotIndex;
stone.isPlaced = true;
dots[dotIndex].stone = stone;
LK.getSound('placeStone').play();
if (stone.color === 'red') {
redStonesPlaced++;
} else {
blueStonesPlaced++;
}
// Check if all stones are placed
if (redStonesPlaced === 3 && blueStonesPlaced === 3) {
gamePhase = 'moving';
phaseText.setText('Moving Phase');
selectedStone = null;
currentPlayer = 'red'; // Reset to red for moving phase
}
// Check for win
if (checkWin()) {
return;
}
// Switch turn only if not all stones are placed yet
if (gamePhase === 'placing') {
currentPlayer = currentPlayer === 'red' ? 'blue' : 'red';
turnText.setText((currentPlayer === 'red' ? 'Red' : 'Blue') + ' Player\'s Turn');
} else {
// In moving phase, keep same player for first move
turnText.setText((currentPlayer === 'red' ? 'Red' : 'Blue') + ' Player\'s Turn');
}
}
function canMoveTo(fromIndex, toIndex) {
return connections[fromIndex].indexOf(toIndex) !== -1;
}
function moveStone(stone, dotIndex) {
// Clear old position
dots[stone.dotIndex].stone = null;
// Move to new position
stone.x = dots[dotIndex].x;
stone.y = dots[dotIndex].y;
stone.dotIndex = dotIndex;
dots[dotIndex].stone = stone;
selectedStone = null;
clearHighlights();
LK.getSound('moveStone').play();
// Check for win
if (checkWin()) {
return;
}
// Switch turn
currentPlayer = currentPlayer === 'red' ? 'blue' : 'red';
turnText.setText((currentPlayer === 'red' ? 'Red' : 'Blue') + ' Player\'s Turn');
}
function highlightValidMoves(fromIndex) {
clearHighlights();
var validMoves = connections[fromIndex];
for (var i = 0; i < validMoves.length; i++) {
var dotIndex = validMoves[i];
if (dots[dotIndex].stone === null) {
dots[dotIndex].highlighted = true;
tween(dots[dotIndex], {
alpha: 0.5
}, {
duration: 300
});
// Create arrow pointing to valid move
var arrow = game.addChild(LK.getAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
}));
// Position arrow between current stone and target dot
var fromDot = dots[fromIndex];
var toDot = dots[dotIndex];
arrow.x = (fromDot.x + toDot.x) / 2;
arrow.y = (fromDot.y + toDot.y) / 2;
// Calculate rotation to point towards target
var dx = toDot.x - fromDot.x;
var dy = toDot.y - fromDot.y;
arrow.rotation = Math.atan2(dy, dx);
arrows.push(arrow);
}
}
}
function clearHighlights() {
for (var i = 0; i < dots.length; i++) {
if (dots[i].highlighted) {
dots[i].highlighted = false;
tween(dots[i], {
alpha: 1
}, {
duration: 300
});
}
}
// Clear all arrows
for (var i = 0; i < arrows.length; i++) {
arrows[i].destroy();
}
arrows = [];
}
function checkWin() {
for (var i = 0; i < winningLines.length; i++) {
var line = winningLines[i];
var stones = [];
for (var j = 0; j < line.length; j++) {
var dotIndex = line[j];
if (dots[dotIndex].stone) {
stones.push(dots[dotIndex].stone.color);
}
}
if (stones.length === 3 && stones[0] === stones[1] && stones[1] === stones[2]) {
// Win detected
LK.getSound('winSound').play();
// Flash winning stones
for (var k = 0; k < line.length; k++) {
var winStone = dots[line[k]].stone;
LK.effects.flashObject(winStone, 0xFFFF00, 1000);
}
// Show winner
var winner = stones[0];
if (winner === 'red') {
redWins++;
} else {
blueWins++;
}
scoreText.setText('Red: ' + redWins + ' Blue: ' + blueWins);
turnText.setText((winner === 'red' ? 'Red' : 'Blue') + ' Player Wins!');
LK.setTimeout(function () {
LK.showYouWin();
}, 2000);
return true;
}
}
return false;
}
game.update = function () {
// Game logic handled by events
};