User prompt
The game is not detecting pairs well
User prompt
Please fix the bug: 'TypeError: self.getCardLabel is not a function' in or related to this line: 'self.rankText = new Text2(self.getCardLabel(), {' Line Number: 90
Code edit (1 edits merged)
Please save this source code
User prompt
Ultimate Video Poker Challenge
Initial prompt
We are making a video-poker game. In this kind of game the player is initially drawn 5 cards and he can select any of the cards dealt to keep, the other cards being rerolled. His score is based on the final hand he obtains after the reroll based on the classic poker hand ranking (with exact values of each hand I will come back later). This is the hand ranking in order from best to worst: Royal Flush: Ace, King, Queen, Jack, Ten, all of the same suit; Straight Flush: Five cards in sequence, all of the same suit; Four of a Kind: Four cards of the same rank; Full House: Three of a kind combined with a pair; Flush: Five cards of the same suit, not in sequence; Straight: Five cards in sequence, not all of the same suit; Three of a Kind: Three cards of the same rank; Two Pair: Two different pairs; One Pair: Two cards of the same rank; High Card: When no other hand is made, the highest card plays
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Button = Container.expand(function (text, width, height, color) {
var self = Container.call(this);
self.buttonShape = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: width || 300,
height: height || 100,
tint: color || 0x2ecc71
});
self.buttonText = new Text2(text, {
size: 40,
fill: 0xFFFFFF
});
self.buttonText.anchor.set(0.5);
self.addChild(self.buttonText);
self.disable = function () {
self.buttonShape.tint = 0x95a5a6;
self.interactive = false;
};
self.enable = function () {
self.buttonShape.tint = color || 0x2ecc71;
self.interactive = true;
};
// Event handlers
self.down = function (x, y, obj) {
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
if (self.onPress) {
self.onPress();
}
};
return self;
});
var Card = Container.expand(function (suit, rank) {
var self = Container.call(this);
self.suit = suit;
self.rank = rank;
self.isHeld = false;
// Get suit symbol
self.getSuitSymbol = function () {
if (self.suit === 'hearts') {
return '♥';
}
if (self.suit === 'diamonds') {
return '♦';
}
if (self.suit === 'clubs') {
return '♣';
}
if (self.suit === 'spades') {
return '♠';
}
return '';
};
// Get card color
self.getCardColor = function () {
if (self.suit === 'hearts' || self.suit === 'diamonds') {
return "#ff0000";
}
return "#000000";
};
// Get card label
self.getCardLabel = function () {
return self.rank + self.getSuitSymbol();
};
// Front and back of card
self.cardFront = self.attachAsset('cardFront', {
anchorX: 0.5,
anchorY: 0.5
});
self.cardBack = self.attachAsset('cardBack', {
anchorX: 0.5,
anchorY: 0.5
});
self.cardBack.visible = false;
// Hold indicator
self.holdIndicator = self.attachAsset('holdIndicator', {
anchorX: 0.5,
anchorY: 0.5,
y: 85
});
self.holdIndicator.visible = false;
// Card text (suit and rank)
self.rankText = new Text2(self.getCardLabel(), {
size: 40,
fill: self.getCardColor()
});
self.rankText.anchor.set(0.5);
self.rankText.y = -65;
self.addChild(self.rankText);
// Suit symbol in the center
self.suitText = new Text2(self.getSuitSymbol(), {
size: 80,
fill: self.getCardColor()
});
self.suitText.anchor.set(0.5);
self.addChild(self.suitText);
// Hold text
self.holdText = new Text2("HOLD", {
size: 24,
fill: 0x000000
});
self.holdText.anchor.set(0.5);
self.holdText.y = 85;
self.addChild(self.holdText);
self.holdText.visible = false;
// Toggle hold state
self.toggleHold = function () {
self.isHeld = !self.isHeld;
self.holdIndicator.visible = self.isHeld;
self.holdText.visible = self.isHeld;
};
// Get card value for hand evaluations (1-13)
self.getValue = function () {
if (self.rank === 'A') {
return 14;
}
if (self.rank === 'K') {
return 13;
}
if (self.rank === 'Q') {
return 12;
}
if (self.rank === 'J') {
return 11;
}
return parseInt(self.rank);
};
// Event handlers
self.down = function (x, y, obj) {
// Scale down slightly on press
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
// Scale back to normal
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
self.toggleHold();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c6e31
});
/****
* Game Code
****/
// Constants
var CARD_SPACING = 180;
var CARDS_PER_HAND = 5;
var CARD_START_Y = 700;
var DECK_POSITION_X = 300;
var DECK_POSITION_Y = 300;
// Game states
var STATE_DEAL = "deal";
var STATE_PLAYER_TURN = "playerTurn";
var STATE_FINAL = "final";
// Game variables
var deck = [];
var playerHand = [];
var gameState = STATE_DEAL;
var handScore = 0;
var handRank = "";
var highestScore = storage.highestScore || 0;
// Hand rankings and their scores
var handRankings = {
"Royal Flush": 800,
"Straight Flush": 500,
"Four of a Kind": 400,
"Full House": 300,
"Flush": 250,
"Straight": 200,
"Three of a Kind": 100,
"Two Pair": 50,
"Jacks or Better": 10,
"High Card": 0
};
// Create the table
var table = game.addChild(LK.getAsset('table', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Create scoreboard text
var scoreText = new Text2("Score: 0", {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 50;
// Create high score text
var highScoreText = new Text2("High Score: " + highestScore, {
size: 40,
fill: 0xFFFFFF
});
highScoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(highScoreText);
highScoreText.x = -30;
highScoreText.y = 30;
// Create hand rank text
var handRankText = new Text2("", {
size: 60,
fill: 0xFFFFFF
});
handRankText.anchor.set(0.5, 0);
handRankText.y = 150;
LK.gui.top.addChild(handRankText);
// Create draw button
var drawButton = new Button("DEAL", 400, 120);
drawButton.x = 2048 / 2;
drawButton.y = 1300;
game.addChild(drawButton);
// Setup button behavior
drawButton.onPress = function () {
if (gameState === STATE_DEAL) {
startNewGame();
gameState = STATE_PLAYER_TURN;
drawButton.buttonText.setText("DRAW");
} else if (gameState === STATE_PLAYER_TURN) {
drawRemainingCards();
gameState = STATE_FINAL;
drawButton.buttonText.setText("DEAL AGAIN");
} else if (gameState === STATE_FINAL) {
resetGame();
gameState = STATE_DEAL;
}
};
// Initialize deck
function createDeck() {
var suits = ['hearts', 'diamonds', 'clubs', 'spades'];
var ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
var newDeck = [];
for (var s = 0; s < suits.length; s++) {
for (var r = 0; r < ranks.length; r++) {
newDeck.push({
suit: suits[s],
rank: ranks[r]
});
}
}
return newDeck;
}
// Shuffle deck
function shuffleDeck(deck) {
for (var i = deck.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
return deck;
}
// Deal cards to player
function dealCards() {
// Remove old cards from display
for (var i = 0; i < playerHand.length; i++) {
if (playerHand[i] && playerHand[i].parent) {
playerHand[i].parent.removeChild(playerHand[i]);
}
}
// Clear hand
playerHand = [];
// Create new hand
for (var i = 0; i < CARDS_PER_HAND; i++) {
if (deck.length > 0) {
var cardData = deck.pop();
var card = new Card(cardData.suit, cardData.rank);
// Position card
card.x = 2048 / 2 + (i - Math.floor(CARDS_PER_HAND / 2)) * CARD_SPACING;
card.y = CARD_START_Y;
// Add animation
card.alpha = 0;
card.y += 50;
tween(card, {
alpha: 1,
y: CARD_START_Y
}, {
duration: 300,
easing: tween.easeOutQuad,
delay: i * 100
});
playerHand.push(card);
game.addChild(card);
// Play sound
LK.setTimeout(function () {
LK.getSound('cardDeal').play();
}, i * 100);
}
}
}
// Start a new game
function startNewGame() {
deck = createDeck();
shuffleDeck(deck);
dealCards();
handRankText.setText("");
handScore = 0;
updateScore();
}
// Draw new cards to replace non-held cards
function drawRemainingCards() {
for (var i = 0; i < playerHand.length; i++) {
if (!playerHand[i].isHeld && deck.length > 0) {
var cardData = deck.pop();
// Store old card for animation
var oldCard = playerHand[i];
// Create new card
var newCard = new Card(cardData.suit, cardData.rank);
newCard.x = oldCard.x;
newCard.y = oldCard.y;
// Replace old card
game.removeChild(oldCard);
game.addChild(newCard);
playerHand[i] = newCard;
// Animation and sound
newCard.alpha = 0;
newCard.y += 20;
tween(newCard, {
alpha: 1,
y: CARD_START_Y
}, {
duration: 200,
easing: tween.easeOutQuad,
delay: i * 50
});
LK.setTimeout(function () {
LK.getSound('cardDeal').play();
}, i * 50);
}
}
// Evaluate hand after a short delay
LK.setTimeout(function () {
evaluateHand();
}, 500);
}
// Reset the game for a new round
function resetGame() {
// Clear the board
for (var i = 0; i < playerHand.length; i++) {
if (playerHand[i] && playerHand[i].parent) {
tween(playerHand[i], {
alpha: 0,
y: playerHand[i].y + 50
}, {
duration: 300,
delay: i * 50,
onFinish: function () {
if (this && this.parent) {
this.parent.removeChild(this);
}
}.bind(playerHand[i])
});
}
}
playerHand = [];
handRankText.setText("");
}
// Evaluate the player's hand
function evaluateHand() {
var cardValues = playerHand.map(function (card) {
return {
value: card.getValue(),
suit: card.suit
};
});
// Sort cards by value (descending)
cardValues.sort(function (a, b) {
return b.value - a.value;
});
// Count occurrences of each value
var valueCounts = {};
var suitCounts = {};
for (var i = 0; i < cardValues.length; i++) {
var value = cardValues[i].value;
var suit = cardValues[i].suit;
valueCounts[value] = (valueCounts[value] || 0) + 1;
suitCounts[suit] = (suitCounts[suit] || 0) + 1;
}
// Check for pairs, three of a kind, etc.
var pairs = 0;
var threeOfAKind = false;
var fourOfAKind = false;
var hasPairOfJacksOrBetter = false;
for (var value in valueCounts) {
// Need to convert value from string to number for proper comparison
var numValue = parseInt(value);
if (valueCounts[value] === 2) {
pairs++;
if (numValue >= 11) {
// Jack or better
hasPairOfJacksOrBetter = true;
}
} else if (valueCounts[value] === 3) {
threeOfAKind = true;
} else if (valueCounts[value] === 4) {
fourOfAKind = true;
}
}
// Check for flush
var isFlush = false;
for (var suit in suitCounts) {
if (suitCounts[suit] === 5) {
isFlush = true;
break;
}
}
// Check for straight
var isStraight = false;
if (Object.keys(valueCounts).length === 5) {
// Create an array with just the values for easier checking
var values = cardValues.map(function (c) {
return c.value;
});
// Sort values in ascending order
values.sort(function (a, b) {
return a - b;
});
// Check if all cards are in sequence
var isSequential = true;
for (var i = 0; i < values.length - 1; i++) {
if (values[i] + 1 !== values[i + 1]) {
isSequential = false;
break;
}
}
if (isSequential) {
isStraight = true;
}
// Special case for A-5 straight (where Ace is low)
if (values[0] === 2 && values[1] === 3 && values[2] === 4 && values[3] === 5 && values[4] === 14) {
isStraight = true;
}
}
// Determine hand rank
if (isStraight && isFlush) {
if (cardValues[0].value === 14 && cardValues[1].value === 13 && cardValues[2].value === 12 && cardValues[3].value === 11 && cardValues[4].value === 10) {
handRank = "Royal Flush";
} else {
handRank = "Straight Flush";
}
} else if (fourOfAKind) {
handRank = "Four of a Kind";
} else if (threeOfAKind && pairs === 1) {
handRank = "Full House";
} else if (isFlush) {
handRank = "Flush";
} else if (isStraight) {
handRank = "Straight";
} else if (threeOfAKind) {
handRank = "Three of a Kind";
} else if (pairs === 2) {
handRank = "Two Pair";
} else if (hasPairOfJacksOrBetter) {
handRank = "Jacks or Better";
} else {
handRank = "High Card";
}
// Set score
handScore = handRankings[handRank];
LK.setScore(LK.getScore() + handScore);
// Update high score if needed
if (LK.getScore() > highestScore) {
highestScore = LK.getScore();
storage.highestScore = highestScore;
highScoreText.setText("High Score: " + highestScore);
}
// Display hand rank
handRankText.setText(handRank + " - " + handScore + " points!");
// Update score
updateScore();
// Play win sound if score is positive
if (handScore > 0) {
LK.getSound('win').play();
}
}
// Update the score display
function updateScore() {
scoreText.setText("Score: " + LK.getScore());
}
// Initialize the game
LK.playMusic('bgMusic'); ===================================================================
--- original.js
+++ change.js
@@ -418,11 +418,13 @@
var threeOfAKind = false;
var fourOfAKind = false;
var hasPairOfJacksOrBetter = false;
for (var value in valueCounts) {
+ // Need to convert value from string to number for proper comparison
+ var numValue = parseInt(value);
if (valueCounts[value] === 2) {
pairs++;
- if (value >= 11) {
+ if (numValue >= 11) {
// Jack or better
hasPairOfJacksOrBetter = true;
}
} else if (valueCounts[value] === 3) {
@@ -441,19 +443,29 @@
}
// Check for straight
var isStraight = false;
if (Object.keys(valueCounts).length === 5) {
- var minValue = Math.min.apply(null, cardValues.map(function (c) {
+ // Create an array with just the values for easier checking
+ var values = cardValues.map(function (c) {
return c.value;
- }));
- var maxValue = Math.max.apply(null, cardValues.map(function (c) {
- return c.value;
- }));
- if (maxValue - minValue === 4) {
+ });
+ // Sort values in ascending order
+ values.sort(function (a, b) {
+ return a - b;
+ });
+ // Check if all cards are in sequence
+ var isSequential = true;
+ for (var i = 0; i < values.length - 1; i++) {
+ if (values[i] + 1 !== values[i + 1]) {
+ isSequential = false;
+ break;
+ }
+ }
+ if (isSequential) {
isStraight = true;
}
- // Special case for A-5 straight
- if (cardValues[0].value === 14 && cardValues[1].value === 5 && cardValues[2].value === 4 && cardValues[3].value === 3 && cardValues[4].value === 2) {
+ // Special case for A-5 straight (where Ace is low)
+ if (values[0] === 2 && values[1] === 3 && values[2] === 4 && values[3] === 5 && values[4] === 14) {
isStraight = true;
}
}
// Determine hand rank