Skip to main content
Code Review

Return to Question

added 4 characters in body; edited tags; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Cleaning Ifif / Elseelse mess in Node.js poker game

This is the third rewrite of the poker bot I am writing. The first one was such a mess of if if/ elseselses that iI could not deal with it. The second version was cluttered, and I had trouble following what happened but did work. I decided to scrap it for a new clean module based / more functional version but it seems to fall into the same traps.

This is my first major project in any language, and version 1 was my first javascriptJavaScript project ever. I tried to read some formatting articles such as the googleGoogle formatting guide and follow those but I haven't read any formal books yet. I should probably do that. Any recommendations would rock.

Cleaning If / Else mess in Node.js poker game

This is the third rewrite of the poker bot I am writing. The first one was such a mess of if / elses that i could not deal with it. The second version was cluttered, and I had trouble following what happened but did work. I decided to scrap it for a new clean module based / more functional version but it seems to fall into the same traps.

This is my first major project in any language, and version 1 was my first javascript project ever. I tried to read some formatting articles such as the google formatting guide and follow those but I haven't read any formal books yet. I should probably do that. Any recommendations would rock.

Cleaning if / else mess in Node.js poker game

This is the third rewrite of the poker bot I am writing. The first one was such a mess of if/ elses that I could not deal with it. The second version was cluttered, and I had trouble following what happened but did work. I decided to scrap it for a new clean module based / more functional version but it seems to fall into the same traps.

This is my first major project in any language, and version 1 was my first JavaScript project ever. I tried to read some formatting articles such as the Google formatting guide and follow those but I haven't read any formal books yet. I should probably do that. Any recommendations would rock.

Source Link

Cleaning If / Else mess in Node.js poker game

This is the third rewrite of the poker bot I am writing. The first one was such a mess of if / elses that i could not deal with it. The second version was cluttered, and I had trouble following what happened but did work. I decided to scrap it for a new clean module based / more functional version but it seems to fall into the same traps.

This is my first major project in any language, and version 1 was my first javascript project ever. I tried to read some formatting articles such as the google formatting guide and follow those but I haven't read any formal books yet. I should probably do that. Any recommendations would rock.

I was going to wait until it was finished to post here, however if there were any major changes to anything it would be easier to do before the rest of the functions were finished.

The project is in node.js using the Node - Steam library.

This is the main program that calls the module running the game. Some values are hard-coded in, which will have to change once I finish the first module and start on a second.

