Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

blackjack-engine

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

blackjack-engine - npm Package Compare versions

Comparing version 0.0.3 to 0.0.4

2

build/engine.d.ts

@@ -22,3 +22,3 @@ import { SideBets, Card, Hand, HandValue, State, Action, Player, SideBetsFromUser } from '../types';

export declare const isLuckyLucky: (playerCards: Card[], dealerCards: Card[]) => boolean;
export declare const getLuckyLuckyMultiplier: (playerCards: Card[], dealerCards: Card[]) => 0 | 10 | 2 | 3 | 200 | 100 | 50 | 30;
export declare const getLuckyLuckyMultiplier: (playerCards: Card[], dealerCards: Card[]) => 10 | 0 | 2 | 3 | 200 | 100 | 50 | 30;
export declare const isPerfectPairs: (playerCards: Card[]) => boolean;

@@ -25,0 +25,0 @@ export declare const getSideBetsInfo: (availableBets: SideBets, sideBets: SideBetsFromUser, playerCards: Card[], dealerCards: Card[]) => SideBetsFromUser;

@@ -1,1 +0,1 @@

!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["blackjack-engine"]=t():e["blackjack-engine"]=t()}(this,(function(){return function(e){var t={};function a(r){if(t[r])return t[r].exports;var n=t[r]={i:r,l:!1,exports:{}};return e[r].call(n.exports,n,n.exports,a),n.l=!0,n.exports}return a.m=e,a.c=t,a.d=function(e,t,r){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(a.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)a.d(r,n,function(t){return e[t]}.bind(null,n));return r},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a(a.s=1)}([function(e,t){e.exports=function(e){function t(r){if(a[r])return a[r].exports;var n=a[r]={i:r,l:!1,exports:{}};return e[r].call(n.exports,n,n.exports,t),n.l=!0,n.exports}var a={};return t.m=e,t.c=a,t.i=function(e){return e},t.d=function(e,a,r){t.o(e,a)||Object.defineProperty(e,a,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(a,"a",a),a},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}({"./src/index.js":function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=t.isNull=function(e){return null===e},r=t.isUndefined=function(e){return void 0===e},n=t.isNullOrUndef=function(e){return r(e)||a(e)},s=t.cardName=function(e){if(n(e))throw Error("Invalid number");return 1===e?"A":11===e?"J":12===e?"Q":13===e?"K":e.toString()},i=t.suiteName=function(e){switch(e.toLowerCase()){case"♥":case"h":case"heart":case"hearts":return"hearts";case"♦":case"d":case"diamond":case"diamonds":return"diamonds";case"♣":case"c":case"club":case"clubs":return"clubs";case"♠":case"s":case"spade":case"spades":return"spades";default:throw Error("invalid suite")}},o=t.suiteColor=function(e){switch(e){case"hearts":case"diamonds":return"R";case"clubs":case"spades":return"B";default:throw Error("invalid suite")}},c=t.cardValue=function(e){return 10>e?e:10},d=t.makeCard=function(e,t){var a=i(t);return{text:s(e),suite:a,value:c(e),color:o(a)}},l=(t.newDecks=function(e){for(var t=[],a=0;a<e;a++)t=l().concat(t);return t},t.newDeck=function(){return[].concat.apply([],["hearts","diamonds","clubs","spades"].map((function(e){return[1,2,3,4,5,6,7,8,9,10,11,12,13].map((function(t){return d(t,e)}))})))}),u=t.getRandom=function(e){return Math.floor(Math.random()*e)},h=(t.shuffle=function(e){for(var t,a,r=e.slice(0),n=r.length;0!==n;)a=u(n),t=r[n-=1],r[n]=r[a],r[a]=t;return r},t.serializeCard=function(e){var t,a=e.match(/\d/g),r=0,n="";if(a&&0<a.length?(r=+a.join(""),n=e.replace(r.toString(),"")):["j","q","k"].forEach((function(a,s){(0<=e.indexOf(a)||0<=e.indexOf(a.toUpperCase()))&&(r=11+s,t=a,n=e.replace(t,"").replace(t.toUpperCase(),""))})),0===r)throw Error("");return n=n.replace("-",""),d(r,n)});t.serializeCards=function(e){if(""===e)throw Error("value should contains a valid raw card/s definition");return e.trim().split(" ").map(h)}},0:function(e,t,a){e.exports=a("./src/index.js")}})},function(e,t,a){"use strict";a.r(t),a.d(t,"constants",(function(){return r})),a.d(t,"engine",(function(){return n})),a.d(t,"presets",(function(){return s})),a.d(t,"actions",(function(){return i})),a.d(t,"Game",(function(){return be}));var r={};a.r(r),a.d(r,"INVALID",(function(){return o})),a.d(r,"RESTORE",(function(){return c})),a.d(r,"DEAL",(function(){return d})),a.d(r,"INSURANCE",(function(){return l})),a.d(r,"SPLIT",(function(){return u})),a.d(r,"HIT",(function(){return h})),a.d(r,"DOUBLE",(function(){return f})),a.d(r,"STAND",(function(){return p})),a.d(r,"SURRENDER",(function(){return y})),a.d(r,"SHOWDOWN",(function(){return b})),a.d(r,"DEALER_HIT",(function(){return g})),a.d(r,"RIGHT",(function(){return E})),a.d(r,"LEFT",(function(){return v})),a.d(r,"STAGE_READY",(function(){return S})),a.d(r,"STAGE_PLAYER_TURN_RIGHT",(function(){return A})),a.d(r,"STAGE_PLAYER_TURN_LEFT",(function(){return O})),a.d(r,"STAGE_SHOWDOWN",(function(){return I})),a.d(r,"STAGE_DEALER_TURN",(function(){return m})),a.d(r,"STAGE_DONE",(function(){return _}));var n={};a.r(n),a.d(n,"isNull",(function(){return T})),a.d(n,"isUndefined",(function(){return k})),a.d(n,"isNullOrUndef",(function(){return w})),a.d(n,"calculate",(function(){return j})),a.d(n,"getHigherValidValue",(function(){return H})),a.d(n,"checkForBusted",(function(){return D})),a.d(n,"isBlackjack",(function(){return R})),a.d(n,"isSoftHand",(function(){return N})),a.d(n,"isSuited",(function(){return P})),a.d(n,"countCards",(function(){return C})),a.d(n,"getHandInfoInit",(function(){return B})),a.d(n,"getHandInfoAfterDeal",(function(){return L})),a.d(n,"getHandInfoAfterSplit",(function(){return U})),a.d(n,"getHandInfoAfterHit",(function(){return G})),a.d(n,"getHandInfoAfterDouble",(function(){return W})),a.d(n,"getHandInfoAfterStand",(function(){return x})),a.d(n,"getHandInfoAfterSurrender",(function(){return $})),a.d(n,"getHandInfoAfterAceSplit",(function(){return F})),a.d(n,"canDouble",(function(){return M})),a.d(n,"isLuckyLucky",(function(){return V})),a.d(n,"getLuckyLuckyMultiplier",(function(){return Y})),a.d(n,"isPerfectPairs",(function(){return z})),a.d(n,"getSideBetsInfo",(function(){return q})),a.d(n,"checkActionAllowed",(function(){return J})),a.d(n,"getPrize",(function(){return K})),a.d(n,"getPlayersWithPrizes",(function(){return Q}));var s={};a.r(s),a.d(s,"getDefaultSideBets",(function(){return Z})),a.d(s,"getDefaultRules",(function(){return ee})),a.d(s,"defaultPlayer",(function(){return te})),a.d(s,"defaultState",(function(){return ae}));var i={};a.r(i),a.d(i,"invalid",(function(){return re})),a.d(i,"restore",(function(){return ne})),a.d(i,"bet",(function(){return se})),a.d(i,"dealCards",(function(){return ie})),a.d(i,"insurance",(function(){return oe})),a.d(i,"split",(function(){return ce})),a.d(i,"hit",(function(){return de})),a.d(i,"double",(function(){return le})),a.d(i,"stand",(function(){return ue})),a.d(i,"surrender",(function(){return he})),a.d(i,"showdown",(function(){return fe})),a.d(i,"dealerHit",(function(){return pe}));const o="INVALID",c="RESTORE",d="DEAL",l="INSURANCE",u="SPLIT",h="HIT",f="DOUBLE",p="STAND",y="SURRENDER",b="SHOWDOWN",g="DEALER-HIT",E="right",v="left",S="ready",A="player-turn-right",O="player-turn-left",I="showdown",m="dealer-turn",_="done";const T=e=>null===e,k=e=>void 0===e,w=e=>k(e)||T(e),j=e=>{if(1===e.length){if(w(e[0]))return{hi:0,lo:0};const t=e[0].value;return{hi:1===t?11:t,lo:1===t?1:t}}const t=[],a=e.reduce((e,a)=>1===a.value?(t.push(1),e):e+=a.value,0);return t.reduce(e=>(e.hi+11<=21?(e.hi+=11,e.lo+=1):(e.hi+=1,e.lo+=1),e.hi>21&&e.lo<=21&&(e.hi=e.lo),e),{hi:a,lo:a})},H=e=>e.hi<=21?e.hi:e.lo,D=e=>e.hi>21&&e.lo===e.hi,R=e=>2===e.length&&21===j(e).hi,N=e=>e.some(e=>1===e.value)&&17===e.reduce((e,t)=>e+=1===t.value&&e<11?11:t.value,0),P=(e=[])=>{if(0===e.length)return!1;const t=e[0].suite;return e.every(e=>e.suite===t)},C=e=>{const t=[-1,1,1,1,1,1,0,0,0,-1,-1,-1,-1];return e.reduce((e,a)=>e+=t[a.value-1],0)},B=(e,t,a=!1)=>{const r=j(e);if(!r)throw Error(e+" cards don't have value");const n=R(e)&&!1===a,s=D(r),i=s||n||21===r.hi;return{bet:0,cards:e,playerValue:r,playerHasBlackjack:n,playerHasBusted:s,playerHasSurrendered:!1,close:i,availableActions:{double:!i&&!0,split:e.length>1&&e[0].value===e[1].value&&!i,insurance:1===t[0].value&&!i,hit:!i,stand:!i,surrender:!i}}},L=(e,t,a)=>{const r=B(e,t);r.bet=a;const n=r.availableActions;return r.availableActions=Object.assign(Object.assign({},n),{stand:!0,hit:!0,surrender:!0}),Object.assign(Object.assign({},r),{close:r.playerHasBlackjack})},U=(e,t,a,r)=>{const n=B(e,t,!0),s=n.availableActions;return n.availableActions=Object.assign(Object.assign({},s),{split:r,double:!n.close&&2===e.length,insurance:!1,surrender:!1}),n.bet=a,n},G=(e,t,a,r)=>{const n=B(e,t,r),s=n.availableActions;return n.availableActions=Object.assign(Object.assign({},s),{double:2===e.length,split:!1,insurance:!1,surrender:!1}),n.bet=a,n},W=(e,t,a,r)=>{const n=G(e,t,a,r),s=n.availableActions;return n.availableActions=Object.assign(Object.assign({},s),{hit:!1,stand:!1}),n.bet=2*a,Object.assign(Object.assign({},n),{close:!0})},x=e=>Object.assign(Object.assign({},e),{close:!0,availableActions:{double:!1,split:!1,insurance:!1,hit:!1,stand:!1,surrender:!1}}),$=e=>{const t=x(e);return Object.assign(Object.assign({},t),{playerHasSurrendered:!0,close:!0})},F=(e,t,a)=>{const r=B(e,t,!0),n=r.availableActions;for(const e in r.availableActions)n[e]=!1;return r.bet=a,r.close=!0,r},M=(e,t)=>"none"!==e&&("9or10"===e?9===t.hi||10===t.hi:"9or10or11"===e?t.hi>=9&&t.hi<=11:"9thru15"!==e||t.hi>=9&&t.hi<=15),V=(e,t)=>{const a=j(e).hi+j(t).hi,r=j(e).lo+j(t).lo,n=j(e).hi+j(t).lo,s=j(e).lo+j(t).hi;return a>=19&&a<=21||r>=19&&r<=21||n>=19&&n<=21||s>=19&&s<=21},Y=(e,t)=>{const a=[...e,...t],r=P(a);return((e,t,a)=>{const r=`${e}${t?"s":""}`;return"777s"===r?200:"678s"===r?100:"777"===r?50:"678"===r?30:21!==a.hi&&21!==a.lo||!t?21!==a.hi&&21!==a.lo||t?20===a.hi||20===a.lo?3:19===a.hi||19===a.lo?2:0:3:10})(a.map(e=>e.value).join(""),r,j(a))},z=e=>e[0].value===e[1].value,q=(e,t,a,r)=>{const n={luckyLucky:0,perfectPairs:0};if(e.luckyLucky&&t.luckyLucky&&V(a,r)){const e=Y(a,r);n.luckyLucky=t.luckyLucky*e}return e.perfectPairs&&t.perfectPairs&&z(a)&&(n.perfectPairs=5*t.perfectPairs),n},J=(e,t)=>{const a=t.stage.name;switch(a){case"STAGE_READY":{if(!e.payload)throw Error("No action payload");const{bet:a,playerId:r}=e.payload;if(void 0===a||void 0===r)throw Error("Omitted 'bet' or 'playerId' params from the action payload");t.players[r];return["BET"].indexOf(e.type)>-1}case"STAGE_DEAL_CARDS":return["DEAL-CARDS"].indexOf(e.type)>-1;case"STAGE_INSURANCE":{if(!e.payload)throw Error("No action payload");const{bet:a,playerId:r}=e.payload;if(void 0===a||void 0===r)throw Error("Omitted 'bet' or 'playerId' params from the action payload");if(!t.rules.insurance)throw new Error("Not allowed stage, because of the set rules");return["INSURANCE"].indexOf(e.type)>-1}case"STAGE_PLAYERS_TURN":{if(void 0===t.stage.activePlayerId||void 0===t.stage.activeHandId)throw new Error("'activePlayerId' and/or 'activeHandId' haven't been set in state");const r=t.stage.activePlayerId,n=t.stage.activeHandId,s=t.players[t.stage.activePlayerId],i=s.hands[t.stage.activeHandId];if(i.close)throw new Error(`${e.type} is not allowed because "${n}" hand of player ${r} is closed on "${a}"`);if(s.hands.slice(0,t.stage.activeHandId).some(e=>!e.close))throw new Error(`${e.type} is not allowed on hand ${n} for user ${r} because you need to finish a hand before`);if(!i.availableActions[e.type.toLowerCase()])throw new Error(`${e.type} is not currently allowed on hand "${n}". Stage is "${a}"`);return[p,y,u,h,f].indexOf(e.type)>-1}case b:return[b,p].indexOf(e.type)>-1;case m:return[g].indexOf(e.type)>-1;default:return!1}},K=(e,t)=>{const{playerHasSurrendered:a=!0,playerHasBlackjack:r=!1,playerHasBusted:n=!0,playerValue:s={hi:0,lo:0},bet:i=0}=e,o=H(j(t)),c=R(t);if(n)return 0;if(a)return i/2;if(r&&!c)return i+1.5*i;if(o>21)return i+i;const d=H(s);return d>o?i+i:d===o?i:0},Q=(e,t)=>{const a=[...e];for(const e of a)for(const a of e.hands)e.finalWin+=K(a,t);return a};var X=a(0);const Z=(e=!1)=>({luckyLucky:e,perfectPairs:e,royalMatch:e,luckyLadies:e,inBet:e,MatchTheDealer:e}),ee=()=>({decks:1,standOnSoft17:!0,double:"any",split:!0,doubleAfterSplit:!0,surrender:!0,insurance:!0,showdownAfterAceSplit:!0,maxHandNumber:4}),te=(e="player-0")=>({name:e,initialBet:0,finalBet:0,finalWin:0,sideBetsFromUser:{luckyLucky:0,perfectPairs:0},sideBetWins:{luckyLucky:0,perfectPairs:0},hands:[]}),ae=e=>({players:[te()],stage:{name:"STAGE_READY"},deck:Object(X.shuffle)(Object(X.newDecks)(e.decks)),availableBets:Z(!1),rules:e,dealerHoleCard:null,dealerHasBlackjack:!1,dealerHasBusted:!1,dealerCards:[],dealerValue:{hi:0,lo:0},cardCount:0,history:[]}),re=(e,t)=>({type:"INVALID",payload:{type:e.type,payload:e.payload,info:t}}),ne=()=>({type:"RESTORE"}),se=({bet:e=10,playerId:t,sideBets:a={luckyLucky:0,perfectPairs:0}})=>({type:"BET",payload:{bet:e,sideBets:a,playerId:t}}),ie=()=>({type:"DEAL-CARDS"}),oe=({bet:e=0,playerId:t})=>({type:"INSURANCE",payload:{bet:e,playerId:t}}),ce=()=>({type:"SPLIT"}),de=()=>({type:"HIT"}),le=()=>({type:"DOUBLE"}),ue=()=>({type:"STAND"}),he=()=>({type:"SURRENDER"}),fe=()=>({type:"SHOWDOWN"}),pe=e=>({type:"DEALER-HIT",payload:{dealerHoleCard:e}}),ye=e=>{const t={ts:(new Date).getTime()};return Object.assign(Object.assign({},t),{action:e})};class be{constructor(e,t=ee()){this.state=e?Object.assign({},e):ae(t),this.dispatch=this.dispatch.bind(this),this.getState=this.getState.bind(this),this.setState=this.setState.bind(this),this.enforceRules=this.enforceRules.bind(this),this._dispatch=this._dispatch.bind(this),this._drawCard=this._drawCard.bind(this)}enforceRules(e){const{availableActions:t,playerValue:a}=e,{rules:r,history:n}=this.state;return M(r.double,a)||(t.double=!1),r.split||(t.split=!1),r.surrender||(t.surrender=!1),r.doubleAfterSplit||n.some(e=>e.action.type===u)&&(t.double=!1),r.insurance||(t.insurance=!1),e}getState(){return Object.assign({},this.state)}setState(e){this.state=Object.assign(Object.assign({},this.state),e)}dispatch(e){try{return J(e,this.getState())?this._dispatch(e):this._dispatch(re(e,`${e.type} is not allowed when stage is ${this.state.stage}`))}catch(t){return this._dispatch(re(e,t.message))}}getActivePlayer(){const{activePlayerId:e,activeHandId:t}=this.state.stage;if(void 0===e||void 0===t)throw Error('"playerId" or "handId" are omitted from the stage when getting Active Player');return{activePlayerId:e,activeHandId:t}}_dispatch(e){switch(e.type){case"BET":{if(void 0===e.payload)throw Error("Payload is omitted");const{bet:t,playerId:a,sideBets:r}=e.payload;if(void 0===t||void 0===a)throw Error('"bet" or "playerId" are omitted from the payload');let n=this.state.players;const s=n[a];s.initialBet=t,n[a]=s,r&&(s.sideBetsFromUser=r);let i={name:"STAGE_READY"};n.every(e=>e.initialBet>0||e.initialBet===1/0)&&(i={name:"STAGE_DEAL_CARDS"}),this.state.history.push(ye(e)),this.state=Object.assign(Object.assign({},this.state),{stage:i,players:n}),"STAGE_DEAL_CARDS"===i.name&&this._dispatch(ie());break}case"DEAL-CARDS":{const{availableBets:e,deck:t,players:a}=this.state,r={};for(const e of a)r[e.name]=[this._drawCard()];const n=[this._drawCard()];for(const e of this.state.players)r[e.name].push(this._drawCard());const s=this._drawCard(),i=j(n);let o=R(n.concat([s]));for(const t of a){const{sideBetsFromUser:a,initialBet:i}=t,o=r[t.name],c=this.enforceRules(L(o,n,i));c.playerHasBlackjack&&(c.close=!0),t.hands=[c],t.sideBetWins=Object.assign(Object.assign({},t.sideBetWins),q(e,a,o,n.concat([s])))}let c=a.findIndex(e=>!e.hands[0].playerHasBlackjack),d={name:"STAGE_PLAYERS_TURN",activePlayerId:c,activeHandId:0};if(1===n[0].value&&(d={name:"STAGE_INSURANCE"}),this.state.history.push(ye({type:"DEAL-CARDS"})),this.state=Object.assign(Object.assign({},this.state),{players:a,deck:t,stage:d,dealerCards:n,dealerHoleCard:s,dealerValue:i,dealerHasBlackjack:o,availableBets:Z(!1)}),-1===c){this._dispatch(fe());break}break}case"INSURANCE":{if(void 0===e.payload)throw Error("Payload is omitted");const{bet:t,playerId:a}=e.payload;if(void 0===t||void 0===a)throw Error('"bet" or "playerId" are omitted from the payload');const r=this.state.players[a];if(void 0!==r.sideBetWins.insurance)throw Error(`Player '${r.name}' already make insurance decision`);if(t>r.initialBet/2)throw Error("\"bet\" can't be higher than the player's initialBet");const{dealerCards:n,dealerHoleCard:s,history:i}=this.state;let o=n;s&&(o=n.concat([s]));const c=R(o),d=t>0?t:0,l=1===o[0].value&&c&&d>0&&t>0?2*d:0;r.hands.forEach(e=>e.availableActions.insurance=!1),r.sideBetWins=Object.assign(Object.assign({},r.sideBetWins),{insurance:{risk:d,win:l}});const u=ye({type:"INSURANCE",payload:{playerId:a}});this.state.history=i.concat(u);const h=this._getStageFromInsuranceStage();this.state.stage=h,"STAGE_SHOWDOWN"===h.name&&this._dispatch(fe());break}case"SPLIT":{const{activePlayerId:e,activeHandId:t}=this.getActivePlayer(),a=this.state.players[e],{initialBet:r,hands:n}=a;let s=n[t];const{rules:i,dealerCards:o,history:c}=this.state,d=[s.cards[0]],l=[s.cards[1]],u=i.showdownAfterAceSplit&&1===d[0].value;let h=!0;n.length+1===i.maxHandNumber&&(n.forEach(e=>{e.availableActions.split=!1}),h=!1),s=this.enforceRules(U(l,o,r,h));let f=this.enforceRules(U(d,o,r,h));u&&(l.push(this._drawCard()),d.push(this._drawCard()),s=this.enforceRules(F(l,o,r)),f=this.enforceRules(F(d,o,r))),a.hands[t]=s,a.hands.push(f),this.state.players[e]=a;const p=this._getStageFromPlayerTurn(e),y=ye({type:"SPLIT",payload:{playerId:e,handId:t}});this.state.stage=p,this.state.history=c.concat(y),"STAGE_SHOWDOWN"===p.name&&this._dispatch(fe());break}case"HIT":{const{activePlayerId:e,activeHandId:t}=this.state.stage;if(void 0===e||void 0===t)throw Error('"playerId" or "handId" are omitted from the stage');const a=this.state.players[e];let r=a.hands[t];const{initialBet:n}=a,{dealerCards:s,history:i}=this.state,o=this._drawCard();r.cards.push(o),r=G(r.cards,s,n,!r.availableActions.split),a.hands[t]=r;const c=this._getStageFromPlayerTurn(e),d=ye({type:"HIT",payload:{playerId:e,handId:t}});this.state=Object.assign(Object.assign({},this.state),{stage:c,history:i.concat(d)}),"STAGE_SHOWDOWN"===c.name&&this._dispatch(fe());break}case"DOUBLE":{const{activePlayerId:e,activeHandId:t}=this.getActivePlayer(),a=this.state.players[e];let r=a.hands[t];const{initialBet:n}=a,{dealerCards:s,history:i}=this.state,o=this._drawCard();r.cards.push(o),r=W(r.cards,s,n,!r.availableActions.split),a.hands[t]=r;const c=ye({type:"DOUBLE",payload:{playerId:e,handId:t}});this.state=Object.assign(Object.assign({},this.state),{history:i.concat(c)}),this._dispatch(ue());break}case"STAND":{const{activePlayerId:e,activeHandId:t}=this.getActivePlayer(),a=this.state.players[e];let r=a.hands[t];r=x(r),a.hands[t]=r;const{history:n}=this.state,s=ye({type:"STAND",payload:{playerId:e,handId:t}});this.state.history=n.concat(s);const i=this._getStageFromPlayerTurn(e);this.state.stage=i,"STAGE_SHOWDOWN"===i.name&&this._dispatch(fe());break}case"SHOWDOWN":{const{dealerHoleCard:t,history:a,players:r}=this.state;if(null==t)throw new Error("Dealer hole card not set at showdown");const n=ye(e);if(this.state.stage={name:"STAGE_DEALER_TURN"},this.state.history=a.concat(n),this._dispatch(pe(t)),r.every(e=>e.hands.every(e=>e.playerHasBusted||e.playerHasBlackjack||e.playerHasSurrendered))){this.state=Object.assign(Object.assign({},this.state),{stage:{name:"STAGE_DONE"},players:Q(this.state.players,this.state.dealerCards)});break}for(;"STAGE_DEALER_TURN"===this.state.stage.name;)this._dispatch(pe());this.state=Object.assign(Object.assign({},this.state),{stage:{name:"STAGE_DONE"},players:Q(this.state.players,this.state.dealerCards)});break}case"SURRENDER":{const{activePlayerId:e}=this.getActivePlayer(),t=this.state.players[e];let a=t.hands[0];if(t.hands.length>1)throw Error("Many hands at surrender");const{history:r}=this.state;a=$(a),t.hands[0]=a;const n=ye({type:"STAND",payload:{playerId:e}}),s=this._getStageFromPlayerTurn(e);this.state=Object.assign(Object.assign({},this.state),{stage:s,history:r.concat(n)}),"STAGE_SHOWDOWN"===s.name&&this._dispatch(fe());break}case"DEALER-HIT":{const{rules:t,history:a}=this.state,r=(e.payload&&e.payload.dealerHoleCard?e.payload.dealerHoleCard:null)||this._drawCard(),n=this.state.dealerCards.concat([r]),s=j(n),i=R(n),o=s.hi>21;let c={name:"STAGE_DEALER_TURN"};s.hi>=17&&(o||i||t.standOnSoft17&&N(n))&&(c={name:"STAGE_DONE"}),s.lo>=17&&(c={name:"STAGE_DONE"});const d=ye(e);this.state=Object.assign(Object.assign({},this.state),{stage:c,dealerCards:n,dealerValue:s,dealerHasBlackjack:i,dealerHasBusted:o,history:a.concat(d)});break}default:{const{history:t}=this.state,a=ye(e);this.state.history=t.concat(a);break}}return this.getState()}_drawCard(){const e=this.state.deck.pop();if(null==e)throw Error("No more cards in the deck");return this.state.cardCount+=C([e]),e}_getStageFromInsuranceStage(){const{players:e}=this.state;return e.some(e=>!!e.sideBetWins.insurance)?{name:"STAGE_INSURANCE"}:this._getStageFromPlayerTurn(0)}_getStageFromPlayerTurn(e){const{players:t}=this.state;let a=e,r=0,n=!1;for(;!n&&a<t.length;){const e=t[a];for(const[t,a]of e.hands.entries())if(!a.close){r=t,n=!0;break}a++}return n&&a!==t.length?{name:"STAGE_PLAYERS_TURN",activePlayerId:a,activeHandId:r}:{name:"STAGE_SHOWDOWN"}}}}])}));
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["blackjack-engine"]=t():e["blackjack-engine"]=t()}(this,(function(){return function(e){var t={};function a(r){if(t[r])return t[r].exports;var n=t[r]={i:r,l:!1,exports:{}};return e[r].call(n.exports,n,n.exports,a),n.l=!0,n.exports}return a.m=e,a.c=t,a.d=function(e,t,r){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(a.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)a.d(r,n,function(t){return e[t]}.bind(null,n));return r},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a(a.s=1)}([function(e,t){e.exports=function(e){function t(r){if(a[r])return a[r].exports;var n=a[r]={i:r,l:!1,exports:{}};return e[r].call(n.exports,n,n.exports,t),n.l=!0,n.exports}var a={};return t.m=e,t.c=a,t.i=function(e){return e},t.d=function(e,a,r){t.o(e,a)||Object.defineProperty(e,a,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(a,"a",a),a},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}({"./src/index.js":function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=t.isNull=function(e){return null===e},r=t.isUndefined=function(e){return void 0===e},n=t.isNullOrUndef=function(e){return r(e)||a(e)},s=t.cardName=function(e){if(n(e))throw Error("Invalid number");return 1===e?"A":11===e?"J":12===e?"Q":13===e?"K":e.toString()},i=t.suiteName=function(e){switch(e.toLowerCase()){case"♥":case"h":case"heart":case"hearts":return"hearts";case"♦":case"d":case"diamond":case"diamonds":return"diamonds";case"♣":case"c":case"club":case"clubs":return"clubs";case"♠":case"s":case"spade":case"spades":return"spades";default:throw Error("invalid suite")}},o=t.suiteColor=function(e){switch(e){case"hearts":case"diamonds":return"R";case"clubs":case"spades":return"B";default:throw Error("invalid suite")}},c=t.cardValue=function(e){return 10>e?e:10},d=t.makeCard=function(e,t){var a=i(t);return{text:s(e),suite:a,value:c(e),color:o(a)}},l=(t.newDecks=function(e){for(var t=[],a=0;a<e;a++)t=l().concat(t);return t},t.newDeck=function(){return[].concat.apply([],["hearts","diamonds","clubs","spades"].map((function(e){return[1,2,3,4,5,6,7,8,9,10,11,12,13].map((function(t){return d(t,e)}))})))}),u=t.getRandom=function(e){return Math.floor(Math.random()*e)},h=(t.shuffle=function(e){for(var t,a,r=e.slice(0),n=r.length;0!==n;)a=u(n),t=r[n-=1],r[n]=r[a],r[a]=t;return r},t.serializeCard=function(e){var t,a=e.match(/\d/g),r=0,n="";if(a&&0<a.length?(r=+a.join(""),n=e.replace(r.toString(),"")):["j","q","k"].forEach((function(a,s){(0<=e.indexOf(a)||0<=e.indexOf(a.toUpperCase()))&&(r=11+s,t=a,n=e.replace(t,"").replace(t.toUpperCase(),""))})),0===r)throw Error("");return n=n.replace("-",""),d(r,n)});t.serializeCards=function(e){if(""===e)throw Error("value should contains a valid raw card/s definition");return e.trim().split(" ").map(h)}},0:function(e,t,a){e.exports=a("./src/index.js")}})},function(e,t,a){"use strict";a.r(t),a.d(t,"constants",(function(){return r})),a.d(t,"engine",(function(){return n})),a.d(t,"presets",(function(){return s})),a.d(t,"actions",(function(){return i})),a.d(t,"Game",(function(){return be}));var r={};a.r(r),a.d(r,"INVALID",(function(){return o})),a.d(r,"RESTORE",(function(){return c})),a.d(r,"DEAL",(function(){return d})),a.d(r,"INSURANCE",(function(){return l})),a.d(r,"SPLIT",(function(){return u})),a.d(r,"HIT",(function(){return h})),a.d(r,"DOUBLE",(function(){return f})),a.d(r,"STAND",(function(){return p})),a.d(r,"SURRENDER",(function(){return y})),a.d(r,"SHOWDOWN",(function(){return b})),a.d(r,"DEALER_HIT",(function(){return g})),a.d(r,"RIGHT",(function(){return E})),a.d(r,"LEFT",(function(){return v})),a.d(r,"STAGE_READY",(function(){return S})),a.d(r,"STAGE_PLAYER_TURN_RIGHT",(function(){return A})),a.d(r,"STAGE_PLAYER_TURN_LEFT",(function(){return O})),a.d(r,"STAGE_SHOWDOWN",(function(){return I})),a.d(r,"STAGE_DEALER_TURN",(function(){return m})),a.d(r,"STAGE_DONE",(function(){return _}));var n={};a.r(n),a.d(n,"isNull",(function(){return T})),a.d(n,"isUndefined",(function(){return k})),a.d(n,"isNullOrUndef",(function(){return w})),a.d(n,"calculate",(function(){return j})),a.d(n,"getHigherValidValue",(function(){return H})),a.d(n,"checkForBusted",(function(){return D})),a.d(n,"isBlackjack",(function(){return R})),a.d(n,"isSoftHand",(function(){return N})),a.d(n,"isSuited",(function(){return P})),a.d(n,"countCards",(function(){return C})),a.d(n,"getHandInfoInit",(function(){return B})),a.d(n,"getHandInfoAfterDeal",(function(){return L})),a.d(n,"getHandInfoAfterSplit",(function(){return U})),a.d(n,"getHandInfoAfterHit",(function(){return G})),a.d(n,"getHandInfoAfterDouble",(function(){return W})),a.d(n,"getHandInfoAfterStand",(function(){return x})),a.d(n,"getHandInfoAfterSurrender",(function(){return $})),a.d(n,"getHandInfoAfterAceSplit",(function(){return F})),a.d(n,"canDouble",(function(){return M})),a.d(n,"isLuckyLucky",(function(){return V})),a.d(n,"getLuckyLuckyMultiplier",(function(){return Y})),a.d(n,"isPerfectPairs",(function(){return z})),a.d(n,"getSideBetsInfo",(function(){return q})),a.d(n,"checkActionAllowed",(function(){return J})),a.d(n,"getPrize",(function(){return K})),a.d(n,"getPlayersWithPrizes",(function(){return Q}));var s={};a.r(s),a.d(s,"getDefaultSideBets",(function(){return Z})),a.d(s,"getDefaultRules",(function(){return ee})),a.d(s,"defaultPlayer",(function(){return te})),a.d(s,"defaultState",(function(){return ae}));var i={};a.r(i),a.d(i,"invalid",(function(){return re})),a.d(i,"restore",(function(){return ne})),a.d(i,"bet",(function(){return se})),a.d(i,"dealCards",(function(){return ie})),a.d(i,"insurance",(function(){return oe})),a.d(i,"split",(function(){return ce})),a.d(i,"hit",(function(){return de})),a.d(i,"double",(function(){return le})),a.d(i,"stand",(function(){return ue})),a.d(i,"surrender",(function(){return he})),a.d(i,"showdown",(function(){return fe})),a.d(i,"dealerHit",(function(){return pe}));const o="INVALID",c="RESTORE",d="DEAL",l="INSURANCE",u="SPLIT",h="HIT",f="DOUBLE",p="STAND",y="SURRENDER",b="SHOWDOWN",g="DEALER-HIT",E="right",v="left",S="ready",A="player-turn-right",O="player-turn-left",I="showdown",m="dealer-turn",_="done";const T=e=>null===e,k=e=>void 0===e,w=e=>k(e)||T(e),j=e=>{if(1===e.length){if(w(e[0]))return{hi:0,lo:0};const t=e[0].value;return{hi:1===t?11:t,lo:1===t?1:t}}const t=[],a=e.reduce((e,a)=>1===a.value?(t.push(1),e):e+=a.value,0);return t.reduce(e=>(e.hi+11<=21?(e.hi+=11,e.lo+=1):(e.hi+=1,e.lo+=1),e.hi>21&&e.lo<=21&&(e.hi=e.lo),e),{hi:a,lo:a})},H=e=>e.hi<=21?e.hi:e.lo,D=e=>e.hi>21&&e.lo===e.hi,R=e=>2===e.length&&21===j(e).hi,N=e=>e.some(e=>1===e.value)&&17===e.reduce((e,t)=>e+=1===t.value&&e<11?11:t.value,0),P=(e=[])=>{if(0===e.length)return!1;const t=e[0].suite;return e.every(e=>e.suite===t)},C=e=>{const t=[-1,1,1,1,1,1,0,0,0,-1,-1,-1,-1];return e.reduce((e,a)=>e+=t[a.value-1],0)},B=(e,t,a=!1)=>{const r=j(e);if(!r)throw Error(e+" cards don't have value");const n=R(e)&&!1===a,s=D(r),i=s||n||21===r.hi;return{bet:0,cards:e,playerValue:r,playerHasBlackjack:n,playerHasBusted:s,playerHasSurrendered:!1,close:i,availableActions:{double:!i&&!0,split:e.length>1&&e[0].value===e[1].value&&!i,insurance:1===t[0].value&&!i,hit:!i,stand:!i,surrender:!i}}},L=(e,t,a)=>{const r=B(e,t);r.bet=a;const n=r.availableActions;return r.availableActions=Object.assign(Object.assign({},n),{stand:!0,hit:!0,surrender:!0}),Object.assign(Object.assign({},r),{close:r.playerHasBlackjack})},U=(e,t,a,r)=>{const n=B(e,t,!0),s=n.availableActions;return n.availableActions=Object.assign(Object.assign({},s),{split:r,double:!n.close&&2===e.length,insurance:!1,surrender:!1}),n.bet=a,n},G=(e,t,a,r)=>{const n=B(e,t,r),s=n.availableActions;return n.availableActions=Object.assign(Object.assign({},s),{double:2===e.length,split:!1,insurance:!1,surrender:!1}),n.bet=a,n},W=(e,t,a,r)=>{const n=G(e,t,a,r),s=n.availableActions;return n.availableActions=Object.assign(Object.assign({},s),{hit:!1,stand:!1}),n.bet=2*a,Object.assign(Object.assign({},n),{close:!0})},x=e=>Object.assign(Object.assign({},e),{close:!0,availableActions:{double:!1,split:!1,insurance:!1,hit:!1,stand:!1,surrender:!1}}),$=e=>{const t=x(e);return Object.assign(Object.assign({},t),{playerHasSurrendered:!0,close:!0})},F=(e,t,a)=>{const r=B(e,t,!0),n=r.availableActions;for(const e in r.availableActions)n[e]=!1;return r.bet=a,r.close=!0,r},M=(e,t)=>"none"!==e&&("9or10"===e?9===t.hi||10===t.hi:"9or10or11"===e?t.hi>=9&&t.hi<=11:"9thru15"!==e||t.hi>=9&&t.hi<=15),V=(e,t)=>{const a=j(e).hi+j(t).hi,r=j(e).lo+j(t).lo,n=j(e).hi+j(t).lo,s=j(e).lo+j(t).hi;return a>=19&&a<=21||r>=19&&r<=21||n>=19&&n<=21||s>=19&&s<=21},Y=(e,t)=>{const a=[...e,...t],r=P(a);return((e,t,a)=>{const r=`${e}${t?"s":""}`;return"777s"===r?200:"678s"===r?100:"777"===r?50:"678"===r?30:21!==a.hi&&21!==a.lo||!t?21!==a.hi&&21!==a.lo||t?20===a.hi||20===a.lo?3:19===a.hi||19===a.lo?2:0:3:10})(a.map(e=>e.value).join(""),r,j(a))},z=e=>e[0].value===e[1].value,q=(e,t,a,r)=>{const n={luckyLucky:0,perfectPairs:0};if(e.luckyLucky&&t.luckyLucky&&V(a,r)){const e=Y(a,r);n.luckyLucky=t.luckyLucky*e}return e.perfectPairs&&t.perfectPairs&&z(a)&&(n.perfectPairs=5*t.perfectPairs),n},J=(e,t)=>{const a=t.stage.name;switch(a){case"STAGE_READY":{if(!e.payload)throw Error("No action payload");const{bet:a,playerId:r}=e.payload;if(void 0===a||void 0===r)throw Error("Omitted 'bet' or 'playerId' params from the action payload");t.players[r];return["BET"].indexOf(e.type)>-1}case"STAGE_DEAL_CARDS":return["DEAL-CARDS"].indexOf(e.type)>-1;case"STAGE_INSURANCE":{if(!e.payload)throw Error("No action payload");const{bet:a,playerId:r}=e.payload;if(void 0===a||void 0===r)throw Error("Omitted 'bet' or 'playerId' params from the action payload");if(!t.rules.insurance)throw new Error("Not allowed stage, because of the set rules");return["INSURANCE"].indexOf(e.type)>-1}case"STAGE_PLAYERS_TURN":{if(void 0===t.stage.activePlayerId||void 0===t.stage.activeHandId)throw new Error("'activePlayerId' and/or 'activeHandId' haven't been set in state");const r=t.stage.activePlayerId,n=t.stage.activeHandId,s=t.players[t.stage.activePlayerId],i=s.hands[t.stage.activeHandId];if(i.close)throw new Error(`${e.type} is not allowed because "${n}" hand of player ${r} is closed on "${a}"`);if(s.hands.slice(0,t.stage.activeHandId).some(e=>!e.close))throw new Error(`${e.type} is not allowed on hand ${n} for user ${r} because you need to finish a hand before`);if(!i.availableActions[e.type.toLowerCase()])throw new Error(`${e.type} is not currently allowed on hand "${n}". Stage is "${a}"`);return[p,y,u,h,f].indexOf(e.type)>-1}case b:return[b,p].indexOf(e.type)>-1;case m:return[g].indexOf(e.type)>-1;default:return!1}},K=(e,t)=>{const{playerHasSurrendered:a=!0,playerHasBlackjack:r=!1,playerHasBusted:n=!0,playerValue:s={hi:0,lo:0},bet:i=0}=e,o=H(j(t)),c=R(t);if(n)return 0;if(a)return i/2;if(r&&!c)return i+1.5*i;if(o>21)return i+i;const d=H(s);return d>o?i+i:d===o?i:0},Q=(e,t)=>{const a=[...e];for(const e of a)for(const a of e.hands)e.finalWin+=K(a,t);return a};var X=a(0);const Z=(e=!0)=>({luckyLucky:e,perfectPairs:e,royalMatch:e,luckyLadies:e,inBet:e,MatchTheDealer:e}),ee=()=>({decks:1,standOnSoft17:!0,double:"any",split:!0,doubleAfterSplit:!0,surrender:!0,insurance:!0,showdownAfterAceSplit:!0,maxHandNumber:4}),te=(e="player-0")=>({name:e,initialBet:0,finalBet:0,finalWin:0,sideBetsFromUser:{luckyLucky:0,perfectPairs:0},sideBetWins:{luckyLucky:0,perfectPairs:0},hands:[]}),ae=e=>({players:[te()],stage:{name:"STAGE_READY"},deck:Object(X.shuffle)(Object(X.newDecks)(e.decks)),availableBets:Z(!1),rules:e,dealerHoleCard:null,dealerHasBlackjack:!1,dealerHasBusted:!1,dealerCards:[],dealerValue:{hi:0,lo:0},cardCount:0,history:[]}),re=(e,t)=>({type:"INVALID",payload:{type:e.type,payload:e.payload,info:t}}),ne=()=>({type:"RESTORE"}),se=({bet:e=10,playerId:t,sideBets:a={luckyLucky:0,perfectPairs:0}})=>({type:"BET",payload:{bet:e,sideBets:a,playerId:t}}),ie=()=>({type:"DEAL-CARDS"}),oe=({bet:e=0,playerId:t})=>({type:"INSURANCE",payload:{bet:e,playerId:t}}),ce=()=>({type:"SPLIT"}),de=()=>({type:"HIT"}),le=()=>({type:"DOUBLE"}),ue=()=>({type:"STAND"}),he=()=>({type:"SURRENDER"}),fe=()=>({type:"SHOWDOWN"}),pe=e=>({type:"DEALER-HIT",payload:{dealerHoleCard:e}}),ye=e=>{const t={ts:(new Date).getTime()};return Object.assign(Object.assign({},t),{action:e})};class be{constructor(e,t=ee()){this.state=e?Object.assign({},e):ae(t),this.dispatch=this.dispatch.bind(this),this.getState=this.getState.bind(this),this.setState=this.setState.bind(this),this.enforceRules=this.enforceRules.bind(this),this._dispatch=this._dispatch.bind(this),this._drawCard=this._drawCard.bind(this)}enforceRules(e){const{availableActions:t,playerValue:a}=e,{rules:r,history:n}=this.state;return M(r.double,a)||(t.double=!1),r.split||(t.split=!1),r.surrender||(t.surrender=!1),r.doubleAfterSplit||n.some(e=>e.action.type===u)&&(t.double=!1),r.insurance||(t.insurance=!1),e}getState(){return Object.assign({},this.state)}setState(e){this.state=Object.assign(Object.assign({},this.state),e)}dispatch(e){try{return J(e,this.getState())?this._dispatch(e):this._dispatch(re(e,`${e.type} is not allowed when stage is ${this.state.stage}`))}catch(t){return this._dispatch(re(e,t.message))}}getActivePlayer(){const{activePlayerId:e,activeHandId:t}=this.state.stage;if(void 0===e||void 0===t)throw Error('"playerId" or "handId" are omitted from the stage when getting Active Player');return{activePlayerId:e,activeHandId:t}}_dispatch(e){switch(e.type){case"BET":{if(void 0===e.payload)throw Error("Payload is omitted");const{bet:t,playerId:a,sideBets:r}=e.payload;if(void 0===t||void 0===a)throw Error('"bet" or "playerId" are omitted from the payload');let n=this.state.players;const s=n[a];s.initialBet=t,n[a]=s,r&&(s.sideBetsFromUser=r);let i={name:"STAGE_READY"};n.every(e=>e.initialBet>0||e.initialBet===1/0)&&(i={name:"STAGE_DEAL_CARDS"}),this.state.history.push(ye(e)),this.state=Object.assign(Object.assign({},this.state),{stage:i,players:n}),"STAGE_DEAL_CARDS"===i.name&&this._dispatch(ie());break}case"DEAL-CARDS":{const{availableBets:e,deck:t,players:a}=this.state,r={};for(const e of a)r[e.name]=[this._drawCard()];const n=[this._drawCard()];for(const e of this.state.players)r[e.name].push(this._drawCard());const s=this._drawCard(),i=j(n);let o=R(n.concat([s]));for(const t of a){const{sideBetsFromUser:a,initialBet:i}=t,o=r[t.name],c=this.enforceRules(L(o,n,i));c.playerHasBlackjack&&(c.close=!0),t.hands=[c],t.sideBetWins=Object.assign(Object.assign({},t.sideBetWins),q(e,a,o,n.concat([s])))}let c=a.findIndex(e=>!e.hands[0].playerHasBlackjack),d={name:"STAGE_PLAYERS_TURN",activePlayerId:c,activeHandId:0};if(1===n[0].value&&(d={name:"STAGE_INSURANCE"}),this.state.history.push(ye({type:"DEAL-CARDS"})),this.state=Object.assign(Object.assign({},this.state),{players:a,deck:t,stage:d,dealerCards:n,dealerHoleCard:s,dealerValue:i,dealerHasBlackjack:o,availableBets:Z(!1)}),-1===c){this._dispatch(fe());break}break}case"INSURANCE":{if(void 0===e.payload)throw Error("Payload is omitted");const{bet:t,playerId:a}=e.payload;if(void 0===t||void 0===a)throw Error('"bet" or "playerId" are omitted from the payload');const r=this.state.players[a];if(void 0!==r.sideBetWins.insurance)throw Error(`Player '${r.name}' already make insurance decision`);if(t>r.initialBet/2)throw Error("\"bet\" can't be higher than the player's initialBet");const{dealerCards:n,dealerHoleCard:s,history:i}=this.state;let o=n;s&&(o=n.concat([s]));const c=R(o),d=t>0?t:0,l=1===o[0].value&&c&&d>0&&t>0?2*d:0;r.hands.forEach(e=>e.availableActions.insurance=!1),r.sideBetWins=Object.assign(Object.assign({},r.sideBetWins),{insurance:{risk:d,win:l}});const u=ye({type:"INSURANCE",payload:{playerId:a}});this.state.history=i.concat(u);const h=this._getStageFromInsuranceStage();this.state.stage=h,"STAGE_SHOWDOWN"===h.name&&this._dispatch(fe());break}case"SPLIT":{const{activePlayerId:e,activeHandId:t}=this.getActivePlayer(),a=this.state.players[e],{initialBet:r,hands:n}=a;let s=n[t];const{rules:i,dealerCards:o,history:c}=this.state,d=[s.cards[0]],l=[s.cards[1]],u=i.showdownAfterAceSplit&&1===d[0].value;let h=!0;n.length+1===i.maxHandNumber&&(n.forEach(e=>{e.availableActions.split=!1}),h=!1),s=this.enforceRules(U(l,o,r,h));let f=this.enforceRules(U(d,o,r,h));u&&(l.push(this._drawCard()),d.push(this._drawCard()),s=this.enforceRules(F(l,o,r)),f=this.enforceRules(F(d,o,r))),a.hands[t]=s,a.hands.push(f),this.state.players[e]=a;const p=this._getStageFromPlayerTurn(e),y=ye({type:"SPLIT",payload:{playerId:e,handId:t}});this.state.stage=p,this.state.history=c.concat(y),"STAGE_SHOWDOWN"===p.name&&this._dispatch(fe());break}case"HIT":{const{activePlayerId:e,activeHandId:t}=this.state.stage;if(void 0===e||void 0===t)throw Error('"playerId" or "handId" are omitted from the stage');const a=this.state.players[e];let r=a.hands[t];const{initialBet:n}=a,{dealerCards:s,history:i}=this.state,o=this._drawCard();r.cards.push(o),r=G(r.cards,s,n,!r.availableActions.split),a.hands[t]=r;const c=this._getStageFromPlayerTurn(e),d=ye({type:"HIT",payload:{playerId:e,handId:t}});this.state=Object.assign(Object.assign({},this.state),{stage:c,history:i.concat(d)}),"STAGE_SHOWDOWN"===c.name&&this._dispatch(fe());break}case"DOUBLE":{const{activePlayerId:e,activeHandId:t}=this.getActivePlayer(),a=this.state.players[e];let r=a.hands[t];const{initialBet:n}=a,{dealerCards:s,history:i}=this.state,o=this._drawCard();r.cards.push(o),r=W(r.cards,s,n,!r.availableActions.split),a.hands[t]=r;const c=ye({type:"DOUBLE",payload:{playerId:e,handId:t}});this.state=Object.assign(Object.assign({},this.state),{history:i.concat(c)}),this._dispatch(ue());break}case"STAND":{const{activePlayerId:e,activeHandId:t}=this.getActivePlayer(),a=this.state.players[e];let r=a.hands[t];r=x(r),a.hands[t]=r;const{history:n}=this.state,s=ye({type:"STAND",payload:{playerId:e,handId:t}});this.state.history=n.concat(s);const i=this._getStageFromPlayerTurn(e);this.state.stage=i,"STAGE_SHOWDOWN"===i.name&&this._dispatch(fe());break}case"SHOWDOWN":{const{dealerHoleCard:t,history:a,players:r}=this.state;if(null==t)throw new Error("Dealer hole card not set at showdown");const n=ye(e);if(this.state.stage={name:"STAGE_DEALER_TURN"},this.state.history=a.concat(n),this._dispatch(pe(t)),r.every(e=>e.hands.every(e=>e.playerHasBusted||e.playerHasBlackjack||e.playerHasSurrendered))){this.state=Object.assign(Object.assign({},this.state),{stage:{name:"STAGE_DONE"},players:Q(this.state.players,this.state.dealerCards)});break}for(;"STAGE_DEALER_TURN"===this.state.stage.name;)this._dispatch(pe());this.state=Object.assign(Object.assign({},this.state),{stage:{name:"STAGE_DONE"},players:Q(this.state.players,this.state.dealerCards)});break}case"SURRENDER":{const{activePlayerId:e}=this.getActivePlayer(),t=this.state.players[e];let a=t.hands[0];if(t.hands.length>1)throw Error("Many hands at surrender");const{history:r}=this.state;a=$(a),t.hands[0]=a;const n=ye({type:"STAND",payload:{playerId:e}}),s=this._getStageFromPlayerTurn(e);this.state=Object.assign(Object.assign({},this.state),{stage:s,history:r.concat(n)}),"STAGE_SHOWDOWN"===s.name&&this._dispatch(fe());break}case"DEALER-HIT":{const{rules:t,history:a}=this.state,r=(e.payload&&e.payload.dealerHoleCard?e.payload.dealerHoleCard:null)||this._drawCard(),n=this.state.dealerCards.concat([r]),s=j(n),i=R(n),o=s.hi>21;let c={name:"STAGE_DEALER_TURN"};s.hi>=17&&(o||i||t.standOnSoft17&&N(n))&&(c={name:"STAGE_DONE"}),s.lo>=17&&(c={name:"STAGE_DONE"});const d=ye(e);this.state=Object.assign(Object.assign({},this.state),{stage:c,dealerCards:n,dealerValue:s,dealerHasBlackjack:i,dealerHasBusted:o,history:a.concat(d)});break}default:{const{history:t}=this.state,a=ye(e);this.state.history=t.concat(a);break}}return this.getState()}_drawCard(){const e=this.state.deck.pop();if(null==e)throw Error("No more cards in the deck");return this.state.cardCount+=C([e]),e}_getStageFromInsuranceStage(){const{players:e}=this.state;return e.some(e=>void 0===e.sideBetWins.insurance)?{name:"STAGE_INSURANCE"}:this._getStageFromPlayerTurn(0)}_getStageFromPlayerTurn(e){const{players:t}=this.state;let a=e,r=0,n=!1;for(;!n&&a<t.length;){const e=t[a];for(const[t,s]of e.hands.entries()){if(console.log("hand at user "+e.name,s),!s.close){r=t,n=!0;break}a++}}return n?{name:"STAGE_PLAYERS_TURN",activePlayerId:a,activeHandId:r}:{name:"STAGE_SHOWDOWN"}}}}])}));

@@ -1,2 +0,2 @@

declare const _default: (flatCards: any, suited: any, value: any) => 0 | 10 | 2 | 3 | 200 | 100 | 50 | 30;
declare const _default: (flatCards: any, suited: any, value: any) => 10 | 0 | 2 | 3 | 200 | 100 | 50 | 30;
export default _default;
{
"name": "blackjack-engine",
"version": "0.0.3",
"version": "0.0.4",
"description": "NodeJs, multi-player, blackjack engine",

@@ -5,0 +5,0 @@ "main": "build/index.js",

@@ -513,2 +513,3 @@ import * as TYPES from './constants'

for(const [handIndex, hand] of player.hands.entries()) {
console.log(`hand at user ${player.name}`, hand)
if(!hand.close) {

@@ -518,5 +519,6 @@ handId = handIndex

break
} else {
playerId++
}
}
playerId++
}

@@ -523,0 +525,0 @@ if (!gotNextPlayer) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc