UNPKG

bacsim

Version:
954 lines (917 loc) 29 kB
/* eslint-disable */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var marga = require('marga'); var cardation = require('cardation'); var tsCustomError = require('ts-custom-error'); const defaultGameRules = { isNoCommision: false, isSuperSixSupported: true, }; const defaultPayoutTable = { banker: { nocommission: { normal: 1, six: .5, }, traditional: .95, }, player: 1, tie: 8, superSix: { two: 12, three: 20, }, pair: { bankerPair: 11, playerPair: 11, eitherPair: 5, perfectPair: { either: 25, both: 250, }, }, big: .54, small: 1.5, }; const defaultConfig = { gameRules: defaultGameRules, payoutTable: defaultPayoutTable, shouldDetectShoe: false, isTryrun: false, shouldCutShoe: true, shouldUseBlackCard: true, shouldBurnCard: true, shouldShuffle: true, shouldGenerateRoad: true, shouldGenerateSmallRoad: false, shouldGenerateOtherRoad: false, shouldShuffleWhileCollectBankerHand: true, }; class Tag { } class Natural extends Tag { score; combinaiton = []; constructor(score) { super(); this.score = score; } } class BankerNatural extends Natural { } class PlayerNatural extends Natural { } const heart = new cardation.Heart(); const diamond = new cardation.Diamond(); const spade = new cardation.Spade(); const club = new cardation.Club(); class BaccaratDeck extends cardation.Deck { _isInitialized = false; _addCard(card) { const protectModel = Object.freeze || Object.seal; this.pushCard(protectModel(card)); } constructor() { super(); this.getOrCreatArray(); } getOrCreatArray() { if (this._isInitialized) { return this.getDuplicatedCardArray(); } this._isInitialized = true; const deckArray = this.getDuplicatedCardArray(); if (deckArray.length) { return [...deckArray]; } this._addCard(cardation.CardFactory.createAceCard(heart, 1)); this._addCard(cardation.CardFactory.createAceCard(diamond, 1)); this._addCard(cardation.CardFactory.createAceCard(spade, 1)); this._addCard(cardation.CardFactory.createAceCard(club, 1)); for (let i = 2; i < 11; i++) { const score = i % 10; this._addCard(cardation.CardFactory.createNumberCard(heart, i, score)); this._addCard(cardation.CardFactory.createNumberCard(diamond, i, score)); this._addCard(cardation.CardFactory.createNumberCard(spade, i, score)); this._addCard(cardation.CardFactory.createNumberCard(club, i, score)); } for (let i = 11; i < 14; i++) { this._addCard(cardation.CardFactory.createFaceCard(heart, i, 0)); this._addCard(cardation.CardFactory.createFaceCard(diamond, i, 0)); this._addCard(cardation.CardFactory.createFaceCard(spade, i, 0)); this._addCard(cardation.CardFactory.createFaceCard(club, i, 0)); } return this.getDuplicatedCardArray(); } detect() { let result = this.getDuplicatedCardArray.length === 52; result = result && this.includes(cardation.CardFactory.createAceCard(heart, 1)) && this.includes(cardation.CardFactory.createAceCard(diamond, 1)) && this.includes(cardation.CardFactory.createAceCard(spade, 1)) && this.includes(cardation.CardFactory.createAceCard(club, 1)); if (!result) { return result; } for (let i = 11; i < 14; i++) { result = result && this.includes(cardation.CardFactory.createFaceCard(heart, i, 0)) && this.includes(cardation.CardFactory.createFaceCard(diamond, i, 0)) && this.includes(cardation.CardFactory.createFaceCard(spade, i, 0)) && this.includes(cardation.CardFactory.createFaceCard(club, i, 0)); } if (!result) { return result; } for (let i = 11; i < 14; i++) { result = result && this.includes(cardation.CardFactory.createFaceCard(heart, i, 0)) && this.includes(cardation.CardFactory.createFaceCard(diamond, i, 0)) && this.includes(cardation.CardFactory.createFaceCard(spade, i, 0)) && this.includes(cardation.CardFactory.createFaceCard(club, i, 0)); } return result; } } class BaccaratShoe extends cardation.Shoe { _isBurnt = false; _index = -1; increaseShoeIndex() { this._index++; } detect() { return true; } burn() { if (this._isBurnt) ; this._isBurnt = true; const [firstCard] = this.deal(); const score = firstCard.getCardScore() | 10; const burntCards = this.deal(score); burntCards.unshift(firstCard); return burntCards; } insertBlackCard(place) { this.insertCard(place, blackCard); } getShoeIndex() { return this._index; } resetShoeIndex() { this._index = -1; } shuffle() { super.shuffle(); this.increaseShoeIndex(); } } const blackCard = new cardation.BlackMarkerCard(); const samael$1 = require('samael'); class RecycleShoe extends cardation.Shoe { collect(hand, shouldShuffle = false) { const fristcard = hand.getFirstCard(); if (shouldShuffle && fristcard && this.getDuplicatedCardArray().length > 20) { const action = fristcard.getCardPoint() % 4; if (action === 1) { const randomPlace = samael$1.randomInt(0, this.getDuplicatedCardArray().length - 1); this.insertCard(randomPlace, ...hand.getDuplicatedCardArray()); } else { this.pushCard(...hand.getDuplicatedCardArray()); } } else { this.pushCard(...hand.getDuplicatedCardArray()); } hand.clear(); } } class Pair$1 extends Tag { score = 0; cardId = ""; constructor(score, cardId) { super(); this.score = score; this.cardId = cardId; } } class BankerPair extends Pair$1 { } class PlayerPair extends Pair$1 { } class EngineError extends tsCustomError.CustomError { constructor(message) { super(message); this.message = "[baccarat-engine]" + message; } } class Mun { } class SuperSix$1 extends Mun { } var Result; (function (Result) { Result["BankerWins"] = "_BankerWins"; Result["PlayerWins"] = "_PlayerWins"; Result["Tie"] = "_Tie"; })(Result || (Result = {})); class HandResult { static BankerWins = new HandResult(1); static PlayerWins = new HandResult(-1); static Tie = new HandResult(0); static isOpposite(foo, bar) { return foo._result != bar._result; } static isIdentical(foo, bar) { return foo._result == bar._result; } static getOpposite(foo) { if (foo._result == Result.BankerWins) { return HandResult.PlayerWins; } if (foo._result == Result.PlayerWins) { return HandResult.BankerWins; } return foo; } _result; constructor(code) { if (code === 0) { this._result = Result.Tie; } else if (code === 1) { this._result = Result.BankerWins; } else { this._result = Result.PlayerWins; } } } class Banker extends Mun { } class Player extends Mun { } class Free extends Mun { } class Tie extends Mun { } class HandOutcome { static getPayout(bet, outcome, config) { const { gameRules, payoutTable } = config; if (!gameRules || !payoutTable) { throw new EngineError(`[HandOutcome][getPayout]: gameRules and payoutTable must be configured!`); } const mun = bet.getMun(); const wager = bet.getWager(); if (mun instanceof Free) { return 0; } else if (mun instanceof Banker) { if (outcome.result === HandResult.BankerWins) { if (!gameRules.isNoCommision) { return wager + wager * payoutTable.banker.traditional; } if (outcome.bankerHand.getScore() === 6) { return wager + wager * payoutTable.banker.nocommission.six; } else { return wager + wager * payoutTable.banker.nocommission.normal; } } else if (outcome.result === HandResult.PlayerWins) { return 0; } return wager; } else if (mun instanceof Player) { if (outcome.result === HandResult.PlayerWins) { return wager + wager * payoutTable.player; } else if (outcome.result === HandResult.BankerWins) { return 0; } return wager; } else if (mun instanceof Tie) { if (outcome.result === HandResult.Tie) { return wager + wager * payoutTable.tie; } else { return 0; } } else if (mun instanceof SuperSix$1) { if (outcome.result === HandResult.BankerWins && outcome.bankerHand.getScore() === 6) { return wager + wager * payoutTable.superSix.two; } return 0; } return wager; } _shoeIndex; _payout; handIndex; _prevHandOutcome; _nextHandOutcome; _wager; result; tagArray = []; playerHand; bankerHand; constructor(result, wager, payout, bCardArray, pCardArray, shoeIndex, hindex) { this.result = result; this._wager = wager; this._payout = payout; this.bankerHand = new cardation.Hand(bCardArray); this.playerHand = new cardation.Hand(pCardArray); this._shoeIndex = shoeIndex; this.handIndex = hindex; } setPreviousHandOutcome(handcomeout) { this._prevHandOutcome = handcomeout; handcomeout.setNextHandOutcome(this); } getPreviousHandOutcome() { return this._prevHandOutcome; } setWager(wager) { this._wager = wager; } setPayout(payout) { this._payout = payout; } setNextHandOutcome(handcomeout) { this._nextHandOutcome = handcomeout; } getNextHandOutcome() { return this._nextHandOutcome; } getPayout() { return this._payout; } getWager() { return this._wager; } addTag(tag) { this.tagArray.push(tag); } getShoeIndex() { return this._shoeIndex; } } class ShoeOutcome { _shoeIndex; _prevShoeOutcome; _lastHandOutcome; _firstHandOutcome; _beadRoad; _bigRoad; _gameComeoutMap = new Map(); _handAmount; _statistics = { banker: 0, player: 0, tie: 0, }; constructor(shoeIndex, lastHandComeout, handAmount) { this._shoeIndex = shoeIndex; this._lastHandOutcome = lastHandComeout; this._handAmount = handAmount; this._beadRoad = new marga.BeadRoad(shoeIndex); this._bigRoad = new marga.BigRoad(shoeIndex); } setPreviousShoeOutcome(handcomeout) { this._prevShoeOutcome = handcomeout; } getPreviousShoeOutcome() { return this._prevShoeOutcome; } getShoeIndex() { return this._shoeIndex; } getLastHandOutcome() { return this._lastHandOutcome; } getStatisticInfo() { return this._statistics; } setComeoutMap(hcomeoutMap) { this._gameComeoutMap = hcomeoutMap; } getOutcomeMap() { return this._gameComeoutMap; } setStatisticInfo(banker, player, tie) { this._statistics = { banker: banker, player: player, tie: tie, }; } setFirstHandComeout(firstcomeout) { this._firstHandOutcome = firstcomeout; } getFirstHandComeout() { return this._firstHandOutcome; } setBeadRoad(beadRoad) { this._beadRoad = beadRoad; } getBeadRoad() { return this._beadRoad; } setBigRoad(road) { this._bigRoad = road; } getBigRoad() { return this._bigRoad; } } class Gamer { _hand = new cardation.Hand(); getScore() { return this.getHand().getScore(); } getHand() { return this._hand; } getLastCard() { if (!this.getHand().getDuplicatedCardArray().length) { throw new EngineError(`[Role][getLastCard]: there's no last card because the hand is empty!`); } return this.getHand().getLastCard(); } acceptCard(card) { this._hand.pushCard(card); } } class PlayerGamer extends Gamer { } class BankerGamer extends Gamer { } class SuperSix extends Tag { withCards = 2; constructor(cardAmount) { super(); this.withCards = cardAmount; } } class Bet { _amount; _mun; _outcome; _prev = undefined; constructor(mun, wager) { this._mun = mun; this._amount = wager; } getWager() { return this._amount; } getMun() { return this._mun; } getOutcome() { return this._outcome; } getStr() { const mun = this.getMun(); const houtcome = this.getOutcome(); let result = ''; let sign = 0; if (mun instanceof Banker) { result = "B "; if (houtcome.result === HandResult.BankerWins) { sign = 1; } else if (houtcome.result === HandResult.PlayerWins) { sign = -1; } } else if (mun instanceof Player) { result = "P "; if (houtcome.result === HandResult.PlayerWins) { sign = 1; } else if (houtcome.result === HandResult.BankerWins) { sign = -1; } } if (sign === 0) { result += "0"; } else { result += `${sign < 0 ? '-' : '+'}${this.getWager()}`; } return result; } setOutcome(value) { this._outcome = value; } getPreviousBet() { return this._prev; } setPreviousBet(prev) { this._prev = prev; } gotWon() { const hcomeout = this.getOutcome(); if (!hcomeout) { throw new EngineError(`[Bet][gotWon]: hcomeout could not be undefined!`); } let result = false; const mun = this.getMun(); if (mun instanceof Banker) { if (hcomeout.result === HandResult.BankerWins) { result = true; } else if (hcomeout.result === HandResult.PlayerWins) { result = false; } } else if (mun instanceof Player) { if (hcomeout.result === HandResult.PlayerWins) { result = true; } else if (hcomeout.result === HandResult.BankerWins) { result = false; } } return result; } gotTie() { if (this.getOutcome()?.result === HandResult.Tie) { return true; } return false; } } const samael = require('samael'); let muuuuuu; class Engine { _player = new PlayerGamer(); _banker = new BankerGamer(); _totalGames = 0; _shoe = new BaccaratShoe(); _prevHandOutcome; _prevBet; _config = defaultConfig; _handIndex = -1; _recycleShoe = new RecycleShoe(); _isExhausted = false; _hasShutdown = false; _hasShoeCustomised = false; get isShoeExhausted() { return this._isExhausted; } set isShoeExhausted(value) { this._isExhausted = value; } shutdown() { console.log(`[baccarat-engine]: ${this._totalGames} games within ${this.getShoe().getShoeIndex() + 1} shoes have been played.`); this.isShoeExhausted = true; this._hasShutdown = true; } powerOn(config = defaultConfig) { this.config(config); this._hasShutdown = false; this.initializeDecks(); } config(config) { const mixin = Object.assign({}, this._config, config); this._config = mixin; } initializeDecks() { this._shoe.clear(); if (this._config.customizedShoe) { if (!this._hasShoeCustomised) { this.getShoe().pushCard(...this._config.customizedShoe); this._hasShoeCustomised = true; } } else { for (let i = 0; i < 8; i++) { this.getShoe().pushDeck(new BaccaratDeck()); } } } playOneShoe(beforeBet = () => { return new Bet(new Free(), 0); }, afterBet = () => { }) { if (this._hasShutdown) { throw new EngineError(`[Engine][playOneShoe]: the engine has been shutdown before some further invoking!`); } if (this._shoe.getDuplicatedCardArray().length < 6) { throw new EngineError(`[Engine][playOneShoe]: card left in the shoe should not be less than 6!`); } if (this._config.isTryrun) ; this.prepareShoe(); const hcomeoutMap = new Map(); let houtcome; let firstcomeout; let totalBankker = 0; let totalPlayer = 0; let totalTie = 0; const beadRoad = new marga.BeadRoad(this.getShoe().getShoeIndex()); do { const bet = beforeBet(this.getPreviousBet(), this.getPreviousHandOutcome()); const mun = bet.getMun(); muuuuuu = mun; if (!(mun instanceof Free)) { this._prevBet = bet; } else { this._prevBet = bet; } houtcome = this.playOneHand(); if (this.getShoe().getDuplicatedCardArray().length < 6) { this.isShoeExhausted = true; } hcomeoutMap.set(houtcome.handIndex, houtcome); if (!firstcomeout) { firstcomeout = houtcome; } if (!(mun instanceof Free)) { bet.setOutcome(houtcome); } const payout = HandOutcome.getPayout(bet, houtcome, this._config); houtcome.setWager(bet.getWager()); houtcome.setPayout(payout); if (houtcome.result === HandResult.BankerWins) { totalBankker++; } else if (houtcome.result === HandResult.PlayerWins) { totalPlayer++; } else { totalTie++; } if (this._config.shouldGenerateRoad) { const beadEntity = this._parseComeout2BeadEntity(houtcome); beadRoad.addEntity(beadEntity); } afterBet?.(houtcome); } while (!this.isShoeExhausted); const result = new ShoeOutcome(this.getShoe().getShoeIndex(), houtcome, 3); result.setStatisticInfo(totalBankker, totalPlayer, totalTie); result.setFirstHandComeout(firstcomeout); if (this._config.shouldGenerateRoad) { result.setBeadRoad(beadRoad); result.setBigRoad(marga.BigRoad.from(beadRoad)); } result.setComeoutMap(hcomeoutMap); this.recycleCardToShoe(); return result; } _parseComeout2BeadEntity(hcomeout) { let bead; if (hcomeout.result === HandResult.BankerWins) { bead = new marga.RedBeadEntity(hcomeout.handIndex); } else if (hcomeout.result === HandResult.PlayerWins) { bead = new marga.BlueBeadEntity(hcomeout.handIndex); } else { bead = new marga.GreenBeadEntity(hcomeout.handIndex); } return bead; } recycleCardToShoe() { this.getShoe().pushCard(...this.getRecycleShoe().getDuplicatedCardArray()); this.getRecycleShoe().clear(); } prepareShoe() { const shoe = this.getShoe(); this.resetGameIndex(); this._prevHandOutcome = undefined; if (this._config.shouldShuffle) { shoe.shuffle(); } if (this._config.shouldDetectShoe) { shoe.detect(); } if (this._config.shouldCutShoe) { shoe.cut(samael.randomInt(270)); } if (this._config.shouldUseBlackCard) { this.insertBlackCard(); } if (this._config.shouldUseBlackCard) { const burntCards = shoe.burn(); this.getRecycleShoe().collect(new cardation.Hand(burntCards), false); } this.isShoeExhausted = false; } resetGameIndex() { this._handIndex = -1; } insertBlackCard() { const shoe = this.getShoe(); const cutPlace = samael.randomInt(280, 410); shoe.cut(cutPlace); const blackPlace = samael.randomInt(12, 20); shoe.insertBlackCard(blackPlace); } playOneHand() { const banker = this.getBanker(); const player = this.getPlayer(); const shoe = this.getShoe(); if (this._hasShutdown) { throw new EngineError(`[Engine][playOneHand]: the engine has been shutdown before some further invoking!`); } if (this.isShoeExhausted) { throw new EngineError(`[Engine][playOneHand]: method playOneHand could not be avoked when shoe is exhausted!`); } this.increaseGameIndex(); this.playerDraw(); this.bankerDraw(); this.playerDraw(); this.bankerDraw(); let bankerScore_num = banker.getScore(); let playerScore_num = player.getScore(); if (playerScore_num < 8 && bankerScore_num < 8) { if (this.shouldPlayerDraw(playerScore_num)) { this.playerDraw(); } const hasPlayerHit = player.getHand().getDuplicatedCardArray().length > 2; if (this.shouldBankerDraw(hasPlayerHit, bankerScore_num, banker.getLastCard().getCardScore())) { this.bankerDraw(); } } const bankerHand = banker.getHand(); const playerHand = player.getHand(); bankerScore_num = banker.getScore(); playerScore_num = player.getScore(); let winning; if (muuuuuu instanceof Banker && bankerScore_num < -1) { bankerScore_num += 3; } if (bankerScore_num - playerScore_num > 0) { winning = HandResult.BankerWins; } else if (bankerScore_num - playerScore_num === 0) { winning = HandResult.Tie; } else { winning = HandResult.PlayerWins; } const outcome = new HandOutcome(winning, 0, 0, bankerHand.getDuplicatedCardArray(), playerHand.getDuplicatedCardArray(), shoe.getShoeIndex(), this.getGameIndex()); this._parseTage(outcome); this.getRecycleShoe().collect(banker.getHand(), this._config.shouldShuffleWhileCollectBankerHand); this.getRecycleShoe().collect(player.getHand(), false); if (this._prevHandOutcome && outcome.getShoeIndex() === this._prevHandOutcome.getShoeIndex()) { outcome.setPreviousHandOutcome(this._prevHandOutcome); } this._prevHandOutcome = outcome; return outcome; } _parseTage(outcome) { const { bankerHand } = outcome; const { playerHand } = outcome; const bankerArray = bankerHand.getDuplicatedCardArray(); const playerArray = playerHand.getDuplicatedCardArray(); if (bankerArray[0].equals(bankerArray[1])) { outcome.addTag(new BankerPair(bankerArray[0].getCardScore(), bankerArray[0].getCardId())); } if (playerArray[0].equals(playerArray[1])) { outcome.addTag(new PlayerPair(playerArray[0].getCardScore(), playerArray[0].getCardId())); } if (bankerHand.getScore() > 7) { outcome.addTag(new BankerNatural(bankerHand.getScore())); } if (playerHand.getScore() > 7) { outcome.addTag(new PlayerNatural(playerHand.getScore())); } if (outcome.result == HandResult.BankerWins) { if (bankerHand.getScore() === 6) { outcome.addTag(new SuperSix(bankerArray.length)); } } } getRecycleShoe() { return this._recycleShoe; } playerDraw() { let [card] = this.getShoe().deal(); if (card instanceof cardation.BlackMarkerCard) { this.isShoeExhausted = true; [card] = this.getShoe().deal(); } this.getPlayer().acceptCard(card); } bankerDraw() { let [card] = this.getShoe().deal(); if (card instanceof cardation.BlackMarkerCard) { this.isShoeExhausted = true; [card] = this.getShoe().deal(); } this.getBanker().acceptCard(card); } getShoe() { return this._shoe; } getPreviousHandOutcome() { return this._prevHandOutcome; } getPlayer() { return this._player; } getBanker() { return this._banker; } shouldPlayerDraw(currentScore) { if (currentScore < 6) { return true; } return false; } shouldBankerDraw(playerHit, bankerScore, playerLastScore) { if (!playerHit) { if (bankerScore < 6) { return true; } return false; } if (bankerScore > 6) { return false; } if (bankerScore < 3) { return true; } if (bankerScore === 3) { if (playerLastScore === 8) { return false; } return true; } if (bankerScore === 4) { if (playerLastScore < 2 || playerLastScore > 7) { return false; } return true; } if (bankerScore === 5) { if (playerLastScore < 4 || playerLastScore > 7) { return false; } return true; } if (bankerScore === 6) { if (playerLastScore < 6 || playerLastScore > 7) { return false; } return true; } return false; } getGameIndex() { return this._handIndex; } increaseGameIndex() { this._handIndex++; this._totalGames++; return this._handIndex; } getPreviousBet() { return this._prevBet; } } class Pair extends Mun { } class Participant { } class Dealer extends Participant { } class Gambler extends Participant { } exports.BaccaratDeck = BaccaratDeck; exports.BaccaratShoe = BaccaratShoe; exports.BankerGamer = BankerGamer; exports.BankerMun = Banker; exports.BankerNatural = BankerNatural; exports.BankerPair = BankerPair; exports.Bet = Bet; exports.Dealer = Dealer; exports.Engine = Engine; exports.EngineError = EngineError; exports.FreeMun = Free; exports.Gambler = Gambler; exports.Gamer = Gamer; exports.HandOutcome = HandOutcome; exports.HandResult = HandResult; exports.Mun = Mun; exports.Natural = Natural; exports.Pair = Pair$1; exports.PairMun = Pair; exports.Participant = Participant; exports.PlayerGamer = PlayerGamer; exports.PlayerMun = Player; exports.PlayerNatural = PlayerNatural; exports.PlayerPair = PlayerPair; exports.RecycleShoe = RecycleShoe; exports.ShoeOutcome = ShoeOutcome; exports.SuperSix = SuperSix; exports.SuperSixMun = SuperSix$1; exports.Tag = Tag; exports.TieMun = Tie; exports["default"] = Engine; exports.defaultConfig = defaultConfig; exports.defaultGameRules = defaultGameRules; exports.defaultPayoutTable = defaultPayoutTable; //# sourceMappingURL=index.js.map