var fs = require('fs')
var Steam = require('steam')
var _ = require('lodash')
var startedRooms = []
if (fs.existsSync('servers')) {
 Steam.servers = JSON.parse(fs.readFileSync('servers'))
}
var bot = new Steam.SteamClient()
bot.logOn({
 accountName: 'SpencerFlem',
 password: 'Ap3rtur3',
 shaSentryfile: fs.readFileSync('sentryfile')
})
bot.on('loggedOn', function() {
 var mainChat = '103582791434524271'
 console.log('Logged in!')
 bot.setPersonaName('Dealer')
 bot.setPersonaState(Steam.EPersonaState.Online); // to display your bot's status as "Online"
 bot.joinChat(mainChat);
})
bot.on('servers', function(servers) {
 fs.writeFile('servers', JSON.stringify(servers))
})
bot.on('chatEnter', function(room) {
 startupRoom(room)
})
// MAIN
var allData = {}
gameLookup = {
 '103582791434524271':'./Games/Poker/5 Card Draw/5 Card Draw.js' // This to the variable to use functions from?
}
var room103582791434524271 = require('./Games/Poker/5 Card Draw/5 Card Draw.js') // Object / array instead of variable? idk if possible 
// OR: require all by default and use its name as variable
function setupData(room) {
 condensedUsers = {}
 for (var i = 0; i < Object.keys(bot.chatRooms[room]).length; i++ ) {
 condensedUsers[Object.keys(bot.chatRooms[room])[i]] = bot.users[Object.keys(bot.chatRooms[room])[i]]
 }
 
 allData[room].users = condensedUsers
 allData[room].steamID = bot.steamID
 allData[room].thisChatRoom = bot.chatRooms[room]
 allData[room].friends = 'NONEXISTANT' //Make this not so!
 allData[room].stored = {}
}
var players = []
function startupRoom(room) { // If went offline and rejoined done restart room?
 allData[room] = {}
 setupData(room)
 progress = room103582791434524271.startup(allData[room])
 applyProgress(progress, room)
}
function applyProgress(progress, room) {
 allData[room].stored = progress.storedData
 commandList = Object.keys(progress.commands)
 if (commandList.indexOf('sendMessage') !== -1) {
 for (var i = 0; i < progress.commands.sendMessage.length; i++) {
 if (progress.commands.sendMessage[i][0] === 'room') { //why cant it know its room?
 bot.sendMessage(room, progress.commands.sendMessage[i][1])
 }
 else {
 bot.sendMessage(progress.commands.sendMessage[i][0], progress.commands.sendMessage[i][1])
 }
 }
 }
 if (commandList.indexOf('lockChat') !== -1) {
 if (lockChat === true) {
 bot.lockChat(room)
 }
 }
 if (commandList.indexOf('unlockChat') !== -1) {
 if (unlockChat === true) {
 bot.unlockChat(room)
 }
 }
 if (commandList.indexOf('setModerated') !== -1) {
 if (setModerated === true) {
 bot.setModerated(room)
 }
 }
 if (commandList.indexOf('setUnmoderated') !== -1) {
 if (setUnmoderated === true) {
 bot.setUnmoderated(room)
 }
 }
 if (commandList.indexOf('kick') !== -1) {
 for (var i = 0; i < progress.commands.kick.length; i++) {
 bot.kick(room, progress.commands.kick[i])
 }
 }
 if (commandList.indexOf('ban') !== -1) {
 for (var i = 0; i < progress.commands.ban.length; i++) {
 bot.ban(room, progress.commands.ban[i])
 }
 }
 if (commandList.indexOf('unban') !== -1) {
 for (var i = 0; i < progress.commands.unban.length; i++) {
 bot.unban(room, progress.commands.unban[i])
 }
 }
}
bot.on('chatStateChange', function(type, player, room, agent) {
 //console.log(type + '-' + player + '-' + room + '-' + agent)
})
bot.on('chatMsg', function(room, message, type, player) {
 progress = room103582791434524271.checkMsg(allData[room], message, type, player)
 applyProgress(progress, room)
 // Do something with progress, prehaps an eval function
 
})

Then, the real game part starts here

