User prompt
חייב אבל שיהיו שניים זהים צמודים כשבונים. לא באלכסון
User prompt
כאשר מחברים אבן, מספיק שרק אחד הצדדים שלה יתאים לצד שמתחבר. זאת אומרת או שיהיה צמוד לטירה, מאחד מארבע הכיוונים שלה, ואז זה בסדר לא משנה מה מעבר, או שיהיה לו אחד הצדדים צמוד לאבן זהה. נניח יער ליער. ואז אם הצד השני לא מתאים למה שמתחבר, זה עדיין בסדר וחוקי
Code edit (2 edits merged)
Please save this source code
User prompt
תזיז רק את הכותרת של הזזת החצים ימינה
User prompt
תזיז את ארבעת החצים להזזת כל האבנים קצת שמאלה
User prompt
תעשה שהכתר יהיה בצד שמאל למעלה של הריבוע
Code edit (1 edits merged)
Please save this source code
User prompt
הורדת הנקודות על תזוזה היא חד פעמית . פעם ראשונה שהוזז, מורידים 10, מאז ניתן להזיז בלי שירד נקודות
User prompt
Move them another 300px down
User prompt
תזיז את החצים ואת הפח 1000 פיקסלים למטה ו100 פיקסלים ימינה
User prompt
קח את החצים שמזיזים את כל האבנים ואת הפח שאיתו אפשר לזרוק אבן שמאלה 2 פוזישנים מאיפה שהם עכשיו
User prompt
תשים את החצים שמזיזים את כל האבנים ואת הפח שאיתו אפשר לזרוק אבן שנבחרה, למטה
User prompt
תוסיף כפתורים שמאפשרים למשתמש להזיז את כל האבנים שלו בתוך הלוח כולל הממלכה במידת האפשר. כפתור ימינה, יזיז את כל האבנים ימינה במידה והוא לא בנה עד לקצה. כפתור שמאלה יזיז הכל שמאלה. כפתור למעלה ולמטה יזיזו בהתאם במידה וניתן לעשות את זה בלי לצאת מהלוח. במידה והמשתמש עשה את זה, יורד לו 10 נקודות. גם המחשבים, במידה וזה מה שיעזור להם לבנות אבן נוספת, הם יוכלו להזיז את כל האבנים שלהם בתוך הלוח ולאבד 10 נקודות. במידה והמחשב קיבל אבן שאין לו איפה לבנות אותה גם בלי הזזה, הוא שם אותה בפח ומאבד 5 נקודות. המשתמש גם, אם הוא שם אבן בפח, יורד לו 5 נקודות. תוסיף כפתור פח, שאם המשתמש לחץ עליו אחרי שהוא בחר אבן, האבן נזרקת ויורד לו הנקודות
User prompt
הבעיה: הקוד הנוכחי מנסה לסובב את האבן על ידי הזזה ידנית של הרכיבים הפנימיים שלה (חלקי השטח והכתרים) בתוך ה-GameTile (שהוא Container). זו גישה מורכבת ומועדת לשגיאות, מכיוון שכל רכיב צריך להיות מחושב מחדש ביחס למרכז האבן ולזווית החדשה. מערכות גרפיות כמו זו שבה אנו משתמשים (LK, בדומה ל-PixiJS) מתוכננות לטפל בזה בצורה יעילה יותר. הפתרון: במקום להזיז את הרכיבים הפנימיים, יש לסובב את ה-Container של ה-GameTile כולו. כאשר ה-Container מסתובב, כל הילדים שלו (השטחים, הכתרים, וכו') מסתובבים איתו באופן אוטומטי, מה שמפשט מאוד את הלוגיקה. שלבי התיקון המומלצים: במחלקת GameTile: הוסף מאפיין חדש בשם self.currentRotationAngle (לדוגמה) שישמור את זווית הסיבוב הנוכחית במעלות (0, 90, 180, 270). בפונקציה self.rotateTile(): עדכן את self.currentRotationAngle ב-90 מעלות ((self.currentRotationAngle + 90) % 360). הגדר את מאפיין ה-rotation המובנה של ה-GameTile (שהוא Container) באמצעות המרת הזווית לרדיאנים: self.rotation = self.currentRotationAngle * Math.PI / 180;. הסר את כל הלוגיקה הידנית של הזזת leftTerrain, rightTerrain והכתרים מתוך פונקציה זו או מתוך self.updateTileVisuals(), מכיוון שהם יסתובבו אוטומטית. במחלקת Kingdom (בפונקציה self.getTilePositions): ודא שהפונקציה משתמשת ב-tile.currentRotationAngle (הזווית במעלות) כדי לחשב את המיקומים הנכונים של שני חלקי האבן על רשת הממלכה, בהתאם לסיבוב. בלוגיקת הגרירה וההצבה (בפונקציה game.move): כאשר אתה מציג את previewTile, ודא שגם הוא מסובב בהתאם ל-draggedTile.currentRotationAngle (previewTile.rotation = draggedTile.currentRotationAngle * Math.PI / 180;). ודא שמידות ה-previewTile (רוחב/גובה) מתחלפות כאשר האבן מסובבת ב-90 או 270 מעלות (כי האבן משנה את כיוונה). בלוגיקת ה-AI (בפונקציה aiTurn): כאשר ה-AI בודק מיקומי הצבה וסיבובים, ודא שהוא מעדכן את selectedTile.currentRotationAngle לפני קריאה ל-kingdom.canPlaceTile או kingdom.placeTile. יישום השינויים הללו יגרום לסיבוב חלק ונכון של האבנים.
User prompt
הבעיה: הקוד הנוכחי מנסה לסובב את האבן על ידי הזזה ידנית של הרכיבים הפנימיים שלה (חלקי השטח והכתרים) בתוך ה-GameTile (שהוא Container). זו גישה מורכבת ומועדת לשגיאות, מכיוון שכל רכיב צריך להיות מחושב מחדש ביחס למרכז האבן ולזווית החדשה. מערכות גרפיות כמו זו שבה אנו משתמשים (LK, בדומה ל-PixiJS) מתוכננות לטפל בזה בצורה יעילה יותר. הפתרון: במקום להזיז את הרכיבים הפנימיים, יש לסובב את ה-Container של ה-GameTile כולו. כאשר ה-Container מסתובב, כל הילדים שלו (השטחים, הכתרים, וכו') מסתובבים איתו באופן אוטומטי, מה שמפשט מאוד את הלוגיקה. שלבי התיקון המומלצים: במחלקת GameTile: הוסף מאפיין חדש בשם self.currentRotationAngle (לדוגמה) שישמור את זווית הסיבוב הנוכחית במעלות (0, 90, 180, 270). בפונקציה self.rotateTile(): עדכן את self.currentRotationAngle ב-90 מעלות ((self.currentRotationAngle + 90) % 360). הגדר את מאפיין ה-rotation המובנה של ה-GameTile (שהוא Container) באמצעות המרת הזווית לרדיאנים: self.rotation = self.currentRotationAngle * Math.PI / 180;. הסר את כל הלוגיקה הידנית של הזזת leftTerrain, rightTerrain והכתרים מתוך פונקציה זו או מתוך self.updateTileVisuals(), מכיוון שהם יסתובבו אוטומטית. במחלקת Kingdom (בפונקציה self.getTilePositions): ודא שהפונקציה משתמשת ב-tile.currentRotationAngle (הזווית במעלות) כדי לחשב את המיקומים הנכונים של שני חלקי האבן על רשת הממלכה, בהתאם לסיבוב. בלוגיקת הגרירה וההצבה (בפונקציה game.move): כאשר אתה מציג את previewTile, ודא שגם הוא מסובב בהתאם ל-draggedTile.currentRotationAngle (previewTile.rotation = draggedTile.currentRotationAngle * Math.PI / 180;). ודא שמידות ה-previewTile (רוחב/גובה) מתחלפות כאשר האבן מסובבת ב-90 או 270 מעלות (כי האבן משנה את כיוונה). בלוגיקת ה-AI (בפונקציה aiTurn): כאשר ה-AI בודק מיקומי הצבה וסיבובים, ודא שהוא מעדכן את selectedTile.currentRotationAngle לפני קריאה ל-kingdom.canPlaceTile או kingdom.placeTile. יישום השינויים הללו יגרום לסיבוב חלק ונכון של האבנים.
User prompt
מעולה שיציג את המספר מתחת רק פעם אחת. לא צריך פעמיים
User prompt
כל האבנים מסודרות בחבילה מ-1 ועד 48 כל פעם שולפים רנדומלית. אם שלפנו בסביב הראשון את אבנים: 4 , 12, 25, 43 אז יהיה כתוב את המספרים האלה מתחת לאבנים לפי הסדר
User prompt
כל האבנים מסודרות בחבילה מ-1 ועד 48 כל פעם שולפים רנדומלית. אם שלפנו בסביב הראשון את אבנים: 4 , 12, 25, 43 אז יהיה כתוב את המספרים האלה מתחת לאבנים לפי הסדר
User prompt
מתחת לכל אבן דומינו שנשלפה, תכתוב את המספר שלה ביחס לכל האבנים במשחק. לא את המספר שלה ביחס ל-4
User prompt
תיקח את טור האבנים חצי פוזישן למטה ביחס לאיפה שהם עכשיו קח את הלוח של שחקן 1 ושל המשתמש חצי פויזשן שמאלה ביחס לאיפה שהם עכשיו
User prompt
קח את הלוח של מחשבב 1 ושל המשתמש, קצת שמאלה ביחס לאיפה שהם עכשיו קח את טור האבנים שנפתחות קצת למטה
User prompt
המשחק נתקע עם הAI מסובב את האבן לא צריך להראות למשתמש את הסיבוב. רק בחירה, ואז כבר בלוח כמו שהמחשב מחליט
User prompt
אין קשר בין איפה שאני מניח את האבן, לאיפה שהוא שם אותה בפועל
User prompt
FI קרה עכשיו, שאחרי שהמחשב שינה כיוון לאבן האבן הפכה להיות של המשתמש ואז לא היה ניתן להתקדם במשחק בנוסף, הסיבוב לא קורה בצורה טובה, זה מסתובב לזוויות לא הגיוניות
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'fill')' in or related to this line: 'turnOrderTexts[i].style.fill = isCurrentPlayer ? 0x00FF00 : 0xFFFFFF;' Line Number: 494
/**** * 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.isDragging = false; // 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 + i * 15 - 7.5, y: -35, anchorX: 0.5, anchorY: 0.5 })); } for (var i = 0; i < rightCrowns; i++) { self.addChild(LK.getAsset('crown', { x: 60 + i * 15 - 7.5, y: -35, anchorX: 0.5, anchorY: 0.5 })); } // Add number var numberText = self.addChild(new Text2(number.toString(), { size: 30, fill: 0xFFFFFF })); numberText.anchor.set(0.5, 0.5); numberText.x = 0; numberText.y = 70; // 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.rotation = (self.rotation + 90) % 360; self.updateTileVisuals(); }; self.updateTileVisuals = function () { // Update terrain positions based on rotation var leftX, leftY, rightX, rightY; if (self.rotation === 0) { leftX = -60; leftY = 0; rightX = 60; rightY = 0; } else if (self.rotation === 90) { leftX = 0; leftY = -60; rightX = 0; rightY = 60; } else if (self.rotation === 180) { leftX = 60; leftY = 0; rightX = -60; rightY = 0; } else { // 270 leftX = 0; leftY = 60; rightX = 0; rightY = -60; } self.leftTerrain.x = leftX; self.leftTerrain.y = leftY; self.rightTerrain.x = rightX; self.rightTerrain.y = rightY; // Update crowns positions var leftCrownStartX = leftX; var leftCrownStartY = leftY - 35; var rightCrownStartX = rightX; var rightCrownStartY = rightY - 35; // Remove existing crowns and recreate them for (var i = self.children.length - 1; i >= 0; i--) { if (self.children[i].isCrown) { self.removeChild(self.children[i]); } } // Add left crowns for (var i = 0; i < self.leftCrowns; i++) { var crown = self.addChild(LK.getAsset('crown', { x: leftCrownStartX + i * 15 - 7.5, y: leftCrownStartY, anchorX: 0.5, anchorY: 0.5 })); crown.isCrown = true; } // Add right crowns for (var i = 0; i < self.rightCrowns; i++) { var crown = self.addChild(LK.getAsset('crown', { x: rightCrownStartX + i * 15 - 7.5, y: rightCrownStartY, anchorX: 0.5, anchorY: 0.5 })); crown.isCrown = true; } }; 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) { 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; // 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 + c * 15 - 7.5, 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 (except for first tile after castle) var hasNonCastleNeighbor = false; 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') { hasNonCastleNeighbor = true; var terrainIndex = p; var tileType = terrainIndex === 0 ? tile.leftType : tile.rightType; if (self.grid[nr][nc].type !== tileType) { return false; } } } } } return true; }; self.getTilePositions = function (tile, row, col) { var positions; if (tile.rotation === 0) { // Horizontal: left-right if (col >= 4) return null; positions = [[row, col], [row, col + 1]]; } else if (tile.rotation === 90) { // Vertical: top-bottom if (row >= 4) return null; positions = [[row, col], [row + 1, col]]; } else if (tile.rotation === 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.rotation === 0 || tile.rotation === 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 }; }; 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); // 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: 'wheat', rightType: 'wheat', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'wheat', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'wheat', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, // Tiles 9-16: Grassland { leftType: 'grassland', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, // Tiles 17-24: Forest { 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: 'forest', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'forest', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, // Tiles 25-32: Lake { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'lake', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'lake', rightType: 'forest', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'lake', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'grassland', leftCrowns: 1, rightCrowns: 0 }, // Tiles 33-40: Swamp and Mine { leftType: 'swamp', rightType: 'swamp', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'swamp', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'mine', rightType: 'mine', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'mine', rightType: 'grassland', leftCrowns: 0, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'mine', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'grassland', rightType: 'swamp', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'forest', rightType: 'grassland', leftCrowns: 0, rightCrowns: 1 }, { leftType: 'forest', rightType: 'wheat', leftCrowns: 0, rightCrowns: 1 }, // Tiles 41-48: Crown tiles { leftType: 'wheat', rightType: 'forest', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'wheat', rightType: 'lake', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'grassland', rightType: 'lake', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'forest', rightType: 'lake', leftCrowns: 1, rightCrowns: 0 }, { leftType: 'swamp', rightType: 'forest', leftCrowns: 1, rightCrowns: 1 }, { leftType: 'mine', rightType: 'wheat', leftCrowns: 2, rightCrowns: 0 }, { leftType: 'swamp', rightType: 'mine', leftCrowns: 2, rightCrowns: 1 }, { leftType: 'mine', rightType: 'mine', leftCrowns: 3, rightCrowns: 0 }]; // 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 but maintain original numbering 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: i + 1 }); } } // 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 slightly kingdom.x = 1024 - 312 + 50; // Center horizontally (625 width / 2) + 50 right (moved left by 50 more) 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 slightly kingdom.x = 1024 - 312 + 50; // Center horizontally + 50 right (moved left by 50 more) 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]); } } currentTiles = []; // Get 4 tiles and sort them by number var tilesToShow = []; for (var i = 0; i < 4; i++) { if (tileDeck.length > 0) { tilesToShow.push(tileDeck.shift()); } } // Sort tiles by 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 - 500 + i * 250; // Move down and reduce spacing currentTiles.push(tile); game.addChild(tile); } } // 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); 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++) { selectedTile.rotation = rot * 90; selectedTile.updateTileVisuals(); if (kingdom.canPlaceTile(selectedTile, row, col)) { kingdom.placeTile(selectedTile, row, col); placed = true; } } } if (placed) { selectedTiles.push({ tile: selectedTile, player: currentPlayer }); // Remove tile from display selectedTile.parent.removeChild(selectedTile); 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++) { finalScores.push({ player: i, score: kingdoms[i].calculateScore() }); } 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]; var localPos = kingdom.toLocal({ x: x, y: y }); // Account for kingdom scaling (1.0) var row = Math.floor(localPos.y / (125 * kingdom.scaleY)); var col = Math.floor(localPos.x / (125 * kingdom.scaleX)); if (col >= 4) col = 3; // Ensure tile fits 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); 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; } }; // 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');
/****
* 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.isDragging = false;
// 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 + i * 15 - 7.5,
y: -35,
anchorX: 0.5,
anchorY: 0.5
}));
}
for (var i = 0; i < rightCrowns; i++) {
self.addChild(LK.getAsset('crown', {
x: 60 + i * 15 - 7.5,
y: -35,
anchorX: 0.5,
anchorY: 0.5
}));
}
// Add number
var numberText = self.addChild(new Text2(number.toString(), {
size: 30,
fill: 0xFFFFFF
}));
numberText.anchor.set(0.5, 0.5);
numberText.x = 0;
numberText.y = 70;
// 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.rotation = (self.rotation + 90) % 360;
self.updateTileVisuals();
};
self.updateTileVisuals = function () {
// Update terrain positions based on rotation
var leftX, leftY, rightX, rightY;
if (self.rotation === 0) {
leftX = -60;
leftY = 0;
rightX = 60;
rightY = 0;
} else if (self.rotation === 90) {
leftX = 0;
leftY = -60;
rightX = 0;
rightY = 60;
} else if (self.rotation === 180) {
leftX = 60;
leftY = 0;
rightX = -60;
rightY = 0;
} else {
// 270
leftX = 0;
leftY = 60;
rightX = 0;
rightY = -60;
}
self.leftTerrain.x = leftX;
self.leftTerrain.y = leftY;
self.rightTerrain.x = rightX;
self.rightTerrain.y = rightY;
// Update crowns positions
var leftCrownStartX = leftX;
var leftCrownStartY = leftY - 35;
var rightCrownStartX = rightX;
var rightCrownStartY = rightY - 35;
// Remove existing crowns and recreate them
for (var i = self.children.length - 1; i >= 0; i--) {
if (self.children[i].isCrown) {
self.removeChild(self.children[i]);
}
}
// Add left crowns
for (var i = 0; i < self.leftCrowns; i++) {
var crown = self.addChild(LK.getAsset('crown', {
x: leftCrownStartX + i * 15 - 7.5,
y: leftCrownStartY,
anchorX: 0.5,
anchorY: 0.5
}));
crown.isCrown = true;
}
// Add right crowns
for (var i = 0; i < self.rightCrowns; i++) {
var crown = self.addChild(LK.getAsset('crown', {
x: rightCrownStartX + i * 15 - 7.5,
y: rightCrownStartY,
anchorX: 0.5,
anchorY: 0.5
}));
crown.isCrown = true;
}
};
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) {
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;
// 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 + c * 15 - 7.5,
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 (except for first tile after castle)
var hasNonCastleNeighbor = false;
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') {
hasNonCastleNeighbor = true;
var terrainIndex = p;
var tileType = terrainIndex === 0 ? tile.leftType : tile.rightType;
if (self.grid[nr][nc].type !== tileType) {
return false;
}
}
}
}
}
return true;
};
self.getTilePositions = function (tile, row, col) {
var positions;
if (tile.rotation === 0) {
// Horizontal: left-right
if (col >= 4) return null;
positions = [[row, col], [row, col + 1]];
} else if (tile.rotation === 90) {
// Vertical: top-bottom
if (row >= 4) return null;
positions = [[row, col], [row + 1, col]];
} else if (tile.rotation === 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.rotation === 0 || tile.rotation === 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
};
};
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);
// 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: 'wheat',
rightType: 'wheat',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'wheat',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'wheat',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
},
// Tiles 9-16: Grassland
{
leftType: 'grassland',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
},
// Tiles 17-24: Forest
{
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: 'forest',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
},
// Tiles 25-32: Lake
{
leftType: 'lake',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'lake',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'lake',
rightType: 'forest',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'lake',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'grassland',
leftCrowns: 1,
rightCrowns: 0
},
// Tiles 33-40: Swamp and Mine
{
leftType: 'swamp',
rightType: 'swamp',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'swamp',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'mine',
rightType: 'mine',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'mine',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'mine',
leftCrowns: 0,
rightCrowns: 1
}, {
leftType: 'grassland',
rightType: 'swamp',
leftCrowns: 0,
rightCrowns: 1
}, {
leftType: 'forest',
rightType: 'grassland',
leftCrowns: 0,
rightCrowns: 1
}, {
leftType: 'forest',
rightType: 'wheat',
leftCrowns: 0,
rightCrowns: 1
},
// Tiles 41-48: Crown tiles
{
leftType: 'wheat',
rightType: 'forest',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'wheat',
rightType: 'lake',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'grassland',
rightType: 'lake',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'forest',
rightType: 'lake',
leftCrowns: 1,
rightCrowns: 0
}, {
leftType: 'swamp',
rightType: 'forest',
leftCrowns: 1,
rightCrowns: 1
}, {
leftType: 'mine',
rightType: 'wheat',
leftCrowns: 2,
rightCrowns: 0
}, {
leftType: 'swamp',
rightType: 'mine',
leftCrowns: 2,
rightCrowns: 1
}, {
leftType: 'mine',
rightType: 'mine',
leftCrowns: 3,
rightCrowns: 0
}];
// 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 but maintain original numbering
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: i + 1
});
}
}
// 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 slightly
kingdom.x = 1024 - 312 + 50; // Center horizontally (625 width / 2) + 50 right (moved left by 50 more)
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 slightly
kingdom.x = 1024 - 312 + 50; // Center horizontally + 50 right (moved left by 50 more)
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]);
}
}
currentTiles = [];
// Get 4 tiles and sort them by number
var tilesToShow = [];
for (var i = 0; i < 4; i++) {
if (tileDeck.length > 0) {
tilesToShow.push(tileDeck.shift());
}
}
// Sort tiles by 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 - 500 + i * 250; // Move down and reduce spacing
currentTiles.push(tile);
game.addChild(tile);
}
}
// 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);
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++) {
selectedTile.rotation = rot * 90;
selectedTile.updateTileVisuals();
if (kingdom.canPlaceTile(selectedTile, row, col)) {
kingdom.placeTile(selectedTile, row, col);
placed = true;
}
}
}
if (placed) {
selectedTiles.push({
tile: selectedTile,
player: currentPlayer
});
// Remove tile from display
selectedTile.parent.removeChild(selectedTile);
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++) {
finalScores.push({
player: i,
score: kingdoms[i].calculateScore()
});
}
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];
var localPos = kingdom.toLocal({
x: x,
y: y
});
// Account for kingdom scaling (1.0)
var row = Math.floor(localPos.y / (125 * kingdom.scaleY));
var col = Math.floor(localPos.x / (125 * kingdom.scaleX));
if (col >= 4) col = 3; // Ensure tile fits
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);
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;
}
};
// 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');
טחנת דגן בלב שדה חיטה עם רקע צהוב. 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