User prompt
קח את השמות של כל המחשבים 5 פיקסלים למעלה
User prompt
עוד 5 פיקסלים
User prompt
עוד 30 פיקסלים
User prompt
קח את הלוח כולו עם השם של שחקן מספר 2 30 פיקסלים שמאלה
User prompt
עוד 3 פיקסלים
User prompt
תיקח את המילים Your Kingdom עוד 10 פיקסלים למטה
User prompt
את הכיתוב Your Kingdom תיקח למטה 10 פיקסלים ותהפוך אותו לשחור את ההנחיות, select a tile וכל דבר שזה מתחלף אליו תהפוך לכתובות בשחור
User prompt
עוד 5 פיקסלים
User prompt
תחסיר 10 פיקסלים מכל אלה עכשיו
User prompt
קח 5 פיקסלים למעלה את השמות של כל המחשבים: AI player i ותעשה אותו בצבע שחור
User prompt
את הכיתוב של המספר מתחת לקלף תעשה בצבע שחור
User prompt
תעשה רקע למאחורי איפה שהקלפים נפתחים תעשה רקע לכל לוח
User prompt
כן, אני מזהה בעיה מהותית באופן הבדיקה האם ניתן להניח את האבן, והיא קשורה ישירות לסיבוב. הבעיה: בתוך הפונקציה self.canPlaceTile, יש שורה שבה המשתנה positions מוגדר מחדש: var positions = [[row, col], [row, col + 1]]; שורה זו דורסת את הערך הנכון של positions שהתקבל קודם לכן מ-self.getTilePositions(tile, row, col). הבעיה היא ש-self.getTilePositions כן לוקחת בחשבון את הסיבוב של האבן (tile.currentRotationAngle), ומחזירה את שני התאים שהאבן תתפוס בפועל על הלוח בהתחשב בסיבובה. כאשר positions נדרס ל-[[row, col], [row, col + 1]], זה אומר שכל הבדיקות הבאות בתוך canPlaceTile (בדיקת סמיכות לממלכה קיימת ובדיקת התאמת שטח) תמיד יניחו שהאבן מונחת בצורה אופקית (שמאל-ימין), ללא קשר לסיבוב האמיתי של האבן. לדוגמה, אם האבן מסובבת ב-90 מעלות (אנכית), getTilePositions תחזיר מיקומים כמו [[row, col], [row+1, col]]. אבל מיד לאחר מכן, positions ישונה ל-[[row, col], [row, col+1]], מה שיוביל לבדיקות שגויות לחלוטין. הפתרון: יש להסיר את השורה הבעייתית שדורסת את המשתנה positions. הפונקציה צריכה להשתמש באופן עקבי במשתנה positions שהתקבל בתחילת הפונקציה מ-self.getTilePositions(tile, row, col).
User prompt
אם סובבתי את האובייקט, שיבדוק בצורה הנכונה האם מתאים או לא מתאים. כשהוא נבנה, שיעשה צ'ק האם יש לפחות תנאי אחד שמקיים את זה
User prompt
אם אני מנסה לחבר שניים זהים לאורך מלמעלה, זה לא נותן. מלמטה כן
User prompt
אחרי היפוך, אם אני מנסה לחבר, הוא לא נותן לי תעשה שעם הפכו, מעכשיו זה נחשב למעלה ולמטה, הפכו שוב, התהפך הימין והשמאל בבדיקות, התהפך שוב, השתנה הלמטה והלמעלה בבדיקות, התהפך שוב חזק לבדוק כרגיל
User prompt
הוא הופך את האבן חזרה בבנייה. שלא יהפוך חזרה, שיבנה אותה הפוכה. סימן ימין בשמאל, וסימן שמאל בימין
User prompt
כשאר בונים אבן הפוכה, הוא גם הופך שוב אחר כך את הסדר שלהם. נניח היה חיטה בימין ועץ בשמאל, סובבתי פעמיים, בניתי, הוא שם חיטה בימין ועץ בשמאל אבל על הראש. שיעשה אותם ישר, אבל אם סובבתי אז להפוך כיוונים
User prompt
זה לא בודק את האבן במתחת אני מנסה לחבר צמד יער ליער בודד, מלמעלה זה לא נותן מלמטה כן
User prompt
כאשר באים לבנות, שיבדוק את כל האבנים השכנות האם אחת מהם מתאימה. אם יצא שהראשונה לא, שיבדוק אם יש אחרת שאולי תתאים, ואם כן לאשר את הבנייה
User prompt
אם סובבתי אבן ואז בניתי, שיבנה אותה מסובב כמו שצריך. העניין הזה בוטל בטעות
User prompt
לפעמים אחרי סיבוב הוא כנראה לא מסובב טוב, ואז הוא לא נותן לבנות למרות שזה חוקי
User prompt
מתחת לתוצאה שלי, תכתוב את התוצאה של שאר המחשבים גם. כמובן מתעדכנת אם הם מזיזים את הלוח שלהם כדי להכניס עוד אבן ויורדת אם הם זורקים אבן לפח
User prompt
זה עדיין לא נותן צריך שרק צד אחד של האבן החדשה יתאים לאחד הדברים שכבר בנויים, ויהיה באמת צמוד אליו בבנייה הטירה מתאימה להכל
User prompt
כל דבר נחשב למתאים לטירה
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var GameTile = Container.expand(function (leftType, rightType, leftCrowns, rightCrowns, number) { var self = Container.call(this); self.leftType = leftType; self.rightType = rightType; self.leftCrowns = leftCrowns; self.rightCrowns = rightCrowns; self.number = number; self.selected = false; self.rotation = 0; // 0, 90, 180, 270 degrees self.currentRotationAngle = 0; // Track rotation angle in degrees self.isDragging = false; self.ownerPlayer = null; // Track which player owns this tile // Create tile background var bg = self.addChild(LK.getAsset('tileSlot', { anchorX: 0.5, anchorY: 0.5 })); // Create terrain sections var leftTerrain = self.addChild(LK.getAsset(leftType, { x: -60, y: 0, anchorX: 0.5, anchorY: 0.5 })); var rightTerrain = self.addChild(LK.getAsset(rightType, { x: 60, y: 0, anchorX: 0.5, anchorY: 0.5 })); // Add crowns for (var i = 0; i < leftCrowns; i++) { self.addChild(LK.getAsset('crown', { x: -60 - 35 + i * 15, y: -35, anchorX: 0.5, anchorY: 0.5 })); } for (var i = 0; i < rightCrowns; i++) { self.addChild(LK.getAsset('crown', { x: 60 - 35 + i * 15, y: -35, anchorX: 0.5, anchorY: 0.5 })); } // Remove the number display from here as it's handled in drawCurrentTiles // Add rotation button (only visible when selected) var rotateBtn = self.addChild(new Text2('↻', { size: 30, fill: 0x00FF00 })); rotateBtn.anchor.set(0.5, 0.5); rotateBtn.x = 100; rotateBtn.y = -50; rotateBtn.alpha = 0; self.rotateBtn = rotateBtn; // Store original terrain references for rotation self.leftTerrain = leftTerrain; self.rightTerrain = rightTerrain; self.rotateTile = function () { self.currentRotationAngle = (self.currentRotationAngle + 90) % 360; self.rotation = self.currentRotationAngle * Math.PI / 180; }; self.updateTileVisuals = function () { // Normalize rotation angle to 0, 90, 180, or 270 degrees self.currentRotationAngle = (self.currentRotationAngle % 360 + 360) % 360; if (self.currentRotationAngle % 90 !== 0) { self.currentRotationAngle = Math.round(self.currentRotationAngle / 90) * 90; } // Set Container rotation based on angle self.rotation = self.currentRotationAngle * Math.PI / 180; }; self.setSelected = function (selected) { self.selected = selected; if (selected) { if (!self.selectedBg) { self.selectedBg = self.addChildAt(LK.getAsset('selectedTile', { anchorX: 0.5, anchorY: 0.5 }), 0); } self.rotateBtn.alpha = 1; } else { if (self.selectedBg) { self.removeChild(self.selectedBg); self.selectedBg = null; } self.rotateBtn.alpha = 0; } }; self.down = function (x, y, obj) { // Prevent interaction if tile is owned by AI player or during AI turn if (self.ownerPlayer && self.ownerPlayer !== 0) { return; } if (gameState === 'aiTurn') { return; } if (gameState === 'selectTile' && currentPlayer === 0) { selectTile(self); } else if (gameState === 'placeTile' && currentPlayer === 0 && self.selected) { // Check if clicked on rotation button using local coordinates directly if (x > 85 && x < 115 && y > -65 && y < -35) { self.rotateTile(); LK.getSound('selectSound').play(); } else { // Start dragging self.isDragging = true; draggedTile = self; } } }; return self; }); var Kingdom = Container.expand(function (playerIndex) { var self = Container.call(this); self.playerIndex = playerIndex; self.grid = []; self.score = 0; self.hasMoved = false; // Track if player has moved kingdom // Initialize 5x5 grid for (var i = 0; i < 5; i++) { self.grid[i] = []; for (var j = 0; j < 5; j++) { self.grid[i][j] = null; } } // Place castle at center self.grid[2][2] = { type: 'castle', crowns: 0 }; // Draw kingdom grid self.drawKingdom = function () { // Clear existing visuals for (var i = self.children.length - 1; i >= 0; i--) { self.removeChild(self.children[i]); } for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { var cell = self.addChild(LK.getAsset('kingdomCell', { x: j * 125, y: i * 125, anchorX: 0, anchorY: 0 })); if (self.grid[i][j]) { var terrain = self.addChild(LK.getAsset(self.grid[i][j].type, { x: j * 125 + 62.5, y: i * 125 + 62.5, anchorX: 0.5, anchorY: 0.5 })); // Add crowns if present for (var c = 0; c < self.grid[i][j].crowns; c++) { var crown = self.addChild(LK.getAsset('crown', { x: j * 125 + 62.5 - 35 + c * 15, y: i * 125 + 35, anchorX: 0.5, anchorY: 0.5 })); } } } } }; self.canPlaceTile = function (tile, row, col) { // Check if positions are valid and empty based on rotation var positions = self.getTilePositions(tile, row, col); if (!positions) { return false; } if (self.grid[positions[0][0]][positions[0][1]] !== null || self.grid[positions[1][0]][positions[1][1]] !== null) { return false; } // Check if adjacent to existing kingdom var adjacent = false; var positions = [[row, col], [row, col + 1]]; for (var p = 0; p < positions.length; p++) { var r = positions[p][0]; var c = positions[p][1]; // Check all 4 directions var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; for (var d = 0; d < directions.length; d++) { var nr = r + directions[d][0]; var nc = c + directions[d][1]; if (nr >= 0 && nr < 5 && nc >= 0 && nc < 5 && self.grid[nr][nc] !== null) { adjacent = true; break; } } if (adjacent) { break; } } if (!adjacent) { return false; } // Check terrain matching - need at least one matching adjacent terrain var validConnections = 0; for (var p = 0; p < positions.length; p++) { var r = positions[p][0]; var c = positions[p][1]; var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; for (var d = 0; d < directions.length; d++) { var nr = r + directions[d][0]; var nc = c + directions[d][1]; if (nr >= 0 && nr < 5 && nc >= 0 && nc < 5 && self.grid[nr][nc] !== null) { if (self.grid[nr][nc].type === 'castle') { // Castle connection is always valid - everything matches castle validConnections++; } else { // Check if terrain matches var terrainIndex = p; var tileType = terrainIndex === 0 ? tile.leftType : tile.rightType; if (self.grid[nr][nc].type === tileType) { validConnections++; } } } } } return validConnections >= 1; }; self.getTilePositions = function (tile, row, col) { var positions; if (tile.currentRotationAngle === 0) { // Horizontal: left-right if (col >= 4) { return null; } positions = [[row, col], [row, col + 1]]; } else if (tile.currentRotationAngle === 90) { // Vertical: top-bottom if (row >= 4) { return null; } positions = [[row, col], [row + 1, col]]; } else if (tile.currentRotationAngle === 180) { // Horizontal: right-left if (col >= 4) { return null; } positions = [[row, col + 1], [row, col]]; } else { // 270 // Vertical: bottom-top if (row >= 4) { return null; } positions = [[row + 1, col], [row, col]]; } // Check bounds for (var i = 0; i < positions.length; i++) { if (positions[i][0] < 0 || positions[i][0] >= 5 || positions[i][1] < 0 || positions[i][1] >= 5) { return null; } } return positions; }; self.placeTile = function (tile, row, col) { var positions = self.getTilePositions(tile, row, col); if (!positions) { return false; } // Place based on rotation if (tile.currentRotationAngle === 0 || tile.currentRotationAngle === 180) { // Horizontal placement self.grid[positions[0][0]][positions[0][1]] = { type: tile.leftType, crowns: tile.leftCrowns }; self.grid[positions[1][0]][positions[1][1]] = { type: tile.rightType, crowns: tile.rightCrowns }; } else { // Vertical placement self.grid[positions[0][0]][positions[0][1]] = { type: tile.leftType, crowns: tile.leftCrowns }; self.grid[positions[1][0]][positions[1][1]] = { type: tile.rightType, crowns: tile.rightCrowns }; } self.drawKingdom(); return true; }; self.calculateScore = function () { var visited = []; var totalScore = 0; for (var i = 0; i < 5; i++) { visited[i] = []; for (var j = 0; j < 5; j++) { visited[i][j] = false; } } for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { if (!visited[i][j] && self.grid[i][j] && self.grid[i][j].type !== 'castle') { var result = self.floodFill(i, j, self.grid[i][j].type, visited); totalScore += result.size * result.crowns; } } } self.score = totalScore; return totalScore; }; self.floodFill = function (row, col, terrainType, visited) { if (row < 0 || row >= 5 || col < 0 || col >= 5) { return { size: 0, crowns: 0 }; } if (visited[row][col]) { return { size: 0, crowns: 0 }; } if (!self.grid[row][col] || self.grid[row][col].type !== terrainType) { return { size: 0, crowns: 0 }; } visited[row][col] = true; var size = 1; var crowns = self.grid[row][col].crowns; var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; for (var d = 0; d < directions.length; d++) { var result = self.floodFill(row + directions[d][0], col + directions[d][1], terrainType, visited); size += result.size; crowns += result.crowns; } return { size: size, crowns: crowns }; }; // Check if kingdom can be moved in a direction self.canMoveKingdom = function (direction) { // Find bounds of current kingdom var minRow = 5, maxRow = -1, minCol = 5, maxCol = -1; for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { if (self.grid[i][j] !== null) { minRow = Math.min(minRow, i); maxRow = Math.max(maxRow, i); minCol = Math.min(minCol, j); maxCol = Math.max(maxCol, j); } } } // Check if movement is possible if (direction === 'up' && minRow <= 0) { return false; } if (direction === 'down' && maxRow >= 4) { return false; } if (direction === 'left' && minCol <= 0) { return false; } if (direction === 'right' && maxCol >= 4) { return false; } return true; }; // Move entire kingdom in a direction self.moveKingdom = function (direction) { if (!self.canMoveKingdom(direction)) { return false; } var newGrid = []; for (var i = 0; i < 5; i++) { newGrid[i] = []; for (var j = 0; j < 5; j++) { newGrid[i][j] = null; } } var deltaRow = 0, deltaCol = 0; if (direction === 'up') { deltaRow = -1; } if (direction === 'down') { deltaRow = 1; } if (direction === 'left') { deltaCol = -1; } if (direction === 'right') { deltaCol = 1; } // Move all tiles for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { if (self.grid[i][j] !== null) { var newRow = i + deltaRow; var newCol = j + deltaCol; if (newRow >= 0 && newRow < 5 && newCol >= 0 && newCol < 5) { newGrid[newRow][newCol] = self.grid[i][j]; } } } } self.grid = newGrid; self.drawKingdom(); self.hasMoved = true; // Mark that kingdom has been moved return true; }; self.drawKingdom(); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F2F }); /**** * Game Code ****/ // Game state variables // Initialize basic game assets var gameState = 'selectTile'; // 'selectTile', 'placeTile', 'gameOver' var currentPlayer = 0; var round = 1; var maxRounds = 12; var selectedTile = null; var draggedTile = null; var placementRow = -1; var placementCol = -1; // Player kingdoms var kingdoms = []; var players = ['Human', 'AI1', 'AI2', 'AI3']; var turnOrder = [0, 1, 2, 3]; // Tile deck var tileDeck = []; var currentTiles = []; var selectedTiles = []; // UI elements var scoreTxt = new Text2('Round: 1', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var playerScoreTxt = new Text2('Your Score: 0', { size: 45, fill: 0xFFFFFF }); playerScoreTxt.anchor.set(0, 0); playerScoreTxt.x = 50; playerScoreTxt.y = 150; LK.gui.topLeft.addChild(playerScoreTxt); var instructionTxt = new Text2('Select a tile', { size: 40, fill: 0xFFFFFF }); instructionTxt.anchor.set(0.5, 1); LK.gui.bottom.addChild(instructionTxt); // Movement control buttons var moveButtonContainer = new Container(); moveButtonContainer.x = 50; moveButtonContainer.y = 1550; LK.gui.topLeft.addChild(moveButtonContainer); var moveUpBtn = new Text2('↑', { size: 50, fill: 0xFFFFFF }); moveUpBtn.anchor.set(0.5, 0.5); moveUpBtn.x = 75; moveUpBtn.y = 0; moveButtonContainer.addChild(moveUpBtn); var moveLeftBtn = new Text2('←', { size: 50, fill: 0xFFFFFF }); moveLeftBtn.anchor.set(0.5, 0.5); moveLeftBtn.x = 25; moveLeftBtn.y = 50; moveButtonContainer.addChild(moveLeftBtn); var moveRightBtn = new Text2('→', { size: 50, fill: 0xFFFFFF }); moveRightBtn.anchor.set(0.5, 0.5); moveRightBtn.x = 125; moveRightBtn.y = 50; moveButtonContainer.addChild(moveRightBtn); var moveDownBtn = new Text2('↓', { size: 50, fill: 0xFFFFFF }); moveDownBtn.anchor.set(0.5, 0.5); moveDownBtn.x = 75; moveDownBtn.y = 100; moveButtonContainer.addChild(moveDownBtn); // Trash button var trashBtn = new Text2('🗑', { size: 60, fill: 0xFF0000 }); trashBtn.anchor.set(0.5, 0.5); trashBtn.x = 135; trashBtn.y = 1750; LK.gui.topLeft.addChild(trashBtn); var trashLabel = new Text2('Trash (-5pts)', { size: 30, fill: 0xFFFFFF }); trashLabel.anchor.set(0.5, 0); trashLabel.x = 135; trashLabel.y = 1790; LK.gui.topLeft.addChild(trashLabel); // Movement cost label var moveCostLabel = new Text2('Move (-10pts)', { size: 30, fill: 0xFFFFFF }); moveCostLabel.anchor.set(0.5, 0); moveCostLabel.x = 140; moveCostLabel.y = 1480; LK.gui.topLeft.addChild(moveCostLabel); // Turn order display var turnOrderContainer = new Container(); turnOrderContainer.x = -200; turnOrderContainer.y = 50; LK.gui.topRight.addChild(turnOrderContainer); var turnOrderTexts = []; for (var i = 0; i < 4; i++) { var turnText = new Text2('', { size: 35, fill: 0xFFFFFF }); turnText.anchor.set(1, 0); turnText.y = i * 45; turnOrderContainer.addChild(turnText); turnOrderTexts.push(turnText); } // Update turn order display function updateTurnOrderDisplay() { var playerNames = ['YOU', 'AI 1', 'AI 2', 'AI 3']; for (var i = 0; i < 4; i++) { if (turnOrderTexts[i]) { var playerIndex = turnOrder[i]; var isCurrentPlayer = i === turnOrder.indexOf(currentPlayer); turnOrderTexts[i].setText(i + 1 + '. ' + playerNames[playerIndex]); turnOrderTexts[i].tint = isCurrentPlayer ? 0x00FF00 : 0xFFFFFF; } } } // Initialize tile deck function initializeTileDeck() { // Complete set of 48 Kingdomino tiles with exact terrain and crown combinations var tileData = [ // Tiles 1-8: Wheat fields { leftType: 'wheat', rightType: 'wheat', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'wheat', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, // Tiles 9-16: Grassland { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'swamp', rightType: 'swamp', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'swamp', leftCrowns: 0, rightCrowns: 0 }, // Tiles 17-24: Forest { leftType: 'forest', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'lake', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'swamp', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'mine', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, // Tiles 25-32: Lake { leftType: 'forest', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'lake', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'grassland', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, // Tiles 33-40: Swamp and Mine { leftType: 'lake', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'lake', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'lake', rightType: 'grassland', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'wheat', rightType: 'swamp', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'grassland', rightType: 'swamp', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'mine', rightType: 'wheat', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 0, rightCrowns: 2 }, // Tiles 41-48: Crown tiles { leftType: 'lake', rightType: 'grassland', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'wheat', rightType: 'swamp', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'grassland', rightType: 'swamp', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'mine', rightType: 'wheat', leftCrowns: 2, rightCrowns: 0 }, { leftType: 'swamp', rightType: 'mine', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'swamp', rightType: 'mine', leftCrowns: 0, rightCrowns: 2 }, { leftType: 'wheat', rightType: 'mine', leftCrowns: 0, rightCrowns: 3 }]; // Create shuffled deck var shuffledIndices = []; for (var i = 0; i < 48; i++) { shuffledIndices.push(i); } // Shuffle the indices for (var i = shuffledIndices.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = shuffledIndices[i]; shuffledIndices[i] = shuffledIndices[j]; shuffledIndices[j] = temp; } // Create tileDeck with shuffled order and original tile numbers for (var i = 0; i < 48; i++) { var data = tileData[shuffledIndices[i]]; tileDeck.push({ leftType: data.leftType, rightType: data.rightType, leftCrowns: data.leftCrowns, rightCrowns: data.rightCrowns, number: shuffledIndices[i] + 1 // Use the original tile number from shuffled deck }); } } // Initialize kingdoms function initializeKingdoms() { for (var i = 0; i < 4; i++) { var kingdom = new Kingdom(i); kingdoms.push(kingdom); // Position kingdoms around the screen if (i === 0) { // Human player - bottom center, moved left by half position kingdom.x = 1024 - 312 - 12.5; // Center horizontally moved left by half position (changed from +50 to -12.5) kingdom.y = 2050; // Move up slightly kingdom.scaleX = 1.0; kingdom.scaleY = 1.0; game.addChild(kingdom); // Add player label above kingdom var playerLabel = new Text2('YOUR KINGDOM', { size: 40, fill: 0xFFFFFF }); playerLabel.anchor.set(0.5, 1); playerLabel.x = kingdom.x + 312; playerLabel.y = kingdom.y - 20; // Above kingdom game.addChild(playerLabel); } else if (i === 1) { // AI 1 - top center, moved left by half position kingdom.x = 1024 - 312 - 12.5; // Center horizontally moved left by half position (changed from +50 to -12.5) kingdom.y = 100; kingdom.scaleX = 1.0; kingdom.scaleY = 1.0; game.addChild(kingdom); // Add player label var playerLabel = new Text2('AI PLAYER 1', { size: 40, fill: 0xFFFFFF }); playerLabel.anchor.set(0.5, 0); playerLabel.x = kingdom.x + 312; playerLabel.y = kingdom.y + 625 + 20; // Below kingdom game.addChild(playerLabel); } else if (i === 2) { // AI 2 - right center, moved left slightly kingdom.x = 1400 + 50; kingdom.y = 1366 - 312; // Center vertically kingdom.scaleX = 1.0; kingdom.scaleY = 1.0; game.addChild(kingdom); // Add player label var playerLabel = new Text2('AI PLAYER 2', { size: 40, fill: 0xFFFFFF }); playerLabel.anchor.set(0.5, 0); playerLabel.x = kingdom.x + 312; playerLabel.y = kingdom.y + 625 + 20; // Below kingdom game.addChild(playerLabel); } else if (i === 3) { // AI 3 - left center, moved left slightly kingdom.x = 20 + 50; kingdom.y = 1366 - 312; // Center vertically kingdom.scaleX = 1.0; kingdom.scaleY = 1.0; game.addChild(kingdom); // Add player label var playerLabel = new Text2('AI PLAYER 3', { size: 40, fill: 0xFFFFFF }); playerLabel.anchor.set(0.5, 0); playerLabel.x = kingdom.x + 312; playerLabel.y = kingdom.y + 625 + 20; // Below kingdom game.addChild(playerLabel); } } } // Draw current tiles function drawCurrentTiles() { // Clear existing tiles for (var i = 0; i < currentTiles.length; i++) { if (currentTiles[i].parent) { currentTiles[i].parent.removeChild(currentTiles[i]); } // Also remove the global number text if (currentTiles[i].globalNumberText && currentTiles[i].globalNumberText.parent) { currentTiles[i].globalNumberText.parent.removeChild(currentTiles[i].globalNumberText); } } currentTiles = []; // Get 4 tiles from deck var tilesToShow = []; for (var i = 0; i < 4; i++) { if (tileDeck.length > 0) { tilesToShow.push(tileDeck.shift()); } } // Sort tiles by their original number (lowest to highest) tilesToShow.sort(function (a, b) { return a.number - b.number; }); // Draw sorted tiles in a column centered on screen for (var i = 0; i < tilesToShow.length; i++) { var tileData = tilesToShow[i]; var tile = new GameTile(tileData.leftType, tileData.rightType, tileData.leftCrowns, tileData.rightCrowns, tileData.number); tile.x = 1024; // Center horizontally (screen width / 2) tile.y = 1366 - 375 + i * 250; // Move down by half position (changed from -500 to -375) currentTiles.push(tile); game.addChild(tile); // Add global tile number below the tile (showing the actual shuffled tile number) var globalNumberText = new Text2(tileData.number.toString(), { size: 40, fill: 0xFFFFFF }); globalNumberText.anchor.set(0.5, 0); globalNumberText.x = tile.x; globalNumberText.y = tile.y + 80; // Position below the tile game.addChild(globalNumberText); // Store reference to remove it later tile.globalNumberText = globalNumberText; } } // Select tile function selectTile(tile) { if (gameState !== 'selectTile' || currentPlayer !== 0) { return; } if (selectedTile) { selectedTile.setSelected(false); } selectedTile = tile; tile.setSelected(true); gameState = 'placeTile'; updateTurnOrderDisplay(); instructionTxt.setText('Click to place tile on your kingdom'); LK.getSound('selectSound').play(); } // AI turn function aiTurn() { if (currentPlayer === 0) { return; } // Prevent user interaction during AI turn gameState = 'aiTurn'; updateTurnOrderDisplay(); // AI selects random available tile var availableTiles = []; for (var i = 0; i < currentTiles.length; i++) { if (!currentTiles[i].selected) { availableTiles.push(currentTiles[i]); } } if (availableTiles.length > 0) { var randomTile = availableTiles[Math.floor(Math.random() * availableTiles.length)]; selectedTile = randomTile; randomTile.setSelected(true); // Mark tile as owned by current AI player to prevent user interaction randomTile.ownerPlayer = currentPlayer; instructionTxt.setText('AI Player ' + currentPlayer + ' selecting tile...'); LK.getSound('selectSound').play(); // Delay before placing tile LK.setTimeout(function () { // AI places tile randomly with rotation attempts var kingdom = kingdoms[currentPlayer]; var placed = false; for (var attempts = 0; attempts < 200 && !placed; attempts++) { var row = Math.floor(Math.random() * 5); var col = Math.floor(Math.random() * 4); // Try different rotations for (var rot = 0; rot < 4 && !placed; rot++) { // Set rotation internally without visual update var originalRotation = selectedTile.currentRotationAngle; selectedTile.currentRotationAngle = rot * 90; if (kingdom.canPlaceTile(selectedTile, row, col)) { // Update visuals only when placing selectedTile.updateTileVisuals(); kingdom.placeTile(selectedTile, row, col); placed = true; } else { // Restore original rotation if placement failed selectedTile.currentRotationAngle = originalRotation; } } } // If tile couldn't be placed, try moving kingdom if (!placed) { var directions = ['up', 'down', 'left', 'right']; for (var d = 0; d < directions.length && !placed; d++) { if (kingdom.canMoveKingdom(directions[d])) { var oldHasMoved = kingdom.hasMoved; kingdom.moveKingdom(directions[d]); if (!oldHasMoved) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); } // Try placing again after movement for (var attempts2 = 0; attempts2 < 100 && !placed; attempts2++) { var row = Math.floor(Math.random() * 5); var col = Math.floor(Math.random() * 4); for (var rot = 0; rot < 4 && !placed; rot++) { var originalRotation = selectedTile.currentRotationAngle; selectedTile.currentRotationAngle = rot * 90; if (kingdom.canPlaceTile(selectedTile, row, col)) { selectedTile.updateTileVisuals(); kingdom.placeTile(selectedTile, row, col); placed = true; } else { selectedTile.currentRotationAngle = originalRotation; } } } } } } if (placed) { selectedTiles.push({ tile: selectedTile, player: currentPlayer }); // Remove tile from display selectedTile.parent.removeChild(selectedTile); // Also remove the global number text if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) { selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText); } selectedTile = null; LK.getSound('placeSound').play(); } else { // AI couldn't place tile even after trying to move, trash it kingdom.score = Math.max(0, kingdom.calculateScore() - 5); selectedTiles.push({ tile: selectedTile, player: currentPlayer }); selectedTile.parent.removeChild(selectedTile); if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) { selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText); } selectedTile = null; LK.getSound('placeSound').play(); } instructionTxt.setText('AI Player ' + currentPlayer + ' placed tile'); LK.setTimeout(function () { nextPlayer(); }, 1000); }, 1000); } } // Next player function nextPlayer() { // Check if all 4 players have selected tiles in this round if (selectedTiles.length === 4) { // All players finished, start new round round++; if (round > maxRounds) { endGame(); return; } // Update turn order based on selected tiles selectedTiles.sort(function (a, b) { return a.tile.number - b.tile.number; }); turnOrder = []; for (var i = 0; i < selectedTiles.length; i++) { turnOrder.push(selectedTiles[i].player); } selectedTiles = []; currentPlayer = turnOrder[0]; drawCurrentTiles(); scoreTxt.setText('Round: ' + round); updateTurnOrderDisplay(); if (currentPlayer === 0) { gameState = 'selectTile'; instructionTxt.setText('Select a tile'); } else { LK.setTimeout(aiTurn, 500); } } else { // Move to next player in current round var currentTurnIndex = turnOrder.indexOf(currentPlayer); var nextTurnIndex = (currentTurnIndex + 1) % 4; currentPlayer = turnOrder[nextTurnIndex]; updateTurnOrderDisplay(); if (currentPlayer !== 0) { LK.setTimeout(aiTurn, 500); } else { gameState = 'selectTile'; instructionTxt.setText('Select a tile'); } } } // End game function endGame() { gameState = 'gameOver'; // Calculate final scores var finalScores = []; for (var i = 0; i < kingdoms.length; i++) { // Use stored score for human player (includes penalties), calculate for AI var finalScore = i === 0 ? kingdoms[i].score : kingdoms[i].calculateScore(); finalScores.push({ player: i, score: finalScore }); } finalScores.sort(function (a, b) { return b.score - a.score; }); var playerRank = 1; for (var i = 0; i < finalScores.length; i++) { if (finalScores[i].player === 0) { playerRank = i + 1; break; } } if (playerRank === 1) { LK.showYouWin(); } else { LK.showGameOver(); } } // Kingdom click handler function handleKingdomClick(x, y) { if (gameState !== 'placeTile' || currentPlayer !== 0 || !selectedTile) { return; } var kingdom = kingdoms[0]; // Convert click coordinates to kingdom local coordinates // Account for kingdom position offset var relativeX = x - kingdom.x; var relativeY = y - kingdom.y; // Calculate grid position based on cell size (125px) var row = Math.floor(relativeY / 125); var col = Math.floor(relativeX / 125); // Ensure coordinates are within valid bounds if (row < 0 || row >= 5 || col < 0 || col >= 5) { return; } // For horizontal tiles, ensure there's space for both cells if ((selectedTile.currentRotationAngle === 0 || selectedTile.currentRotationAngle === 180) && col >= 4) { col = 3; // Ensure tile fits horizontally } // For vertical tiles, ensure there's space for both cells if ((selectedTile.currentRotationAngle === 90 || selectedTile.currentRotationAngle === 270) && row >= 4) { row = 3; // Ensure tile fits vertically } if (kingdom.canPlaceTile(selectedTile, row, col)) { kingdom.placeTile(selectedTile, row, col); selectedTiles.push({ tile: selectedTile, player: currentPlayer }); // Remove tile from game selectedTile.parent.removeChild(selectedTile); // Also remove the global number text if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) { selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText); } selectedTile = null; LK.getSound('placeSound').play(); gameState = 'waitingForOthers'; instructionTxt.setText('Wait for other players...'); // Update score playerScoreTxt.setText('Your Score: ' + kingdom.calculateScore()); nextPlayer(); } } // Game move handler for dragging game.move = function (x, y, obj) { if (draggedTile && draggedTile.isDragging) { draggedTile.x = x; draggedTile.y = y; } }; // Game up handler for dropping tiles game.up = function (x, y, obj) { if (draggedTile && draggedTile.isDragging) { draggedTile.isDragging = false; // Try to place tile on kingdom handleKingdomClick(x, y); draggedTile = null; } }; // Movement button handlers moveUpBtn.down = function () { if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) { var kingdom = kingdoms[0]; if (kingdom.canMoveKingdom('up')) { kingdom.moveKingdom('up'); if (!kingdom.hasMoved) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); } playerScoreTxt.setText('Your Score: ' + kingdom.score); LK.getSound('selectSound').play(); } } }; moveDownBtn.down = function () { if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) { var kingdom = kingdoms[0]; if (kingdom.canMoveKingdom('down')) { kingdom.moveKingdom('down'); if (!kingdom.hasMoved) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); } playerScoreTxt.setText('Your Score: ' + kingdom.score); LK.getSound('selectSound').play(); } } }; moveLeftBtn.down = function () { if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) { var kingdom = kingdoms[0]; if (kingdom.canMoveKingdom('left')) { kingdom.moveKingdom('left'); if (!kingdom.hasMoved) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); } playerScoreTxt.setText('Your Score: ' + kingdom.score); LK.getSound('selectSound').play(); } } }; moveRightBtn.down = function () { if (currentPlayer === 0 && (gameState === 'selectTile' || gameState === 'placeTile')) { var kingdom = kingdoms[0]; if (kingdom.canMoveKingdom('right')) { kingdom.moveKingdom('right'); if (!kingdom.hasMoved) { kingdom.score = Math.max(0, kingdom.calculateScore() - 10); } playerScoreTxt.setText('Your Score: ' + kingdom.score); LK.getSound('selectSound').play(); } } }; // Trash button handler trashBtn.down = function () { if (currentPlayer === 0 && gameState === 'placeTile' && selectedTile) { // Remove tile and deduct points var kingdom = kingdoms[0]; kingdom.score = Math.max(0, kingdom.calculateScore() - 5); playerScoreTxt.setText('Your Score: ' + kingdom.score); // Remove tile from display selectedTile.parent.removeChild(selectedTile); if (selectedTile.globalNumberText && selectedTile.globalNumberText.parent) { selectedTile.globalNumberText.parent.removeChild(selectedTile.globalNumberText); } selectedTiles.push({ tile: selectedTile, player: currentPlayer }); selectedTile = null; LK.getSound('placeSound').play(); gameState = 'waitingForOthers'; instructionTxt.setText('Wait for other players...'); nextPlayer(); } }; // Game event handlers game.down = function (x, y, obj) { if (gameState === 'placeTile' && currentPlayer === 0 && !draggedTile) { handleKingdomClick(x, y); } }; game.update = function () { // Game update logic handled by event system and timeouts }; // Initialize game initializeTileDeck(); initializeKingdoms(); drawCurrentTiles(); // Start with human player gameState = 'selectTile'; updateTurnOrderDisplay(); instructionTxt.setText('Select a tile');
===================================================================
--- original.js
+++ change.js
@@ -205,9 +205,9 @@
}
if (!adjacent) {
return false;
}
- // Check terrain matching - need at least two matching adjacent terrains
+ // Check terrain matching - need at least one matching adjacent terrain
var validConnections = 0;
for (var p = 0; p < positions.length; p++) {
var r = positions[p][0];
var c = positions[p][1];
@@ -229,9 +229,9 @@
}
}
}
}
- return validConnections >= 2;
+ return validConnections >= 1;
};
self.getTilePositions = function (tile, row, col) {
var positions;
if (tile.currentRotationAngle === 0) {
טחנת דגן בלב שדה חיטה עם רקע צהוב. In-Game asset. 2d. High contrast. No shadows
כתר בעל קווי מתאר שחורים. In-Game asset. 2d. High contrast. No shadows
יער מלא בעצים. In-Game asset. 2d. High contrast. No shadows
מכרה זהב עם רקע כהה. In-Game asset. 2d. High contrast. No shadows
ים עם אי בודד במרכזו. In-Game asset. 2d. High contrast. No shadows
מרעה ירוק עם דיר קטן במרכזו. In-Game asset. 2d. High contrast. No shadows
ביצה טובענית בצבעי חום. In-Game asset. 2d. High contrast. No shadows
טירה אפורה. In-Game asset. 2d. High contrast. No shadows
שקיעה ירוקה עם צבעים כהים למעלה וכהים למטה, למטה זה עצים ולמעלה הרים, השמש לא רואים אותה באמצע, ציורי ופסטורלי מהאגדות. In-Game asset. 2d. High contrast. No shadows
ריבוע חלול עם קו מתאר חום. In-Game asset. 2d. High contrast. No shadows
תמונה מלבנית בצבע שמנת ביחס 2 על1 ממוסגרת עם מסגרת דקה בצבע חום. In-Game asset. 2d. High contrast. No shadows
אדמה חולית בצורת ריבוע בצבע צהוב עם פינות מעוגלות. In-Game asset. 2d. High contrast. No shadows