/// Invigorating Imports
var _ = require('lodash') //Not necessary? //so?
var fs = require('fs')
/// Sumptuous Variables
var data = {}
var roomData = {}
var playerData = {}
/// Useful Functions
var symbolNumbers = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
var symbolSuits = ['♣', '♦', '♥', '♠']
var wordNumbers = ['Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King', 'Ace']
var wordSuits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
function setupLookup(numbers,suits) {
 var tempLookup = []
 for (var i=0; i<numbers.length; i++) {
 for (var j=0; j<suits.length; j++) {
 tempLookup.push([numbers[i],suits[j]])
 }
 }
 return tempLookup
}
var symbolLookup = setupLookup(symbolNumbers,symbolSuits)
var wordLookup = setupLookup(wordNumbers,wordSuits)
function extractNumbers(message) { //run regex and check for each middle part to get in order?
 var regex = /\D+/
 var numbers = []
 numbers = message.split(regex)
 _.pull(numbers, '') // !!! Commas ex: 1,984 would be 1 & 984 not: 1984 :( Also 1.5 or 1 and 1/2 would be weird
 
 // Copypasta from old bot incoming
 
 var numbersZeroToNine = ['ZERO','ONE','TWO','THREE','FOUR','FIVE','SIX','SEVEN','EIGHT','NINE']
 var numbersTenToNineteen = ['TEN','ELEVEN','TWELVE','THIRTEEN','FOURTEEN','FIFTEEN','SIXTEEN','SEVENTEEN','EIGHTEEN','NINETEEN']
 var numbersTwentyToNinety = ['ZERO','TEN','TWENTY','THIRTY','FORTY','FIFTY','SIXTY','SEVENTY','EIGHTY','NINETY']
 for (i = 1 ; i < numbersTwentyToNinety.length ; i++) {
 if (message.indexOf(numbersTwentyToNinety[i]) != -1) {
 submessage = message.substr(message.indexOf(numbersTwentyToNinety[i]))
 for (j = 1 ; j < numbersZeroToNine.length ; j++) {
 if (submessage.indexOf(numbersZeroToNine[j]) != -1) {
 numberBet = i*10+j
 numbers.push(numberBet) //numberBet is bad name
 }
 else if (j == numbersZeroToNine.length - 1) {
 numberBet = i*10
 numbers.push(numberBet)
 }
 }
 }
 }
 for (k = 0 ; k < numbersTenToNineteen.length ; k++) {
 if (message.indexOf(numbersTenToNineteen[k]) != -1) {
 numberBet = k+10
 numbers.push(numberBet)
 }
 }
 for (l = 0 ; l < numbersZeroToNine.length ; l++) {
 if (message.indexOf(numbersZeroToNine[l]) != -1) {
 numberBet = l
 numbers.push(numberBet)
 } 
 }
 // </copypasta>
 
 console.log('NUMBERSNUMBERSNUMBERS---' + numbers)
 return numbers // Array should be in order of distance, right now is not due to copypasta
}
function formatHand(player) { //unfinshed //Also, add if increase
 var optionsList = []
 if (player === roomData.turn) {
 if (playerData[player].mustSpecifyBetAmount === true) {
 optionsList.push('SAY HOW MUCH YOU BET')
 }
 else {
 if (playerData[player].canBet === true) { optionsList.push('Bet') }
 if (playerData[player].canCheck === true) { optionsList.push('Check') }
 if (playerData[player].canAllIn === true) { optionsList.push('All In (' + playerData[player].wallet + ')') }
 if (playerData[player].canRaise === true) { optionsList.push('Raise (#)') }
 if (playerData[player].canCall === true) { optionsList.push('Call (' + (roomData.currentBet - playerData[player].amountBet) + ')') }
 if (playerData[player].canFold === true) { optionsList.push('Fold') }
 if (playerData[player].canShow === true) { optionsList.push('Yes'); optionsList.push('No')} 
 }
 }
 else {
 optionsList.push('AWAIT YOUR TURN')
 }
 var shortHand = ''
 for (var i = 0; i < playerData[player].hand.length; i++) {
 shortHand += symbolLookup[ playerData[player].hand[i] ][0] 
 shortHand += symbolLookup[ playerData[player].hand[i] ][1]
 if (i !== playerData[player].hand.length - 1) {
 shortHand += ' '
 }
 }
 var shortOptions = ''
 for (var i = 0; i < optionsList.length; i++) {
 shortOptions += optionsList[i]
 if (i !== optionsList.length - 1) {
 shortOptions += ' | '
 }
 }
 var longHand = ' '
 for (var i = 0; i < playerData[player].hand.length; i++) {
 longHand += ' '
 longHand += symbolLookup[ playerData[player].hand[i] ][0]
 longHand += symbolLookup[ playerData[player].hand[i] ][1] 
 }
 
 var statusSpaces = ''
 var statusNumberList = ''
 statusNumberList += roomData.currentBet.toString() + roomData.pot.toString() + playerData[player].wallet.toString()
 
 var statusSpacesNumber = Math.floor((27-(statusNumberList.length * 2)) / 4 )
 for (var i = 0; i < statusSpacesNumber; i++ ) {
 statusSpaces += ' '
 }
 var statusBar = ''
 statusBar = statusSpaces + 'CURRENT BET: ' + roomData.currentBet + statusSpaces + 'YOUR WALLET: ' + playerData[player].wallet + statusSpaces + 'POT: ' + roomData.pot
 
 var longOptions = ''
 var optionsSize = 0
 for (var i = 0; i < optionsList.length; i++) {
 optionsSize += optionsList[i].length * 2
 }
 
 var longOptionsSpaces = ''
 var longOptionsSpacesSize = Math.floor( (91 - optionsSize) / (optionsList.length * 2) )
 for (var i = 0; i < longOptionsSpacesSize; i++) {
 longOptionsSpaces += ' '
 }
 
 for (var i = 0; i < (optionsList.length); i++ ) {
 if (i === 0) {
 longOptions += longOptionsSpaces + optionsList[i]
 }
 else {
 longOptions += longOptionsSpaces + '|' + longOptionsSpaces + optionsList[i]
 }
 }
 
 var specialMessage = '.'
 
 message = shortHand + '\n' + shortOptions + '\n' + '———————————————————————————' + '\n' + '.' + '\n' + longHand + '\n' + '.' + '\n' + '———————————————————————————' 
 + '\n' + statusBar + '\n' + '———————————————————————————' + '\n' + specialMessage + '\n' + longOptions
 return [player, message]
}
 /// PLAY FUNCTIONS BEGIN HERE
 
