Skip to content

Commit

Permalink
Avoid malloc for player hands
Browse files Browse the repository at this point in the history
  • Loading branch information
mhluska committed Aug 4, 2021
1 parent 82e2163 commit 69da5cf
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 66 deletions.
2 changes: 1 addition & 1 deletion src/basic-strategy-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default class BasicStrategyChecker {
return 'N';
}

const allowSplit = hand.player.hands.length < game.settings.maxHandsAllowed;
const allowSplit = hand.player.handsCount < game.settings.maxHandsAllowed;

const { chart: chartGroup } = selectCharts(game.settings);
const chartType = this._chartType(hand, allowSplit);
Expand Down
2 changes: 1 addition & 1 deletion src/cli-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default class CLIRenderer implements Renderer {

if (
this.game.focusedHand.hasPairs &&
this.game.player.hands.length < this.game.settings.maxHandsAllowed
this.game.player.handsCount < this.game.settings.maxHandsAllowed
) {
choices.push('P (split)');
}
Expand Down
42 changes: 22 additions & 20 deletions src/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export default class Game extends EventEmitter {
}

get focusedHand(): Hand {
return this.player.hands[this.state.focusedHandIndex];
return this.player.getHand(this.state.focusedHandIndex);
}

updateSettings(settings: GameSettings): void {
Expand All @@ -113,6 +113,7 @@ export default class Game extends EventEmitter {
this.shoe = this.chainEmitChange(new Shoe({ settings: this.settings }));
this.dealer = this.chainEmitChange(
new Dealer({
handsMax: this.settings.maxHandsAllowed,
debug: this.settings.debug,
strategy: PlayerStrategy.DEALER,
})
Expand All @@ -123,6 +124,7 @@ export default class Game extends EventEmitter {
(_item, index) =>
this.chainEmitChange(
new Player({
handsMax: this.settings.maxHandsAllowed,
balance: this.settings.playerBankroll,
blackjackPayout: this.settings.blackjackPayout,
debug: this.settings.debug,
Expand Down Expand Up @@ -151,7 +153,7 @@ export default class Game extends EventEmitter {
this.emit('create-record', 'hand-result', {
createdAt: Date.now(),
gameId: this.gameId,
dealerHand: this.dealer.hands[0].serialize({ showHidden: true }),
dealerHand: this.dealer.firstHand.serialize({ showHidden: true }),
playerHand: hand.serialize(),
winner,
});
Expand Down Expand Up @@ -226,7 +228,7 @@ export default class Game extends EventEmitter {
this.emit('create-record', 'move', {
createdAt: Date.now(),
gameId: this.gameId,
dealerHand: this.dealer.hands[0].serialize({ showHidden: true }),
dealerHand: this.dealer.firstHand.serialize({ showHidden: true }),
playerHand: this.focusedHand.serialize(),
move: input,
correction: typeof checkerResult === 'object' ? checkerResult.code : null,
Expand Down Expand Up @@ -374,9 +376,9 @@ export default class Game extends EventEmitter {

// Draw card for each player face up again (upcard).
for (const player of this.players) {
for (const hand of player.hands) {
player.eachHand((hand) => {
player.takeCard(this.shoe.drawCard(), { hand });
}
});
}

// Draw card for dealer face down (hole card).
Expand All @@ -387,12 +389,12 @@ export default class Game extends EventEmitter {
// Dealer peeks at the hole card if the upcard is 10 to check blackjack.
if (this.dealer.upcard.value === 10 && this.dealer.holeCard.value === 11) {
this.dealer.cards[0].flip();
this.dealer.hands[0].incrementTotalsForCard(this.dealer.cards[0]);
this.dealer.firstHand.incrementTotalsForCard(this.dealer.cards[0]);

for (const player of this.players) {
for (const hand of player.hands) {
player.eachHand((hand) => {
player.setHandWinner({ winner: 'dealer', hand });
}
});
}

return 'waiting-for-new-game-input';
Expand All @@ -415,7 +417,7 @@ export default class Game extends EventEmitter {
...players: Player[]
): void {
for (const player of players) {
for (const hand of player.hands) {
player.eachHand((hand) => {
const input =
player.isUser && userInput
? userInput
Expand All @@ -429,7 +431,7 @@ export default class Game extends EventEmitter {
if (input === 'ask-insurance') {
player.useChips(amount / 2, { hand });
}
}
});
}
}

Expand All @@ -439,7 +441,7 @@ export default class Game extends EventEmitter {
}

for (const player of this.players) {
for (const hand of player.hands) {
player.eachHand((hand) => {
player.setHandWinner({ winner: 'dealer', hand });

// TODO: Store this in state so we don't have to check it again.
Expand All @@ -454,7 +456,7 @@ export default class Game extends EventEmitter {
player === this.player ? this.betAmount : this.settings.minimumBet
);
}
}
});
}
}

Expand Down Expand Up @@ -503,7 +505,7 @@ export default class Game extends EventEmitter {

if (
input === 'split' &&
player.hands.length < this.settings.maxHandsAllowed
player.handsCount < this.settings.maxHandsAllowed
) {
const newHandCard = hand.removeCard();

Expand Down Expand Up @@ -556,7 +558,7 @@ export default class Game extends EventEmitter {

playNPCHands(...players: Player[]): void {
for (const player of players) {
for (const hand of player.hands) {
player.eachHand((hand) => {
let handFinished = false;

while (!handFinished) {
Expand All @@ -567,7 +569,7 @@ export default class Game extends EventEmitter {
player.getNPCInput(this, hand)
);
}
}
});
}
}

Expand All @@ -580,7 +582,7 @@ export default class Game extends EventEmitter {
);

if (handFinished) {
if (this.state.focusedHandIndex < this.player.hands.length - 1) {
if (this.state.focusedHandIndex < this.player.handsCount - 1) {
this.state.focusedHandIndex += 1;
} else {
return 'play-hands-left';
Expand All @@ -592,7 +594,7 @@ export default class Game extends EventEmitter {

playDealer(): void {
this.dealer.cards[0].flip();
this.dealer.hands[0].incrementTotalsForCard(this.dealer.cards[0]);
this.dealer.firstHand.incrementTotalsForCard(this.dealer.cards[0]);

// Dealer draws cards until they reach 17. However, if all player hands have
// busted, this step is skipped.
Expand All @@ -611,9 +613,9 @@ export default class Game extends EventEmitter {
}

for (const player of this.players) {
for (const hand of player.hands) {
player.eachHand((hand) => {
if (player.handWinner.get(hand.id)) {
continue;
return;
}

if (this.dealer.busted) {
Expand All @@ -625,7 +627,7 @@ export default class Game extends EventEmitter {
} else {
player.setHandWinner({ winner: 'push', hand });
}
}
});
}
}

Expand Down
36 changes: 19 additions & 17 deletions src/hand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,37 @@ export type HandAttributes = {
export default class Hand extends GameObject {
static entity = 'hand';

acesCount!: number;
betAmount!: number;
cardHighTotal!: number;
cardLowTotal!: number;
cards!: Card[];
fromSplit!: boolean;
id: string;
player: Player;
fromSplit: boolean;
betAmount: number;
cardHighTotal: number;
cardLowTotal: number;
acesCount: number;
cards: Card[];

constructor(player: Player, cards: Card[] = []) {
super();

this.reset();

this.id = Utils.randomId();
this.player = player;
this.fromSplit = false;
this.betAmount = 0;
this.cardHighTotal = 0;
this.cardLowTotal = 0;
this.acesCount = 0;
this.cards = [];

for (const card of cards) {
this.takeCard(card);
}
}

reset(): void {
this.acesCount = 0;
this.betAmount = 0;
this.cardHighTotal = 0;
this.cardLowTotal = 0;
this.cards = [];
this.fromSplit = false;
}

takeCard(card: Card, { prepend = false } = {}): void {
card.on('change', () => this.emitChange());

Expand Down Expand Up @@ -85,12 +90,9 @@ export default class Hand extends GameObject {

// TODO: Remove change handler when removing cards.
removeCards(): Card[] {
const cards = this.cards.slice();
this.cards = [];
this.cardHighTotal = 0;
this.cardLowTotal = 0;
this.acesCount = 0;
const cards = this.cards;

this.reset();
this.emitChange();

return cards;
Expand Down
2 changes: 1 addition & 1 deletion src/hi-lo-deviation-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default class HiLoDeviationChecker {
return { correctMove: false };
}

const allowSplit = hand.player.hands.length < game.settings.maxHandsAllowed;
const allowSplit = hand.player.handsCount < game.settings.maxHandsAllowed;
if (correctMove === 'P' && !allowSplit) {
return { correctMove: false };
}
Expand Down
Loading

0 comments on commit 69da5cf

Please sign in to comment.