目前大致已經構思好我們的架構了!那關鍵就是遊戲,因此我們今天就來做百家樂的遊戲核心吧!需要了解的當然就是百家樂遊戲規則囉!
百家樂wiki
百家樂遊戲規則
首先說明百家樂有莊閒兩家,那簡易規則就是比大小,但是為了確保勝率,有一些奇怪規則,先說明當牌得到10 J Q K都是歸0點,其他則是補牌規則比較複雜。以下圖片可以大致知道補牌規則。
上面半部是補牌細節,下半部是補牌總表,莊家部分點數會看閒家點數進行補牌,所以才有下張補牌總表。
下注區域分為這八種,分別為莊、閒、莊對、閒對、莊天王、閒天王、平、平對。
以上有可能同時發生,像是莊雖然贏,但是閒是對子,因此兩區域都判定為贏。
以上面那張桌面來看,像是莊賠率即為1:2,也就是你丟1000可以拿回2000且賺1000,某些高賠率的也就是因為比較難出現,那就是看運氣了!
另外在外面娛樂城要注意有水錢就是手續費的感覺或是傭金,但因為我們是有丟籌碼的,水錢會造成有零碎的數字,非常難計算,所以就作罷,畢竟已經是電子娛樂了,小手段已經可以使出夠多了還要抽水錢,太惡劣了!
一般牌組都是4-8副牌下去洗,所以我們要準備牌組、洗牌、發牌、計算輸贏、計算玩家輸贏結果。因為我希望我可以記錄總彩池,且不希望我還要透過資料去算,我會新增兩個部分。
core
我們先來看我們的Round,就是每一局的產生牌局的方法。其實都是call lib內的方法派牌。
var { shallowObject } = require('../utils')
/**
* 引入
*/
var Round = function () {
this.pokerList = null
this.timeClock = null
this.notify = null
this.playerSupplyRule = null
this.bankererSupplyRule = null
this.fanPi = null
this.odds = null
this.roundTime = 0
this.roundPool = {}
this.users = {}
this.state = 0 // 0 不可投注 1 可投注
this.data = {}
var _completeCbs = []
var _changeCbs = []
this.initPokerList = function (pokerList) { this.pokerList = pokerList }
this.initRoundTime = function (time) { this.roundTime = time }
this.initTimeClock = function (timeClock) { this.timeClock = timeClock() }
this.initNotify = function (notify) { this.notify = notify }
this.initPlayerSupplyRule = function (playerSupplyRule) { this.playerSupplyRule = playerSupplyRule }
this.initBankererSupplyRule = function (bankererSupplyRule) { this.bankererSupplyRule = bankererSupplyRule }
this.initFanPi = function (fanPi) { this.fanPi = fanPi }
this.initOdds = function (odds) { this.odds = odds}
this.checkInit = function () {
// 省略太多了!
// 檢查初始化的都有沒有進來,方便抽換。
}
this.onComplete = function (cb) { _completeCbs.push(cb) }
this.onChange = function (cb) { _changeCbs.push(cb) }
var emitComplete = function () {
this.state = 0
setTimeout(() => { this.fanPiProcess() }, 1000)
// 倒數開始發牌
setTimeout(() => { this.calcResultProcess() }, 2000)
// 倒數開始計算輸贏結果
setTimeout(() => { _completeCbs.map(e => e(this.data)) }, 3000)
// 完成通知掛載的
}
var emitChange = function (c) { _changeCbs.map(e => e(c)) }
this.startCountdown = function () {
this.state = 1
this.timeClock.onComplete(() => emitComplete.bind(this)())
this.timeClock.onChange(c => { emitChange.bind(this)(c) })
this.timeClock.start(this.roundTime)
// 計時器開始計時,變化時都會emitChange讓外部可以知道內部情況,並發送訊息。
// 完成十會通知emitComplete
}
this.userJoin = function (user) {
this.users[user.id] = user
// 使用者進到這個牌局
}
this.userBetout = function (user) {
// 省略太多了!
// 使用者下注
}
this.fanPiProcess = function () {
// 省略太多了!
// 翻牌!得到牌局!
}
this.calcResultProcess = function () {
// 省略 太多了!
// 計算牌局結果,輸贏。
}
this.start = function () {
this.checkInit()
this.startCountdown()
}
}
module.exports = Round
再來看Game!
var Game = function () {
// Round
this.roundTemplate = null
this.round = null
this.pokerList = null
this.notify = null
this.timeClock = null
this.playerSupplyRule = null
this.bankererSupplyRule = null
this.fanPi = null
// 牌組
this.pokerList = null
this.notify = null
// 內部game data
this.pool = {}
this.userCount = 0
this.state = 0 // 0等於暫停 1等於開始
this.initRound = function (roundtmp) { this.roundTemplate = roundtmp }
this.initPokerList = function (pokerList) { this.pokerList = pokerList }
this.initNotify = function (notify) { this.notify = notify }
this.initTimeClock = function (timeClock) { this.timeClock = timeClock }
this.initPlayerSupplyRule = function (playerSupplyRule) { this.playerSupplyRule = playerSupplyRule }
this.initBankererSupplyRule = function (bankererSupplyRule) { this.bankererSupplyRule = bankererSupplyRule }
this.initFanPi = function (fanPi) { this.fanPi = fanPi }
this.initOdds = function (odds) { this.odds = odds }
this.checkInit = function () {
// 檢查初始化
}
this.userJoin = function (user) {
try {
this.userCount++
this.reStartCheck()
this.round.userJoin(user)
} catch (err) {
user.emit('MSG', { type: 'RES_BET_JOIN', msg: err })
}
}
this.userBetout = function (user) {
try {
this.round.userBetout(user)
} catch (err) {
user.emit('MSG', { type: 'RES_BET_OUT', msg: err })
}
}
this.startGame = function () {
this.checkInit()
this.startNewRound()
}
this.startNewRound = function () {
if (this.state) return
this.state = 1
this.round = null
this.round = new this.roundTemplate()
this.round.initPokerList(this.pokerList)
this.round.initTimeClock(this.timeClock)
this.round.initNotify(this.notify)
this.round.initPlayerSupplyRule(this.playerSupplyRule)
this.round.initBankererSupplyRule(this.bankererSupplyRule)
this.round.initFanPi(this.fanPi)
this.round.initOdds(this.odds)
this.round.initRoundTime(1000)
this.round.onChange((c) => { console.log('剩下' + c) })
this.round.onComplete((res) => {
console.log('倒數結束')
console.log(res.users_result)
this.userCount = 0
this.state = 0
setTimeout(this.reStartCheck.bind(this), 1000)
})
this.round.start()
}
this.reStartCheck = function () {
// 如果加入玩家不為0,就繼續開牌,為0就不開牌,代表沒人
if (this.userCount !== 0) {
this.startNewRound()
}
}
}
module.exports = Game
其實兩個差不多,會多新增一個Game的原因是因為,我想要紀錄整個彩池的狀況,且全部封裝在這core內,只要我掛上去監聽就可以知道內容,並傳送訊息給使用者。
其實判斷補牌是由設定檔來判斷,只是簡單的對應而已,以下為設定規則檔,很像上半部的圖片吧!
{
"time": 30,
"banker_rule": {
"9": ["S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S"],
"8": ["S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S"],
"7": ["S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S"],
"6": ["S", "S", "S", "S", "S", "S", "H", "H", "S", "S", "S"],
"5": ["S", "S", "S", "S", "H", "H", "H", "H", "S", "S", "H"],
"4": ["S", "S", "H", "H", "H", "H", "H", "H", "S", "S", "H"],
"3": ["H", "H", "H", "H", "H", "H", "H", "H", "S", "H", "H"],
"2": ["H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H"],
"1": ["H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H"],
"0": ["H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H"]
},
"player_rule": {
"0": "H",
"1": "H",
"2": "H",
"3": "H",
"4": "H",
"5": "H",
"6": "S",
"7": "S",
"8": "S",
"9": "S"
},
"odds": {
"banker": 2,
"player": 2,
"bankerking": 3,
"playerking": 3,
"tie": 9,
"tiepair": 33,
"bpair": 12,
"ppair": 12
},
"betResult": {
"banker": "莊",
"player": "閒",
"bankerking": "莊天王",
"playerking": "閒天王",
"tie": "平",
"tiepair": "平對",
"bpair": "莊對",
"ppair": "閒對"
}
}
這是大概的遊戲內容,那複雜的地方在於我和前端溝通的時機點,以及斷線等等狀態的同步問題,其實有時候在思考前端的價值所在,我現在感受得很清楚,串API、串SOCKET真的很辛苦,但這可能就是前端的價值所在吧?想參考內容的可以到Github看看哦,可能還沒同步上去,但可以關注!