function check() {
 var messages = []
 if (roomData.nextTurn === roomData.originalTurn) {
 messages.push(['room', 'Everybody loses. Try harder next time.'])
 
 //EVERYONE LOSES
 
 }
 else {
 messages.push(['room', data.users[roomData.turn].playerName + ' checked.'])
 roomData.advanceTurn()
 }
 messages.push(formatHand(roomData.turn))
 if (roomData.turn !== roomData.nextTurn) {
 messages.push(formatHand(roomData.nextTurn))
 }
 return messages
}
function bet(amount) { //unfinished
 var messages = []
 if (amount.length === 0) {
 playerData[roomData.turn].mustSpecifyBetAmount = true
 messages.push(['room', 'How much do you bet?'])
 messages.push(formatHand(roomData.turn))
 }
 else if (amount.length > 1) {
 playerData[roomData.turn].mustSpecifyBetAmount = true
 var message = 'How much do you bet? You said '
 if (amount.length === 2) {
 message += 'both ' + amount[0] + ' and ' + amount[1] + '.'
 }
 else {
 for (var i = 0; i < amount.length; i++) {
 if (i === amount.length - 1) {
 message += 'and ' + amount[i] + '.'
 }
 else {
 message += amount[i] + ', '
 }
 }
 }
 messages.push(['room', message])
 messages.push(formatHand(roomData.turn))
 }
 else {
 playerData[roomData.turn].mustSpecifyBetAmount = false
 if (amount[0] === playerData[roomData.turn].wallet) {
 // ACTIVATE ALL IN
 }
 else if (amount[0] > playerData[roomData.turn].wallet) {
 messages.push(['room', 'You are too poor, please bet a little lower.'])
 }
 else {
 roomData.originalTurn = roomData.turn
 playerData[roomData.turn].wallet -= amount[0]
 roomData.pot += amount[0]
 roomData.currentBet = amount
 playerData[roomData.turn].amountBet = amount
 for (var i = 0; i < roomData.remainingPlayers.length; i++) {
 playerData[roomData.remainingPlayers[i]].canCheck = false
 playerData[roomData.remainingPlayers[i]].canBet = false
 playerData[roomData.remainingPlayers[i]].canRaise = true
 playerData[roomData.remainingPlayers[i]].canCall = true
 playerData[roomData.remainingPlayers[i]].canFold = true
 }
 messages.push(['room', data.users[roomData.turn].playerName + 'bet ' + amount + '.'])
 messages.push(formatHand(roomData.turn))
 messages.push(formatHand(roomData.nextTurn))
 roomData.advanceTurn()
 }
 }
 return messages
}
/// Interesting Exports (allowed to affect the real messages)
exports.startup = function(givenData) {
 
 data = givenData
 players = Object.keys(data.thisChatRoom) //shuffle?
 _.pull(players,data.steamID)
 
 /// OBJECT SETUP BEGINS HERE
 roomData = {
 deck: [],
 makeDeck: function() { roomData.deck = _.shuffle(_.range(0,52,1)) },
 pot: 0,
 currentBet: 0,
 players: players,
 remainingPlayers: players,
 get turn() {return roomData.remainingPlayers[0]},
 originalTurn: players[0], //used to be defined lower. Breaks?
 get nextTurn() {return _.last(roomData.remainingPlayers)},
 advanceTurn: function() { roomData.remainingPlayers.unshift(roomData.remainingPlayers.pop()) }
 }
 playerData.addPlayer = function(player) {
 this[player] = {}
 this[player].hand = []
 this[player].deal = function(amount) { // should this be here?
 for (var i = 0; i < amount; i++) { //could subtract for optimal awesome (var i = amount. . .)
 this.hand.push(roomData.deck.pop()) // check if possible 1st
 }
 }
 this[player].amountBet = 0
 this[player].wallet = 0 // REMOVE?
 this[player].canCheck = true
 this[player].canBet = true
 this[player].mustSpecifyBetAmount = false
 this[player].canCall = false
 this[player].canRaise = false
 this[player].canFold = false
 this[player].canAllIn = false
 this[player].canShow = false
 }
 
 /// OBJECT SETUP ENDS HERE
 
 roomData.makeDeck()
 setupLookup(symbolLookup,symbolNumbers,symbolSuits)
 setupLookup(wordLookup,wordNumbers,wordSuits)
 
 var messages = []
 
 for(var i=0; i < players.length; i++) {
 playerData.addPlayer(players[i])
 playerData[players[i]].deal(5)
 messages.push(formatHand(players[i]))
 }
 
 data.stored.roomData = roomData
 data.stored.playerData = playerData
 
 var commands = {}
 console.log('nn' + JSON.stringify(messages, null, 4))
 commands.sendMessage = messages
 
 /*
 other commands:
 .addFirend = [player1, player2]
 .lockChat = true
 .unlockChat = true
 .setModerated = true
 .setUnmoderated = true
 .kick = [player1, ...]
 .ban = [player1 ...]
 .unban = [player1, ...]
 */
 
 var progress = {}
 progress.storedData = data.stored
 progress.commands = commands
 
 return progress
}
exports.checkMsg = function(givenData, receivedMessage, type, player) { //unfinished
 data = givenData
 roomData = data.stored.roomData
 playerData = data.stored.playerData
 receivedMessage = receivedMessage.toUpperCase()
 var messages = []
 
 if (playerData[player].mustSpecifyBetAmount === true && roomData.turn) {
 if (receivedMessage.indexOf('CHECK') !== -1) { // better way than listing each one?
 messages.push(['room', 'Do you bet or check?'])
 playerData[player].mustSpecifyBetAmount = false
 }
 else {
 var amount = extractNumbers(receivedMessage)
 var localMessages = bet(amount)
 for (var i = 0; i < localMessages.length; i++) {
 messages.push(localMessages[i])
 }
 }
 messages.push(formatHand(player))
 }
 
 else {
 if (receivedMessage.indexOf('CHECK') !== -1 && roomData.turn === player && playerData[player].canCheck === true) { // if both?
 var localMessages = check()
 for (var i = 0; i < localMessages.length; i++) { // Array holding each to its required values and its outcome? Would solve both problem and allow for similar values
 messages.push(localMessages[i])
 }
 }
 if (receivedMessage.indexOf('BET') !== -1 && roomData.turn === player && playerData[player].canBet === true) {
 var amount = extractNumbers(receivedMessage)
 var localMessages = bet(amount)
 for (var i = 0; i < localMessages.length; i++) {
 messages.push(localMessages[i])
 }
 }
 }
 
 if(receivedMessage.indexOf('HIT ME') !== -1) {
 playerData[player].wallet += 10
 console.log(playerData[player].wallet)
 messages.push(formatHand(player))
 }
 
 console.log('mm' + JSON.stringify(messages, null, 4))
 data.stored.roomData = roomData
 data.stored.playerData = playerData
 var commands = {}
 commands.sendMessage = messages
 var progress = {}
 progress.storedData = data.stored
 progress.commands = commands
 return progress
}

