-
Notifications
You must be signed in to change notification settings - Fork 655
/
script.js
390 lines (338 loc) · 14.2 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
/* Note: This implementation incldues the following features:
1. Regular beat that game (i.e. largest num wins)
2. Auto-Generate Combined Number
3. Variable Number of Dice
4. Variable Number of Players
We've removed Lowest Combined Number to reduce bloat, making the code more legible. However, please feel free to try to implement all the features together on your own
*/
/*====================================
==============GLOBAL VARIABLES========
======================================*/
// Game modes
var GAME_MODE_CHOOSE_NUM_PLAYERS = 'GAME_MODE_CHOOSE_NUM_PLAYERS';
var GAME_MODE_CHOOSE_NUM_DICE = 'GAME_MODE_CHOOSE_NUM_DICE';
var GAME_MODE_DICE_ROLL = 'GAME_MODE_DICE_ROLL';
var GAME_MODE_CHOOSE_DICE_ORDER_AUTOMATICALLY =
'GAME_MODE_CHOOSE_DICE_ORDER_AUTOMATICALLY';
// Track num of dice user has chosen to play with
var numDiceChosen = 0;
// Track num of players
var numPlayers = 0;
// Initialise the game to start with the dice roll game mode
var gameMode = GAME_MODE_CHOOSE_NUM_PLAYERS;
// Keep track of the current player's number, either 1 or 2.
// The game starts with Player 1.
var currPlayer = 0;
// Set an array that will contains details about each player (i.e. an array of objects)
var playerProfiles = [];
// Track the current round's winner
var roundWinner = null;
/*====================================
==============HELPER FUNCTIONS========
======================================*/
/**
* Return a random number from 1 to 6
*/
var getDiceRoll = function () {
return Math.ceil(Math.random() * 6);
};
/**
* Get dice rolls for curr player and populate curr player's dice array
* Return the new dice rolls
*/
var getDiceRolls = function () {
// Create an array newDiceRolls with 2 independent dice roll values
var newDiceRolls = [];
for (var i = 0; i < numDiceChosen; i += 1) {
newDiceRolls.push(getDiceRoll());
}
// assign dice rolls to the respective player
playerProfiles[currPlayer].diceRolls = newDiceRolls;
// Return new dice rolls to parent function
return newDiceRolls;
};
/**
* Return a number that is the concatenation of num1 and num2
* @param {number} num1
* @param {number} num2
*/
var concatenate2Numbers = function (num1, num2) {
return Number(String(num1) + String(num2));
};
/**
* Sort an array such that it can order any number of elements
* @param {Array} anArray
* @returns {Array} anArray sorted in ascending order
*/
var sortAnArray = function (anArray) {
// get the length of the given array
var length = anArray.length;
//Use bubble sort to sort a given array
// More info on bubble sort: https://www.geeksforgeeks.org/bubble-sort/
for (var i = 0; i < length - 1; i += 1) {
for (var j = 0; j < length - 1; j += 1) {
if (anArray[j] > anArray[j + 1]) {
var temp = anArray[j];
anArray[j] = anArray[j + 1];
anArray[j + 1] = temp;
}
}
}
return anArray;
};
/**
* Automate choosing the player's number from the dice rolls
* Return the player number
* @param {number} firstNumeralIndex
*/
var getPlayerNumberAutomatically = function () {
// Get the current player's dice array.
// We use the ternary operator on the following line for more concise syntax.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
// The example below is equivalent to:
// var diceArray;
// if (currPlayer === 1) { diceArray = player1Dice; } else { diceArray = player2Dice; }
// var diceArray = currPlayer === 1 ? player1Dice : player2Dice;
var diceArray = playerProfiles[currPlayer].diceRolls;
var playerNum;
// Sort the array such that it can order any number of elements in ascending order
sortAnArray(diceArray);
//Alternatively, instead of writing our own sorting algorithm to sort arrays, we can use a native native JS method: diceArray.sort()
// More info at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
// By now, dice array would be sorted. Iterate thru diceArray again, this time concatenating the elements from largest to smallest
while (diceArray.length > 0) {
// get hold of the largest num in the array (which is also the last element since we sorted it in ascending order earlier)
var largestNum = diceArray.pop();
// On the first iteration, there is no need to concatenate; just reassign playerNum
if (playerNum == null) {
playerNum = largestNum;
} else {
// else if it's not the first iteration, concatenate to get the largest possible number
playerNum = concatenate2Numbers(playerNum, largestNum);
}
}
// Update respective player's playerNum
playerProfiles[currPlayer].diceNum = playerNum;
// Return generated player num to parent function
return playerNum;
};
/**
* Update the global variable that tracks players' current round number
* @param {number} firstNumeralIndex
*/
updateCurrentRoundRoll = function (playerNum) {
// Store player num in the relevant global player num variable
if (currPlayer == 1) {
player1Num = playerNum;
} else {
player2Num = playerNum;
}
};
var sortAnArrayByASpecifiedKey = function (anArray, key) {
// get the length of the given array
var length = anArray.length;
//Use bubble sort to sort a given array
// More info on bubble sort: https://www.geeksforgeeks.org/bubble-sort/
for (var i = 0; i < length - 1; i += 1) {
for (var j = 0; j < length - 1; j += 1) {
if (anArray[j][key] > anArray[j + 1][key]) {
var temp = anArray[j];
anArray[j] = anArray[j + 1];
anArray[j + 1] = temp;
}
}
}
return anArray;
};
/**
* Compute the winner between all players.
* Return an array that is ordered according to who has the largest score.
*/
var determineWinner = function () {
// Overall summary of the logic: We'll start by arbitrarily assigning the first player to be the roundWinner. Then, on each subsequent player's turn, we'll assess if their diceNum is larger than the roundWinner. If yes: re-assign roundWinner; if No: do nothing
// If we've not yet set a roundWinner before (as will always be the case for the first player's turn), arbitrarily assign current player as the round winner
if (roundWinner == null) {
roundWinner = playerProfiles[currPlayer];
}
// If there is a previous roundWinner, assess if currPlayer's diceNum is larger than roundWinner's. If yes, this player becomes the new roundWinner
else if (playerProfiles[currPlayer].diceNum > roundWinner.diceNum) {
roundWinner = playerProfiles[currPlayer];
}
// If it's a draw, or the the currPlayer's diceNum is not larger than the existing roundWinner, do nothing
};
/**
* Incr the winner's points by adding previus round's points
* @param {number} roundScore
*/
var addNumToRunningScore = function (roundScore) {
// Get hold of the current players score, and add the roundScore to it
playerProfiles[currPlayer].score += roundScore;
};
var createLeaderBoardOutput = function () {
// set the preamble and assign it to a variable that will eventually be returned from this function
var leaderBoardOutput = 'Leaderboard: ';
// As per the game instructions, feel free to display the leaderboard in any order.
// To do so, loop thru all the player profiles to get their score.
//----------Option 1-------------------------
// for (var i = 0; i < playerProfiles.length; i += 1) {
// // On each iteration, concatentate with the previous verision of leaderBoardOutput
// leaderBoardOutput +=
// '<br> Player ' + playerProfiles[i].id + ': ' + playerProfiles[i].score;
// }
// return leaderboardOutput
//-------------------------------------------
// else if you would like to have the leaderboard sorted, it might look smth like this:
// Overall strategy: Create a copy of the playerProfiles array, then implement a bubble sort (similar to what we did earlier, only this time we are sorting the array based on its elements property)
// ----------Option 2---------------------------
// Copy playerProfiles into another array so that the sorting function (implemented below) won't change the order of playerProfiles
var copyOfPlayerProfiles = [];
for (var i = 0; i < playerProfiles.length; i += 1) {
copyOfPlayerProfiles.push(playerProfiles[i]);
}
var sortedByPlayerScore = sortAnArrayByASpecifiedKey(
copyOfPlayerProfiles,
'score'
);
// Loop thru the sorted array, getting hold of the last element each time. Concatenate that with the preamble
// (The reason why we get hold of the last element is because the array is sorted in ascending order, but we want to display the leaderboard in descending order)
while (sortedByPlayerScore.length > 0) {
var leadingPlayer = sortedByPlayerScore.pop();
leaderBoardOutput +=
'<br> Player ' + leadingPlayer.id + ': ' + leadingPlayer.score;
}
return leaderBoardOutput;
//-------------------------------------------
};
/**
* Reset the game so that the user has to choose how many dice he wants to play with
*/
var resetGame = function () {
// Rest currPlayer to 0 so that we can use it to point at the first element of playerProfiles (Remember: arrays are 0 indexed)
currPlayer = 0;
//Switch to choose number of dice mode so that players can restart without having to re-specify the number of players
gameMode = GAME_MODE_CHOOSE_NUM_DICE;
// Reset round winner
roundWinner = null;
};
/**
* Create a message that shows the user his dice roll vaue for each of his dice rolls
* @param {Array} diceRollsArr An array of the current user's dice rolls
*/
var createDiceRollInfoMsg = function (diceRollsArr) {
// Craft a preamble and assign it to a variable that we will return at the end of this function
var outputMsg =
'Welcome Player ' +
playerProfiles[currPlayer].id +
'.<br> Your dice rolls are:';
// Loop thru the array; on each iteration, use the index as a pointer to help you access the relevant element in diceRolls array
for (var i = 0; i < diceRollsArr.length; i += 1) {
// concatenate the existing outputMsg with a new string
outputMsg += '<br> Dice ' + (i + 1) + ': ' + diceRollsArr[i];
}
// return the concatenated msgs
return outputMsg;
};
/**
* Create a player profile for each player
*/
var createPlayerProfiles = function () {
// Loop thru n times, creating a an object with relevant keys each iteration. (n is the number of players in the game)
for (var i = 0; i < numPlayers; i += 1) {
playerProfiles.push({id: i + 1, diceRolls: [], diceNum: 0, score: 0});
}
};
/*====================================
==============MAIN====================
======================================*/
/**
* Play Beat with variable number of players and auto-choosing the largest number from the die rolled.
* https://swe101.rocketacademy.co/projects/project-2-dice
* @param {string} input
*/
var main = function (input) {
if (gameMode == GAME_MODE_CHOOSE_NUM_PLAYERS) {
// validate that user has provided an an integer larger than 0
if (isNaN(input) == true || !Number(input) > 0) {
return 'Please enter a number larger than 0';
}
// Convert user input from string to number, and assign it to the global var tracking the number of dice users have chosen to play with
numPlayers = Number(input);
// create player profiles based on the number of players that will be playing
createPlayerProfiles();
// Change to dice roll mode
gameMode = GAME_MODE_CHOOSE_NUM_DICE;
return (
'There are ' +
numPlayers +
' players in this game. Please enter how many dice you would like to play with.'
);
}
if (gameMode == GAME_MODE_CHOOSE_NUM_DICE) {
// validate that user has provided an an integer larger than 0
if (isNaN(input) == true || !Number(input) > 0) {
return 'Please enter a number larger than 0';
}
// Convert user input from string to number, and assign it to the global var tracking the number of dice users have chosen to play with
numDiceChosen = Number(input);
// Change to dice roll mode
gameMode = GAME_MODE_DICE_ROLL;
return (
'You have chosen to play with ' +
numDiceChosen +
' dice. Player 1, click submit to get your dice rolls'
);
}
// Roll 2 dice and show the player the values
if (gameMode == GAME_MODE_DICE_ROLL) {
// Get dice rolls for curr player and populate the curr player's dice array
var newDiceRolls = getDiceRolls();
// Switch mode to choose dice order
gameMode = GAME_MODE_CHOOSE_DICE_ORDER_AUTOMATICALLY;
// Return the dice roll values to that player
var diceRollInfo = createDiceRollInfoMsg(newDiceRolls);
return diceRollInfo;
}
// Create a number based on the player's chosen dice order, and show it to the player
if (gameMode == GAME_MODE_CHOOSE_DICE_ORDER_AUTOMATICALLY) {
// Get player number for curr player
var playerNum = getPlayerNumberAutomatically();
var playerNumResponse =
'Player ' +
playerProfiles[currPlayer].id +
', your number is ' +
playerProfiles[currPlayer].diceNum +
'.';
// add the playerNum to player's running score
addNumToRunningScore(playerNum);
//On each player's turn, determine if he has the largest dice so far
determineWinner();
// if currPlayer is less than the number of players (i.e. the number that the user chose at the start), it means not everyone has had a go. Therefore change it back to the dice roll mode and increment currplayer
if (playerProfiles[currPlayer].id < numPlayers) {
// change the mode
gameMode = GAME_MODE_DICE_ROLL;
// increment currPlayer
currPlayer += 1;
// Prompt next user to roll the dice
return (
playerNumResponse +
'<br> It is now Player ' +
playerProfiles[currPlayer].id +
"'s turn. Press Submit to roll the dice"
);
}
var leaderBoardOutput = createLeaderBoardOutput();
// Craft the end game response
var myOutputValue =
playerNumResponse +
' <br><br> Player' +
roundWinner.id +
' won this round. <br> <br> <br>' +
leaderBoardOutput +
'<br><br> To continue playing enter the number of dice you would like to play with, and click submit.';
// Reset the game
resetGame();
return myOutputValue;
}
// If we reach this point, there is an error because game mode is not what we expect
return 'An error occurred. Please refresh to start again.';
};