The parts I am specifically worried about if / else monstrosities is where the chat is processed. Right now it is not too bad, but right now only checking and betting is possible. With raising, folding etc.. it is bound to get more complicated. It also isn't able to tell if the message contained two commands such as "bet check" which is a problem. According to the style guides ifs should only be 1 or two levels deep and functions should be shorter.

if (playerData[player].mustSpecifyBetAmount === true && roomData.turn) {
 if (receivedMessage.indexOf('CHECK') !== -1) { // better way than listing each one?
 messages.push(['room', 'Do you bet or check?'])
 playerData[player].mustSpecifyBetAmount = false
 }
 else {
 var amount = extractNumbers(receivedMessage)
 var localMessages = bet(amount)
 for (var i = 0; i < localMessages.length; i++) {
 messages.push(localMessages[i])
 }
 }
 messages.push(formatHand(player))
}
else {
 if (receivedMessage.indexOf('CHECK') !== -1 && roomData.turn === player && playerData[player].canCheck === true) { // if both?
 var localMessages = check()
 for (var i = 0; i < localMessages.length; i++) { // Array holding each to its required values and its outcome? Would solve both problem and allow for similar values
 messages.push(localMessages[i])
 }
 }
 if (receivedMessage.indexOf('BET') !== -1 && roomData.turn === player && playerData[player].canBet === true) {
 var amount = extractNumbers(receivedMessage)
 var localMessages = bet(amount)
 for (var i = 0; i < localMessages.length; i++) {
 messages.push(localMessages[i])
 }
 }
}

Possible ideas: I tried making an array of the trigger word, its conditions and the function to be executed which could be iterated through. Unfortinitely I could not figure out how to make the function return a value wihout it looking even messier.

default

AltStyle によって変換されたページ (->オリジナル) /