diff --git a/.eslintrc.js b/.eslintrc.js
index 2567d5f9..d890be8b 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,24 +1,24 @@
-module.exports = {
- env: {
- browser: true,
- es2020: true,
- },
- extends: [
- 'airbnb-base',
- ],
- parserOptions: {
- ecmaVersion: 11,
- },
- rules: {
- // Don't enforce control flow closing curly brace needs to be
- // on same line as next control flow opening statement
- 'brace-style': 'off',
- // Disable linebreak style to prevent ESLint errors on Windows line endings
- // https://eslint.org/docs/rules/linebreak-style
- 'linebreak-style': 'off',
- // Allow console for students to debug
- 'no-console': 'off',
- // Allow function param reassign for array or object elements or properties
- 'no-param-reassign': ['error', { props: false }],
- },
-};
+module.exports = {
+ env: {
+ browser: true,
+ es2020: true,
+ },
+ extends: [
+ 'airbnb-base',
+ ],
+ parserOptions: {
+ ecmaVersion: 11,
+ },
+ rules: {
+ // Don't enforce control flow closing curly brace needs to be
+ // on same line as next control flow opening statement
+ 'brace-style': 'off',
+ // Disable linebreak style to prevent ESLint errors on Windows line endings
+ // https://eslint.org/docs/rules/linebreak-style
+ 'linebreak-style': 'off',
+ // Allow console for students to debug
+ 'no-console': 'off',
+ // Allow function param reassign for array or object elements or properties
+ 'no-param-reassign': ['error', { props: false }],
+ },
+};
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 600afc3b..d3b8f87f 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,17 +1,17 @@
-Please fill out the survey before submitting the pull request. Thanks!
-
-🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀
-
-How many hours did you spend on this assignment?
-
-Please fill in one error and/or error message you received while working on this assignment.
-
-What part of the assignment did you spend the most time on?
-
-Comfort Level (1-5):
-
-Completeness Level (1-5):
-
-What did you think of this deliverable?
-
-Is there anything in this code that you feel pleased about?
+Please fill out the survey before submitting the pull request. Thanks!
+
+🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀
+
+How many hours did you spend on this assignment?
+
+Please fill in one error and/or error message you received while working on this assignment.
+
+What part of the assignment did you spend the most time on?
+
+Comfort Level (1-5):
+
+Completeness Level (1-5):
+
+What did you think of this deliverable?
+
+Is there anything in this code that you feel pleased about?
diff --git a/.gitignore b/.gitignore
index 1a04d2b9..93ed6693 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
-# File that sometimes appears on MacOS
-.DS_Store
-
-# Dependency directories
-node_modules/
+# File that sometimes appears on MacOS
+.DS_Store
+
+# Dependency directories
+node_modules/
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 202a1c13..68f92937 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,14 +1,14 @@
-{
- "editor.defaultFormatter": "esbenp.prettier-vscode",
- "[javascript]": {
- "editor.defaultFormatter": "dbaeumer.vscode-eslint"
- },
- "editor.formatOnSave": true,
- "editor.formatOnPaste": true,
- "editor.minimap.enabled": false,
- "editor.tabSize": 2,
- "editor.wordWrap": "on",
- "eslint.format.enable": true,
- "eslint.lintTask.enable": true,
- "eslint.migration.2_x": "off"
-}
+{
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "[javascript]": {
+ "editor.defaultFormatter": "dbaeumer.vscode-eslint"
+ },
+ "editor.formatOnSave": true,
+ "editor.formatOnPaste": true,
+ "editor.minimap.enabled": false,
+ "editor.tabSize": 2,
+ "editor.wordWrap": "on",
+ "eslint.format.enable": true,
+ "eslint.lintTask.enable": true,
+ "eslint.migration.2_x": "off"
+}
diff --git a/README.md b/README.md
index 1d3a8a65..03e3ce3d 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,7 @@
-# Rocket Academy Coding Bootcamp: Video Poker
+# Rocket Academy Coding Bootcamp: Video Poker
+
+Video Poker is single-player Poker where we try to optimise our score by getting the best possible hands. The gameplay is as follows.
+
+1. The user starts with 100 points.
+2. When they click the "Deal" button the computer deals a hand of 5 cards. The user can choose any number of their cards to replace with new, random cards.
+3. After the user finishes replacing cards, the game assigns points based on the resulting hand.
diff --git a/images/cards.zip b/images/cards.zip
new file mode 100644
index 00000000..9ece11a0
Binary files /dev/null and b/images/cards.zip differ
diff --git a/images/cards/10_of_clubs.png b/images/cards/10_of_clubs.png
new file mode 100644
index 00000000..18af741d
Binary files /dev/null and b/images/cards/10_of_clubs.png differ
diff --git a/images/cards/10_of_diamonds.png b/images/cards/10_of_diamonds.png
new file mode 100644
index 00000000..3bbc4e06
Binary files /dev/null and b/images/cards/10_of_diamonds.png differ
diff --git a/images/cards/10_of_hearts.png b/images/cards/10_of_hearts.png
new file mode 100644
index 00000000..3eb83d72
Binary files /dev/null and b/images/cards/10_of_hearts.png differ
diff --git a/images/cards/10_of_spades.png b/images/cards/10_of_spades.png
new file mode 100644
index 00000000..0b3d2947
Binary files /dev/null and b/images/cards/10_of_spades.png differ
diff --git a/images/cards/2_of_clubs.png b/images/cards/2_of_clubs.png
new file mode 100644
index 00000000..291ed975
Binary files /dev/null and b/images/cards/2_of_clubs.png differ
diff --git a/images/cards/2_of_diamonds.png b/images/cards/2_of_diamonds.png
new file mode 100644
index 00000000..4deee7cc
Binary files /dev/null and b/images/cards/2_of_diamonds.png differ
diff --git a/images/cards/2_of_hearts.png b/images/cards/2_of_hearts.png
new file mode 100644
index 00000000..75a014f3
Binary files /dev/null and b/images/cards/2_of_hearts.png differ
diff --git a/images/cards/2_of_spades.png b/images/cards/2_of_spades.png
new file mode 100644
index 00000000..1ce0ffe8
Binary files /dev/null and b/images/cards/2_of_spades.png differ
diff --git a/images/cards/3_of_clubs.png b/images/cards/3_of_clubs.png
new file mode 100644
index 00000000..076ab318
Binary files /dev/null and b/images/cards/3_of_clubs.png differ
diff --git a/images/cards/3_of_diamonds.png b/images/cards/3_of_diamonds.png
new file mode 100644
index 00000000..8ee0b4b9
Binary files /dev/null and b/images/cards/3_of_diamonds.png differ
diff --git a/images/cards/3_of_hearts.png b/images/cards/3_of_hearts.png
new file mode 100644
index 00000000..8e74673f
Binary files /dev/null and b/images/cards/3_of_hearts.png differ
diff --git a/images/cards/3_of_spades.png b/images/cards/3_of_spades.png
new file mode 100644
index 00000000..f9e06b4f
Binary files /dev/null and b/images/cards/3_of_spades.png differ
diff --git a/images/cards/4_of_clubs.png b/images/cards/4_of_clubs.png
new file mode 100644
index 00000000..8be9e089
Binary files /dev/null and b/images/cards/4_of_clubs.png differ
diff --git a/images/cards/4_of_diamonds.png b/images/cards/4_of_diamonds.png
new file mode 100644
index 00000000..70e82e83
Binary files /dev/null and b/images/cards/4_of_diamonds.png differ
diff --git a/images/cards/4_of_hearts.png b/images/cards/4_of_hearts.png
new file mode 100644
index 00000000..ceecbfe0
Binary files /dev/null and b/images/cards/4_of_hearts.png differ
diff --git a/images/cards/4_of_spades.png b/images/cards/4_of_spades.png
new file mode 100644
index 00000000..95abe3e7
Binary files /dev/null and b/images/cards/4_of_spades.png differ
diff --git a/images/cards/5_of_clubs.png b/images/cards/5_of_clubs.png
new file mode 100644
index 00000000..bde97776
Binary files /dev/null and b/images/cards/5_of_clubs.png differ
diff --git a/images/cards/5_of_diamonds.png b/images/cards/5_of_diamonds.png
new file mode 100644
index 00000000..bb925255
Binary files /dev/null and b/images/cards/5_of_diamonds.png differ
diff --git a/images/cards/5_of_hearts.png b/images/cards/5_of_hearts.png
new file mode 100644
index 00000000..d923456f
Binary files /dev/null and b/images/cards/5_of_hearts.png differ
diff --git a/images/cards/5_of_spades.png b/images/cards/5_of_spades.png
new file mode 100644
index 00000000..53a1aad2
Binary files /dev/null and b/images/cards/5_of_spades.png differ
diff --git a/images/cards/6_of_clubs.png b/images/cards/6_of_clubs.png
new file mode 100644
index 00000000..a9660a03
Binary files /dev/null and b/images/cards/6_of_clubs.png differ
diff --git a/images/cards/6_of_diamonds.png b/images/cards/6_of_diamonds.png
new file mode 100644
index 00000000..78a80ad0
Binary files /dev/null and b/images/cards/6_of_diamonds.png differ
diff --git a/images/cards/6_of_hearts.png b/images/cards/6_of_hearts.png
new file mode 100644
index 00000000..361643ef
Binary files /dev/null and b/images/cards/6_of_hearts.png differ
diff --git a/images/cards/6_of_spades.png b/images/cards/6_of_spades.png
new file mode 100644
index 00000000..40242a71
Binary files /dev/null and b/images/cards/6_of_spades.png differ
diff --git a/images/cards/7_of_clubs.png b/images/cards/7_of_clubs.png
new file mode 100644
index 00000000..9d6b5455
Binary files /dev/null and b/images/cards/7_of_clubs.png differ
diff --git a/images/cards/7_of_diamonds.png b/images/cards/7_of_diamonds.png
new file mode 100644
index 00000000..6ad5f15b
Binary files /dev/null and b/images/cards/7_of_diamonds.png differ
diff --git a/images/cards/7_of_hearts.png b/images/cards/7_of_hearts.png
new file mode 100644
index 00000000..19b89a2e
Binary files /dev/null and b/images/cards/7_of_hearts.png differ
diff --git a/images/cards/7_of_spades.png b/images/cards/7_of_spades.png
new file mode 100644
index 00000000..b9f1b93d
Binary files /dev/null and b/images/cards/7_of_spades.png differ
diff --git a/images/cards/8_of_clubs.png b/images/cards/8_of_clubs.png
new file mode 100644
index 00000000..cec743cb
Binary files /dev/null and b/images/cards/8_of_clubs.png differ
diff --git a/images/cards/8_of_diamonds.png b/images/cards/8_of_diamonds.png
new file mode 100644
index 00000000..ed129512
Binary files /dev/null and b/images/cards/8_of_diamonds.png differ
diff --git a/images/cards/8_of_hearts.png b/images/cards/8_of_hearts.png
new file mode 100644
index 00000000..fb39723c
Binary files /dev/null and b/images/cards/8_of_hearts.png differ
diff --git a/images/cards/8_of_spades.png b/images/cards/8_of_spades.png
new file mode 100644
index 00000000..b6b3b381
Binary files /dev/null and b/images/cards/8_of_spades.png differ
diff --git a/images/cards/9_of_clubs.png b/images/cards/9_of_clubs.png
new file mode 100644
index 00000000..2174db58
Binary files /dev/null and b/images/cards/9_of_clubs.png differ
diff --git a/images/cards/9_of_diamonds.png b/images/cards/9_of_diamonds.png
new file mode 100644
index 00000000..0b933fb0
Binary files /dev/null and b/images/cards/9_of_diamonds.png differ
diff --git a/images/cards/9_of_hearts.png b/images/cards/9_of_hearts.png
new file mode 100644
index 00000000..7b196d6d
Binary files /dev/null and b/images/cards/9_of_hearts.png differ
diff --git a/images/cards/9_of_spades.png b/images/cards/9_of_spades.png
new file mode 100644
index 00000000..3c3b5ffb
Binary files /dev/null and b/images/cards/9_of_spades.png differ
diff --git a/images/cards/ace_of_clubs.png b/images/cards/ace_of_clubs.png
new file mode 100644
index 00000000..42bf5ec9
Binary files /dev/null and b/images/cards/ace_of_clubs.png differ
diff --git a/images/cards/ace_of_diamonds.png b/images/cards/ace_of_diamonds.png
new file mode 100644
index 00000000..79cd3b8a
Binary files /dev/null and b/images/cards/ace_of_diamonds.png differ
diff --git a/images/cards/ace_of_hearts.png b/images/cards/ace_of_hearts.png
new file mode 100644
index 00000000..b4221240
Binary files /dev/null and b/images/cards/ace_of_hearts.png differ
diff --git a/images/cards/ace_of_spades.png b/images/cards/ace_of_spades.png
new file mode 100644
index 00000000..103f56d1
Binary files /dev/null and b/images/cards/ace_of_spades.png differ
diff --git a/images/cards/back.png b/images/cards/back.png
new file mode 100644
index 00000000..84575a2a
Binary files /dev/null and b/images/cards/back.png differ
diff --git a/images/cards/jack_of_clubs.png b/images/cards/jack_of_clubs.png
new file mode 100644
index 00000000..5e003be2
Binary files /dev/null and b/images/cards/jack_of_clubs.png differ
diff --git a/images/cards/jack_of_diamonds.png b/images/cards/jack_of_diamonds.png
new file mode 100644
index 00000000..131a9773
Binary files /dev/null and b/images/cards/jack_of_diamonds.png differ
diff --git a/images/cards/jack_of_hearts.png b/images/cards/jack_of_hearts.png
new file mode 100644
index 00000000..bf342bcb
Binary files /dev/null and b/images/cards/jack_of_hearts.png differ
diff --git a/images/cards/jack_of_spades.png b/images/cards/jack_of_spades.png
new file mode 100644
index 00000000..f539c19c
Binary files /dev/null and b/images/cards/jack_of_spades.png differ
diff --git a/images/cards/king_of_clubs.png b/images/cards/king_of_clubs.png
new file mode 100644
index 00000000..68e57747
Binary files /dev/null and b/images/cards/king_of_clubs.png differ
diff --git a/images/cards/king_of_diamonds.png b/images/cards/king_of_diamonds.png
new file mode 100644
index 00000000..e21d6a0a
Binary files /dev/null and b/images/cards/king_of_diamonds.png differ
diff --git a/images/cards/king_of_hearts.png b/images/cards/king_of_hearts.png
new file mode 100644
index 00000000..1d3c468d
Binary files /dev/null and b/images/cards/king_of_hearts.png differ
diff --git a/images/cards/king_of_spades.png b/images/cards/king_of_spades.png
new file mode 100644
index 00000000..2edbbc14
Binary files /dev/null and b/images/cards/king_of_spades.png differ
diff --git a/images/cards/queen_of_clubs.png b/images/cards/queen_of_clubs.png
new file mode 100644
index 00000000..7be5f9a9
Binary files /dev/null and b/images/cards/queen_of_clubs.png differ
diff --git a/images/cards/queen_of_diamonds.png b/images/cards/queen_of_diamonds.png
new file mode 100644
index 00000000..928f6501
Binary files /dev/null and b/images/cards/queen_of_diamonds.png differ
diff --git a/images/cards/queen_of_hearts.png b/images/cards/queen_of_hearts.png
new file mode 100644
index 00000000..21839e68
Binary files /dev/null and b/images/cards/queen_of_hearts.png differ
diff --git a/images/cards/queen_of_spades.png b/images/cards/queen_of_spades.png
new file mode 100644
index 00000000..7983d034
Binary files /dev/null and b/images/cards/queen_of_spades.png differ
diff --git a/images/logo.png b/images/logo.png
new file mode 100644
index 00000000..61de30d1
Binary files /dev/null and b/images/logo.png differ
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..a6714ecd
--- /dev/null
+++ b/index.html
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+ Shaz's Video Poker Game!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Video Poker
+
+
+
+
+
+
+
+
1
+
2
+
3
+
4
+
5
+
+
+
+
+
Royal Flush
+
250
+
500
+
750
+
1000
+
4000
+
+
+
Straight Flush
+
50
+
100
+
150
+
200
+
250
+
+
+
Four Of A Kind
+
25
+
50
+
75
+
100
+
125
+
+
+
Full House
+
9
+
18
+
27
+
36
+
45
+
+
+
Flush
+
6
+
12
+
18
+
24
+
30
+
+
+
Straight
+
4
+
8
+
12
+
16
+
20
+
+
+
Three Of A Kind
+
3
+
6
+
9
+
12
+
15
+
+
+
Two Pair
+
2
+
4
+
6
+
8
+
10
+
+
+
+
+
+
+
+ Start by pressing Bet 1 or
+ Bet 5 and pressing
+ Deal after.
+
+
+
+
+
+
+
+
+
+
+
+ Total Combinations Available:
+ 1,533,939
+
+
+
Royal Flush: 0.00%
+
+ Straight Flush: 0.00%
+
+
+ Four Of A Kind: 0.00%
+
+
Full House: 0.00%
+
Flush: 0.00%
+
Straight: 0.00%
+
+ Three Of A Kind: 0.00%
+
+
Two Pair: 0.00%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bet: 0
+ /
+ Credits: 100
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 7c1c09b9..fd1fd5d8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1029,6 +1029,11 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
+ "nes.css": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/nes.css/-/nes.css-2.3.0.tgz",
+ "integrity": "sha512-lCFZs9vj3f5RVdbvTL/kSxiYsOARwSeAdJaMNo+bCgmWOO9x8ay7QpT4yQVKHy3r5Dttzd0uqVdpt3fvvx6EpQ=="
+ },
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
diff --git a/package.json b/package.json
index 1bf85b18..ba5ab359 100644
--- a/package.json
+++ b/package.json
@@ -1,24 +1,27 @@
-{
- "name": "video-poker-swe1",
- "version": "1.0.0",
- "description": "SWE1 Video Poker",
- "main": "script.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/rocketacademy/video-poker-swe1.git"
- },
- "author": "",
- "license": "ISC",
- "bugs": {
- "url": "https://github.com/rocketacademy/video-poker-swe1/issues"
- },
- "homepage": "https://github.com/rocketacademy/video-poker-swe1#readme",
- "devDependencies": {
- "eslint": "^7.6.0",
- "eslint-config-airbnb-base": "^14.2.0",
- "eslint-plugin-import": "^2.22.0"
- }
-}
+{
+ "name": "video-poker-swe1",
+ "version": "1.0.0",
+ "description": "SWE1 Video Poker",
+ "main": "script.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/rocketacademy/video-poker-swe1.git"
+ },
+ "author": "",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/rocketacademy/video-poker-swe1/issues"
+ },
+ "homepage": "https://github.com/rocketacademy/video-poker-swe1#readme",
+ "devDependencies": {
+ "eslint": "^7.6.0",
+ "eslint-config-airbnb-base": "^14.2.0",
+ "eslint-plugin-import": "^2.22.0"
+ },
+ "dependencies": {
+ "nes.css": "^2.3.0"
+ }
+}
diff --git a/scripts/checkCombination.js b/scripts/checkCombination.js
new file mode 100644
index 00000000..28cc173b
--- /dev/null
+++ b/scripts/checkCombination.js
@@ -0,0 +1,1654 @@
+/**
+ *
+ * @param {Number} number of items to be rearranged
+ * @returns {Number} number of permutations to arrange num distinct objects into an ordered sequence
+ */
+const factorialize = (num) => {
+ if (num < 0) return -1;
+ if (num === 0) return 1;
+ return (num * factorialize(num - 1));
+};
+
+/**
+ *
+ * @param {Number} [numberOfCardsLeft] - number of cards still left in the deck yet to be drawn
+ * @param {Number} [cardsToDraw] - number of cards to be drawn
+ * @returns {Number} number of ways to choose a sample of [cardsToDraw] cards from a set of [numberOfCardsLeft] cards where order does not matter and replacements are allowed.
+ */
+const countTotalCombinations = (numberOfCardsLeft, cardsToDraw) => {
+ const numerator = factorialize(numberOfCardsLeft);
+ const denominator = (factorialize(numberOfCardsLeft - cardsToDraw) * factorialize(cardsToDraw));
+
+ return numerator / denominator;
+};
+
+/**
+ *
+ * @returns {Number} number of royal flush combinations that can be achieved with cards being held
+ */
+const checkRoyalFlushCombinations = () => {
+ const royalResult = isHeldCardsRoyal(stats.hand);
+ const flushResult = isHeldCardsSameSuit(stats.hand);
+
+ // check whether same suit first
+ if (flushResult.result && royalResult.result) {
+ // check what are the remaining cards to draw to get a royal flush
+ if (royalResult.royalHand.ace !== 1) {
+ // check if card is available
+ if (cardsLeft.ace[flushResult.suit] !== 1) {
+ return 0;
+ }
+ }
+
+ if (royalResult.royalHand.king !== 1) {
+ // check if card is available
+ if (cardsLeft.king[flushResult.suit] !== 1) {
+ return 0;
+ }
+ }
+
+ if (royalResult.royalHand.queen !== 1) {
+ // check if card is available
+ if (cardsLeft.queen[flushResult.suit] !== 1) {
+ return 0;
+ }
+ }
+
+ if (royalResult.royalHand.jack !== 1) {
+ // check if card is available
+ if (cardsLeft.jack[flushResult.suit] !== 1) {
+ return 0;
+ }
+ }
+
+ if (royalResult.royalHand[10] !== 1) {
+ // check if card is available
+ if (cardsLeft[10][flushResult.suit] !== 1) {
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+ return 0;
+};
+
+/**
+ *
+ * @returns {Number} number of straight flush combinations that can be achieved with cards being held
+ */
+const checkStraightFlushCombinations = () => {
+ const flushResult = isHeldCardsSameSuit(stats.hand);
+ const withinStraightResult = isHeldCardsWithinStraight(stats.hand);
+
+ let combinations = 0;
+
+ if (flushResult.result && withinStraightResult.result) {
+ const { straightHand } = withinStraightResult;
+ const { diff } = withinStraightResult;
+ const { suit } = flushResult;
+
+ // check all the different cards i need to draw
+ // if i have rank 1 and 5, 1 and 5 are the limits (diff = 4)
+ // and i can only find 3, 4 ane 5
+ // if i have rank 2 and 5, 1 and 6 are the limits (diff = 3)
+ // e.g. 1,2,3,4,5 or 2,3,4,5,6
+ // if i have rank 5 and 7, 3 and 9 are the limits (diff = 2)
+ // e.g. 3,4,5,6,7 or 5,6,7,8,9
+ // if i have rank 5 and 6, 2 and 9 are the limits (diff = 1)
+ // e.g. 2,3,4,5,6,7 or 5,6,7,8,9
+
+ const rankArray = Object.keys(straightHand);
+
+ if (diff === 4) {
+ let straightPossible = true;
+
+ const firstRank = parseInt(rankArray[0], 10);
+
+ for (let i = 1; i < 5; i += 1) {
+ if (rankArray.indexOf((firstRank + i).toString()) === -1) {
+ // current rank is not in held cards
+ // find in cardsLeft
+ if (cardsLeft[(firstRank + i).toString()][suit] === 0) {
+ straightPossible = false;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ } else if (diff === 3) {
+ let straightPossible = true;
+
+ const firstRank1 = parseInt(rankArray[0], 10);
+ const lastRank1 = firstRank1 + 4;
+
+ for (let i = firstRank1; i <= lastRank1; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 1 > 0) {
+ const firstRank2 = parseInt(rankArray[0], 10) - 1;
+ const lastRank2 = firstRank2 + 4;
+
+ for (let i = firstRank2; i <= lastRank2; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+ } else if (diff === 2) {
+ let straightPossible = true;
+
+ const firstRank1 = parseInt(rankArray[0], 10) - 1;
+ const lastRank1 = firstRank1 + 4;
+
+ for (let i = firstRank1; i <= lastRank1; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 1 > 0) {
+ const firstRank2 = parseInt(rankArray[0], 10) - 1;
+ const lastRank2 = firstRank2 + 4;
+
+ for (let i = firstRank2; i <= lastRank2; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 2 > 0) {
+ const firstRank3 = parseInt(rankArray[0], 10) - 2;
+ const lastRank3 = firstRank3 + 4;
+
+ for (let i = firstRank3; i <= lastRank3; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+ } else if (diff === 1) {
+ let straightPossible = true;
+
+ const firstRank1 = parseInt(rankArray[0], 10) - 1;
+ const lastRank1 = firstRank1 + 4;
+
+ for (let i = firstRank1; i <= lastRank1; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 1 > 0) {
+ const firstRank2 = parseInt(rankArray[0], 10) - 1;
+ const lastRank2 = firstRank2 + 4;
+
+ for (let i = firstRank2; i <= lastRank2; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 2 > 0) {
+ const firstRank3 = parseInt(rankArray[0], 10) - 2;
+ const lastRank3 = firstRank3 + 4;
+
+ for (let i = firstRank3; i <= lastRank3; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+
+ if (parseInt(rankArray[0], 10) - 3 > 0) {
+ const firstRank4 = parseInt(rankArray[0], 10) - 3;
+ const lastRank4 = firstRank4 + 4;
+
+ for (let i = firstRank4; i <= lastRank4; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+ } else if (diff === 0) {
+ let straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) !== 0) {
+ const firstRank1 = parseInt(rankArray[0], 10);
+ const lastRank1 = firstRank1 + 4;
+
+ for (let i = firstRank1; i <= lastRank1; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 1 > 0) {
+ const firstRank2 = parseInt(rankArray[0], 10) - 1;
+ const lastRank2 = firstRank2 + 4;
+
+ for (let i = firstRank2; i <= lastRank2; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 2 > 0) {
+ const firstRank3 = parseInt(rankArray[0], 10) - 2;
+ const lastRank3 = firstRank3 + 4;
+
+ for (let i = firstRank3; i <= lastRank3; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 3 > 0) {
+ const firstRank4 = parseInt(rankArray[0], 10) - 3;
+ const lastRank4 = firstRank4 + 4;
+
+ for (let i = firstRank4; i <= lastRank4; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+
+ straightPossible = true;
+
+ if (parseInt(rankArray[0], 10) - 4 > 0) {
+ const firstRank5 = parseInt(rankArray[0], 10) - 4;
+ const lastRank5 = firstRank5 + 4;
+
+ for (let i = firstRank5; i <= lastRank5; i += 1) {
+ if (straightHand[i] === undefined) {
+ if (i === 1) {
+ if (cardsLeft.ace[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 11) {
+ if (cardsLeft.jack[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 12) {
+ if (cardsLeft.queen[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i === 13) {
+ if (cardsLeft.king[suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ } else if (i > 13) {
+ straightPossible = false;
+ break;
+ } else if (cardsLeft[i][suit] === 0) {
+ straightPossible = false;
+ break;
+ }
+ }
+ }
+
+ if (straightPossible) {
+ combinations += 1;
+ }
+ }
+ }
+
+ return combinations;
+ }
+
+ return 0;
+};
+
+/**
+ *
+ * @returns {Number} number of two pair combinations that can be achieved with cards being held
+ */
+const checkTwoPairCombinations = () => {
+ const result = {
+ combinations: 0,
+ alreadyWin: false,
+ };
+ let combinations = 0;
+
+ // get the cards being held first
+ const twoPairHand = {};
+
+ for (let i = 0; i < stats.hand.length; i += 1) {
+ if (stats.hand[i].hold === true) {
+ if (twoPairHand[stats.hand[i].rank] === undefined) {
+ twoPairHand[stats.hand[i].rank] = 1;
+ } else {
+ twoPairHand[stats.hand[i].rank] += 1;
+ }
+ }
+ }
+
+ const rankArray = Object.keys(twoPairHand);
+
+ const twoPairHandValues = Object.values(twoPairHand);
+ const twoPairHandCardLeft = [];
+
+ for (let i = 0; i < rankArray.length; i += 1) {
+ const rank = parseInt(rankArray[i], 10);
+
+ const cardsLeftWithRank = getCardsLeftWithRank(rank);
+
+ twoPairHandCardLeft.push(cardsLeftWithRank);
+ }
+
+ let twoCounts = 0;
+
+ for (let i = 0; i < twoPairHandValues.length; i += 1) {
+ if (twoPairHandValues[i] === 2) {
+ twoCounts += 1;
+ }
+ }
+
+ if (Object.values(twoPairHand).length === 5 || rankArray.length >= 4) {
+ combinations = 0;
+ } else if (twoCounts === 2) {
+ result.alreadyWin = true;
+ combinations = 1;
+ } else if (rankArray.length === 3) {
+ const rank1Held = twoPairHandValues[0];
+ const rank1Left = twoPairHandCardLeft[0];
+
+ const rank2Held = twoPairHandValues[1];
+ const rank2Left = twoPairHandCardLeft[1];
+
+ const rank3Held = twoPairHandValues[2];
+ const rank3Left = twoPairHandCardLeft[2];
+
+ if (rank1Held <= 2 && rank2Held <= 2 && rank3Held <= 2) {
+
+ let tempCombinations = 0;
+
+ let rank1 = parseInt(rankArray[0], 10);
+
+ if (rank1 === 1) {
+ rank1 = 'ace';
+ } else if (rank1 === 11) {
+ rank1 = 'jack';
+ } else if (rank1 === 12) {
+ rank1 = 'queen';
+ } else if (rank1 === 13) {
+ rank1 = 'king';
+ }
+
+ let rank2 = parseInt(rankArray[1], 10);
+
+ if (rank2 === 1) {
+ rank2 = 'ace';
+ } else if (rank2 === 11) {
+ rank2 = 'jack';
+ } else if (rank2 === 12) {
+ rank2 = 'queen';
+ } else if (rank2 === 13) {
+ rank2 = 'king';
+ }
+
+ let rank3 = parseInt(rankArray[1], 10);
+
+ if (rank3 === 1) {
+ rank3 = 'ace';
+ } else if (rank3 === 11) {
+ rank3 = 'jack';
+ } else if (rank3 === 12) {
+ rank3 = 'queen';
+ } else if (rank3 === 13) {
+ rank3 = 'king';
+ }
+
+ const cardsLeftKeys = Object.keys(cardsLeft);
+ const cardsLeftValues = Object.values(cardsLeft);
+
+ // set 1: 2 of Rank A 2 of Rank B 1 of Rank C
+ if ((rank1Left + rank1Held >= 2) && (rank2Left + rank2Held >= 2)) {
+ const rank1Combinations = countTotalCombinations(rank1Left, 2 - rank1Held);
+ const rank2Combinations = countTotalCombinations(rank2Left, 2 - rank2Held);
+
+ tempCombinations += (rank1Combinations * rank2Combinations);
+ } else {
+ tempCombinations = 0;
+ }
+
+ combinations += tempCombinations;
+
+ tempCombinations = 0;
+
+ // set 2: 2 of Rank A 1 of Rank B 2 of Rank C
+ if ((rank1Left + rank1Held >= 2) && (rank3Left + rank3Held >= 2)) {
+ const rank1Combinations = countTotalCombinations(rank1Left, 2 - rank1Held);
+ const rank3Combinations = countTotalCombinations(rank3Left, 2 - rank3Held);
+
+ tempCombinations += (rank1Combinations * rank3Combinations);
+ } else {
+ tempCombinations = 0;
+ }
+
+ combinations += tempCombinations;
+
+ tempCombinations = 0;
+
+ // set 3: 1 of Rank A 2 of Rank B 2 of Rank C
+ if ((rank2Left + rank2Held >= 2) && (rank3Left + rank3Held >= 2)) {
+ const rank2Combinations = countTotalCombinations(rank2Left, 2 - rank2Held);
+ const rank3Combinations = countTotalCombinations(rank3Left, 2 - rank3Held);
+
+ tempCombinations += (rank2Combinations * rank3Combinations);
+ } else {
+ tempCombinations = 0;
+ }
+
+ combinations += tempCombinations;
+ }
+ } else if (rankArray.length === 2) {
+ const rank1Held = twoPairHandValues[0];
+ const rank1Left = twoPairHandCardLeft[0];
+
+ const rank2Held = twoPairHandValues[1];
+ const rank2Left = twoPairHandCardLeft[1];
+
+ if (rank1Held <= 2 && rank2Held <= 2) {
+
+ let tempCombinations = 0;
+
+ // if i am holding to 2 and 4
+ // i need to have different conditions
+
+ let rank1 = parseInt(rankArray[0], 10);
+
+ if (rank1 === 1) {
+ rank1 = 'ace';
+ } else if (rank1 === 11) {
+ rank1 = 'jack';
+ } else if (rank1 === 12) {
+ rank1 = 'queen';
+ } else if (rank1 === 13) {
+ rank1 = 'king';
+ }
+
+ let rank2 = parseInt(rankArray[1], 10);
+
+ if (rank2 === 1) {
+ rank2 = 'ace';
+ } else if (rank2 === 11) {
+ rank2 = 'jack';
+ } else if (rank2 === 12) {
+ rank2 = 'queen';
+ } else if (rank2 === 13) {
+ rank2 = 'king';
+ }
+
+ const cardsLeftKeys = Object.keys(cardsLeft);
+ const cardsLeftValues = Object.values(cardsLeft);
+
+ // set 1: two 2s one 4 and two of other cards
+ if (rank1Left + rank1Held >= 2) {
+ const rank1Combinations = countTotalCombinations(rank1Left, 2 - rank1Held);
+
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ let tempCombi = 0;
+ if (cardsLeftKeys[i] !== rank1 && cardsLeftKeys[i] !== rank2) {
+ const tempCardLeftValue = getCardsLeftWithRank(cardsLeftKeys[i]);
+ if (tempCardLeftValue >= 2) {
+ tempCombi = countTotalCombinations(tempCardLeftValue, 2);
+ } else {
+ tempCombi = 0;
+ }
+
+ tempCombinations += (rank1Combinations * tempCombi);
+ }
+ }
+ } else {
+ tempCombinations = 0;
+ }
+
+ combinations += tempCombinations;
+
+ tempCombinations = 0;
+
+ // set 2: one 2 two 4s and two of other cards
+ if (rank2Left + rank2Held >= 2) {
+ const rank2Combinations = countTotalCombinations(rank2Left, 2 - rank2Held);
+
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ let tempCombi = 0;
+ if (cardsLeftKeys[i] !== rank1 && cardsLeftKeys[i] !== rank2) {
+ const tempCardLeftValue = getCardsLeftWithRank(cardsLeftKeys[i]);
+ if (tempCardLeftValue >= 2) {
+ tempCombi = countTotalCombinations(tempCardLeftValue, 2);
+ } else {
+ tempCombi = 0;
+ }
+
+ tempCombinations += (rank2Combinations * tempCombi);
+ }
+ }
+ } else {
+ tempCombinations = 0;
+ }
+
+ combinations += tempCombinations;
+ }
+ } else if (rankArray.length === 1) {
+ const rankHeld = twoPairHandValues[0];
+ const rankLeft = twoPairHandCardLeft[0];
+
+ if (rankHeld <= 2) {
+ let rank = parseInt(rankArray[0], 10);
+
+ if (rank === 1) {
+ rank = 'ace';
+ } else if (rank === 11) {
+ rank = 'jack';
+ } else if (rank === 12) {
+ rank = 'queen';
+ } else if (rank === 13) {
+ rank = 'king';
+ }
+
+ const cardsLeftKeys = Object.keys(cardsLeft);
+ const cardsLeftValues = Object.values(cardsLeft);
+
+ // set 1: 2 of rank 1, 2 of any other number, 1 of any other number
+ if ((rankLeft + rankHeld) >= 2) {
+ const rankCombinations = countTotalCombinations(rankLeft, 2 - rankHeld);
+
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ let tempCombinations = 0;
+ if (cardsLeftKeys[i] !== rank) {
+ const tempCardLeftValue = getCardsLeftWithRank(cardsLeftKeys[i]);
+ if (tempCardLeftValue >= 2) {
+ // there is enough of this second rank to fill up the second pair
+ tempCombinations = countTotalCombinations(tempCardLeftValue, 2);
+ } else {
+ // there is not enough of this second rank to fill up the second pair
+ // need to rely on third rank
+ tempCombinations = 0;
+ }
+
+ const totalCardsLeft = 47 - tempCardLeftValue;
+ const remainingCombinations = countTotalCombinations(totalCardsLeft, 1);
+
+ combinations += (rankCombinations * tempCombinations * remainingCombinations);
+ }
+ }
+ } else {
+ // set 2: 1 of rank 1, 2 of any other number, 2 of any other number
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ let tempCombinations = 0;
+ if (cardsLeftKeys[i] !== rank) {
+ const tempCardLeftValue = getCardsLeftWithRank(cardsLeftKeys[i]);
+ if (tempCardLeftValue >= 2) {
+ // there is enough of this second rank to fill up the second pair
+ tempCombinations = countTotalCombinations(tempCardLeftValue, 2);
+ for (let j = 0; j < cardsLeftKeys.length; j += 1) {
+ if (cardsLeftKeys[j] !== cardsLeftKeys[i] && cardsLeftKeys[j] !== rank) {
+ const tempCardLeftValue2 = getCardsLeftWithRank(cardsLeftKeys[j]);
+
+ if (tempCardLeftValue2 >= 2) {
+ tempCombinations *= countTotalCombinations(tempCardLeftValue2, 2);
+ } else {
+ tempCombinations = 0;
+ }
+
+ combinations += tempCombinations;
+ }
+ }
+ } else {
+ // there is not enough of this second rank to fill up the second pair
+ // need to rely on third rank
+ tempCombinations = 0;
+ }
+
+ combinations += tempCombinations;
+ }
+ }
+ }
+ }
+ }
+
+ result.combinations = combinations;
+ return result;
+};
+
+/**
+ *
+ * @returns {Number} number of three of a kind combinations that can be achieved with cards being held
+ */
+const checkThreeOfAKindCombinations = () => {
+ const result = {
+ combinations: 0,
+ alreadyWin: false,
+ };
+ let combinations = 0;
+
+ // get the cards being held first
+ const threeOfAKindHand = {};
+
+ for (let i = 0; i < stats.hand.length; i += 1) {
+ if (stats.hand[i].hold === true) {
+ if (threeOfAKindHand[stats.hand[i].rank] === undefined) {
+ threeOfAKindHand[stats.hand[i].rank] = 1;
+ } else {
+ threeOfAKindHand[stats.hand[i].rank] += 1;
+ }
+ }
+ }
+
+ const rankArray = Object.keys(threeOfAKindHand);
+
+ if (Object.values(threeOfAKindHand).length >= 4) {
+ // if there are 3 different card ranks are being held, return 0
+ combinations = 0;
+ } else if (Object.values(threeOfAKindHand).indexOf(3) !== -1) {
+ // if there are already 4 cards with the same rank being held, return 1
+ combinations = 1;
+ result.alreadyWin = true;
+ } else {
+ for (let i = 0; i < rankArray.length; i += 1) {
+ const rank = parseInt(rankArray[i], 10);
+ const noOfCardsHeld = threeOfAKindHand[rank];
+
+ const noOfCardsLeft = getCardsLeftWithRank(rank);
+
+ if (noOfCardsHeld + noOfCardsLeft >= 3) {
+ combinations += 1;
+ }
+ }
+ }
+
+ result.combinations = combinations;
+
+ return result;
+};
+
+/**
+ *
+ * @returns {Number} number of four of a kind combinations that can be achieved with cards being held
+ */
+const checkFourOfAKindCombinations = () => {
+ const result = {
+ combinations: 0,
+ alreadyWin: false,
+ };
+ let combinations = 0;
+
+ // get the cards being held first
+ const fourOfAKindHand = {};
+
+ for (let i = 0; i < stats.hand.length; i += 1) {
+ if (stats.hand[i].hold === true) {
+ if (fourOfAKindHand[stats.hand[i].rank] === undefined) {
+ fourOfAKindHand[stats.hand[i].rank] = 1;
+ } else {
+ fourOfAKindHand[stats.hand[i].rank] += 1;
+ }
+ }
+ }
+
+ const rankArray = Object.keys(fourOfAKindHand);
+
+ if (Object.values(fourOfAKindHand).length >= 3) {
+ // if there are 3 different card ranks are being held, return 0
+ combinations = 0;
+ } else if (Object.values(fourOfAKindHand).indexOf(4) !== -1) {
+ // if there are already 4 cards with the same rank being held, return 1
+ combinations = 1;
+ result.alreadyWin = true;
+ } else {
+ for (let i = 0; i < rankArray.length; i += 1) {
+ const rank = parseInt(rankArray[i], 10);
+ const noOfCardsHeld = fourOfAKindHand[rank];
+
+ const noOfCardsLeft = getCardsLeftWithRank(rank);
+
+ if (noOfCardsHeld + noOfCardsLeft === 4) {
+ combinations += 1;
+ }
+ }
+ }
+ result.combinations = combinations;
+
+ return result;
+};
+
+/**
+ *
+ * @returns {Number} number of full house combinations that can be achieved with cards being held
+ */
+const checkFullHouseCombinations = () => {
+ const result = {
+ combinations: 0,
+ alreadyWin: false,
+ };
+ let combinations = 0;
+
+ // get the cards being held first
+ const fullHouseHand = {};
+
+ for (let i = 0; i < stats.hand.length; i += 1) {
+ if (stats.hand[i].hold === true) {
+ if (fullHouseHand[stats.hand[i].rank] === undefined) {
+ if (stats.hand[i].rank === 11) {
+ fullHouseHand.jack = 1;
+ } else if (stats.hand[i].rank === 12) {
+ fullHouseHand.queen = 1;
+ } else if (stats.hand[i].rank === 13) {
+ fullHouseHand.king = 1;
+ } else if (stats.hand[i].rank === 1) {
+ fullHouseHand.ace = 1;
+ } else {
+ fullHouseHand[stats.hand[i].rank] = 1;
+ }
+ } else if (stats.hand[i].rank === 11) {
+ fullHouseHand.jack += 1;
+ } else if (stats.hand[i].rank === 12) {
+ fullHouseHand.queen += 1;
+ } else if (stats.hand[i].rank === 13) {
+ fullHouseHand.king += 1;
+ } else if (stats.hand[i].rank === 1) {
+ fullHouseHand.ace += 1;
+ } else {
+ fullHouseHand[stats.hand[i].rank] += 1;
+ }
+ }
+ }
+
+ const rankArray = Object.keys(fullHouseHand);
+
+ if (rankArray.length >= 3) {
+ combinations = 0;
+ } else if (rankArray.length === 2) {
+ // given the two different ranks A and B, i need to find out
+ // different combinations of 3 As 2 Bs and 2 As 3 Bs.
+
+ const rank1 = rankArray[0];
+ const noOfRank1CardsHeld = fullHouseHand[rank1];
+ const noOfRank1CardsLeft = getCardsLeftWithRank(rank1);
+
+ const rank2 = rankArray[1];
+ const noOfRank2CardsHeld = fullHouseHand[rank2];
+ const noOfRank2CardsLeft = getCardsLeftWithRank(rank2);
+
+ // 3 of Rank1Cards 2 of Rank2Cards
+ if (noOfRank1CardsHeld === 3) {
+ if (noOfRank2CardsLeft >= (2 - noOfRank2CardsHeld)) {
+ combinations += countTotalCombinations(noOfRank2CardsLeft, 2 - noOfRank2CardsHeld);
+ }
+ } else if (noOfRank1CardsHeld < 3) {
+ if (noOfRank1CardsLeft >= (3 - noOfRank1CardsHeld)) {
+ const rank1TotalCombinations = countTotalCombinations(noOfRank1CardsLeft,
+ 3 - noOfRank1CardsHeld);
+ if (noOfRank2CardsLeft >= (2 - noOfRank2CardsHeld)) {
+ combinations += (rank1TotalCombinations
+ * countTotalCombinations(noOfRank2CardsLeft, 2 - noOfRank2CardsHeld));
+ }
+ }
+ }
+
+ // 2 of Rank1Cards 3 of Rank2Cards
+ if (noOfRank1CardsHeld === 2) {
+ if (noOfRank2CardsLeft >= (3 - noOfRank2CardsHeld)) {
+ combinations += countTotalCombinations(noOfRank2CardsLeft, 3 - noOfRank2CardsHeld);
+ }
+ } else if (noOfRank1CardsHeld < 2) {
+ if (noOfRank1CardsLeft >= (2 - noOfRank1CardsHeld)) {
+ const rank1TotalCombinations = countTotalCombinations(noOfRank1CardsLeft,
+ 2 - noOfRank1CardsHeld);
+ if (noOfRank2CardsLeft >= (3 - noOfRank2CardsHeld)) {
+ combinations += (rank1TotalCombinations
+ * countTotalCombinations(noOfRank2CardsLeft, 3 - noOfRank2CardsHeld));
+ }
+ }
+ }
+ } else if (rankArray.length === 1) {
+ // if there is only 1 rank A, i need to find out
+ // different combinations of 3 As 2 Of Everything Else and
+ // 2 As 3 Of Everything Else
+
+ const rank1 = rankArray[0];
+ const noOfRank1CardsHeld = fullHouseHand[rank1];
+ const noOfRank1CardsLeft = getCardsLeftWithRank(rank1);
+ const totalRank1Cards = noOfRank1CardsHeld + noOfRank1CardsLeft;
+
+ const cardsLeftKeys = Object.keys(cardsLeft);
+ const cardsLeftValues = Object.values(cardsLeft);
+
+ for (let i = 0; i < cardsLeftValues.length; i += 1) {
+ cardsLeftValues[i] = getCardsLeftWithRank(cardsLeftKeys[i]);
+ }
+
+ // 3 of Rank1Cards 2 of Rank2Cards
+ if (noOfRank1CardsHeld === 3) {
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ if (cardsLeftValues[i] >= 2) {
+ combinations += countTotalCombinations(cardsLeftValues[i], 2);
+ }
+ }
+ } else if (noOfRank1CardsHeld < 3) {
+ if (noOfRank1CardsLeft >= (3 - noOfRank1CardsHeld)) {
+ const rank1TotalCombinations = countTotalCombinations(noOfRank1CardsLeft,
+ 3 - noOfRank1CardsHeld);
+
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ if (cardsLeftValues[i] >= 2) {
+ combinations += (rank1TotalCombinations * countTotalCombinations(cardsLeftValues[i], 2));
+ }
+ }
+ }
+ }
+
+ // 2 of Rank1Cards 3 of Rank2Cards
+ if (noOfRank1CardsHeld === 2) {
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ if (cardsLeftValues[i] >= 3) {
+ combinations += countTotalCombinations(cardsLeftValues[i], 3);
+ }
+ }
+ } else if (noOfRank1CardsHeld < 2) {
+ if (noOfRank1CardsLeft >= (2 - noOfRank1CardsHeld)) {
+ const rank1TotalCombinations = countTotalCombinations(noOfRank1CardsLeft,
+ 2 - noOfRank1CardsHeld);
+
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ if (cardsLeftValues[i] >= 3) {
+ combinations += (rank1TotalCombinations * countTotalCombinations(cardsLeftValues[i], 3));
+ }
+ }
+ }
+ }
+ }
+
+ result.combinations = combinations;
+
+ return result;
+};
+
+/**
+ *
+ * @returns {Number} number of flush combinations that can be achieved with cards being held
+ */
+const checkFlushCombinations = () => {
+ let combinations = 0;
+ const flushHand = {};
+
+ for (let i = 0; i < stats.hand.length; i += 1) {
+ if (stats.hand[i].hold === true) {
+ if (flushHand[stats.hand[i].suit] === undefined) {
+ flushHand[stats.hand[i].suit] = 1;
+ } else {
+ flushHand[stats.hand[i].suit] += 1;
+ }
+ }
+ }
+
+ const cardsLeftValues = Object.values(cardsLeft);
+
+ if (Object.keys(flushHand).length > 1) {
+ combinations = 0;
+ } else {
+ const suit = Object.keys(flushHand)[0];
+ const cardsHeld = Object.values(flushHand)[0];
+
+ let cardsLeftWithSuit = 0;
+
+ for (let i = 0; i < cardsLeftValues.length; i += 1) {
+ cardsLeftWithSuit += cardsLeftValues[i][suit];
+ }
+
+ combinations = countTotalCombinations(cardsLeftWithSuit, 5 - cardsHeld);
+ }
+
+ return combinations;
+};
+
+/**
+ *
+ * @returns {Number} number of straight combinations that can be achieved with cards being held
+ */
+const checkStraightCombinations = () => {
+ const withinStraightResult = isHeldCardsWithinStraight(stats.hand);
+
+ let combinations = 0;
+
+ if (withinStraightResult.result) {
+ const { straightHand } = withinStraightResult;
+ const { diff } = withinStraightResult;
+
+ const rankArray = Object.keys(straightHand);
+
+ if (diff > 4) {
+ combinations = 0;
+ } else if (diff === 4) {
+ const firstRank = parseInt(rankArray[0], 10);
+
+ combinations = 1;
+
+ for (let i = 1; i < 5; i += 1) {
+ if (rankArray.indexOf((firstRank + i).toString()) === -1) {
+ // current rank is not in held cards
+ // find in cardsLeft
+
+ const cardsLeftWithRank = getCardsLeftWithRank(firstRank + i);
+
+ if (cardsLeftWithRank > 0) {
+ combinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ combinations = 0;
+ }
+ }
+ }
+ } else if (diff === 3) {
+ let tempCombinations = 1;
+
+ const firstRank = parseInt(rankArray[0], 10);
+ const lastRank = firstRank + 4;
+
+ for (let i = firstRank; i <= lastRank; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+
+ tempCombinations = 1;
+
+ const firstRank1 = parseInt(rankArray[0], 10) - 1;
+ if (firstRank1 > 0) {
+ const lastRank1 = firstRank1 + 4;
+
+ for (let i = firstRank1; i <= lastRank1; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+ } else if (diff === 2) {
+ let tempCombinations = 1;
+
+ const firstRank = parseInt(rankArray[0], 10);
+ const lastRank = firstRank + 4;
+
+ for (let i = firstRank; i <= lastRank; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+
+ tempCombinations = 1;
+
+ const firstRank1 = parseInt(rankArray[0], 10) - 1;
+ if (firstRank1 > 0) {
+ const lastRank1 = firstRank1 + 4;
+
+ for (let i = firstRank1; i <= lastRank1; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+
+ tempCombinations = 1;
+
+ const firstRank2 = parseInt(rankArray[0], 10) - 2;
+ if (firstRank2 > 0) {
+ const lastRank2 = firstRank2 + 4;
+
+ for (let i = firstRank2; i <= lastRank2; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+ } else if (diff === 1) {
+ let tempCombinations = 1;
+
+ const firstRank = parseInt(rankArray[0], 10);
+ const lastRank = firstRank + 4;
+
+ for (let i = firstRank; i <= lastRank; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+
+ tempCombinations = 1;
+
+ const firstRank1 = parseInt(rankArray[0], 10) - 1;
+ if (firstRank1 > 0) {
+ const lastRank1 = firstRank1 + 4;
+
+ for (let i = firstRank1; i <= lastRank1; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+
+ tempCombinations = 1;
+
+ const firstRank2 = parseInt(rankArray[0], 10) - 2;
+ if (firstRank2 > 0) {
+ const lastRank2 = firstRank2 + 4;
+
+ for (let i = firstRank2; i <= lastRank2; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+
+ tempCombinations = 1;
+
+ const firstRank3 = parseInt(rankArray[0], 10) - 3;
+ if (firstRank3 > 0) {
+ const lastRank3 = firstRank3 + 4;
+
+ for (let i = firstRank3; i <= lastRank3; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+ } else if (diff === 0) {
+ let tempCombinations = 1;
+
+ const firstRank = parseInt(rankArray[0], 10);
+ const lastRank = firstRank + 4;
+
+ for (let i = firstRank; i <= lastRank; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+
+ tempCombinations = 1;
+
+ const firstRank1 = parseInt(rankArray[0], 10) - 1;
+ if (firstRank1 > 0) {
+ const lastRank1 = firstRank1 + 4;
+
+ for (let i = firstRank1; i <= lastRank1; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+
+ tempCombinations = 1;
+
+ const firstRank2 = parseInt(rankArray[0], 10) - 2;
+ if (firstRank2 > 0) {
+ const lastRank2 = firstRank2 + 4;
+
+ for (let i = firstRank2; i <= lastRank2; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+
+ tempCombinations = 1;
+
+ const firstRank3 = parseInt(rankArray[0], 10) - 3;
+ if (firstRank3 > 0) {
+ const lastRank3 = firstRank3 + 4;
+
+ for (let i = firstRank3; i <= lastRank3; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+
+ tempCombinations = 1;
+
+ const firstRank4 = parseInt(rankArray[0], 10) - 3;
+ if (firstRank4 > 0) {
+ const lastRank4 = firstRank4 + 4;
+
+ for (let i = firstRank4; i <= lastRank4; i += 1) {
+ if ((rankArray.indexOf((i).toString()) === -1) && (i < 15)) {
+ const cardsLeftWithRank = getCardsLeftWithRank(i);
+
+ if (cardsLeftWithRank > 0) {
+ tempCombinations *= countTotalCombinations(cardsLeftWithRank, 1);
+ } else {
+ tempCombinations = 0;
+ }
+ }
+ }
+
+ combinations += tempCombinations;
+ }
+ }
+ }
+
+ return combinations;
+};
diff --git a/scripts/checkHand.js b/scripts/checkHand.js
new file mode 100644
index 00000000..493b176d
--- /dev/null
+++ b/scripts/checkHand.js
@@ -0,0 +1,302 @@
+/**
+ *
+ * @param {Object} stats object containing the current hand with number of suits and number of ranks
+ * @returns {Boolean} true if current hand is four of a kind
+ */
+const checkFourOfAKindHand = (input) => {
+ const nameCount = Object.values(input.name);
+
+ if (nameCount.indexOf(4) !== -1) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ *
+ * @param {Object} stats object containing the current hand with number of suits and number of ranks
+ * @returns {Boolean} true if current hand is full house
+ */
+const checkFullHouseHand = (input) => {
+ const nameCount = Object.values(input.name);
+
+ if (nameCount.indexOf(3) !== -1 && nameCount.indexOf(2) !== -1) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ *
+ * @param {Object} stats object containing the current hand with number of suits and number of ranks
+ * @returns {Boolean} true if current hand is flush
+ */
+const checkFlushHand = (input) => {
+ const suitCount = Object.values(input.suit);
+
+ if (suitCount.indexOf(5) !== -1) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ *
+ * @param {Object} stats object containing the current hand with number of suits and number of ranks
+ * @returns {Boolean} true if current hand is straight
+ */
+const checkStraightHand = (input) => {
+ const nameCount = Object.values(input.name);
+
+ // check whether there is any names repeated twice or more
+ for (let i = 0; i < nameCount.length; i += 1) {
+ if (nameCount[i] >= 2) {
+ return null;
+ }
+ }
+
+ // put all ranks into a table
+ // if there is an ace, put both rank 1 and 14
+ const rankTable = [];
+ let rankTable2 = null;
+
+ if (input.name.ace === 1) {
+ rankTable2 = [];
+ }
+
+ for (let i = 0; i < input.hand.length; i += 1) {
+ rankTable.push(input.hand[i].rank);
+ if (rankTable2 !== null) {
+ if (input.hand[i].name === 'ace') {
+ rankTable2.push(14);
+ } else {
+ rankTable2.push(input.hand[i].rank);
+ }
+ }
+ }
+
+ // check rankTable to see whether sequential
+ rankTable.sort((a, b) => a - b);
+ let sequential = true;
+ for (let i = 1; i < rankTable.length; i += 1) {
+ if (rankTable[i] - 1 === rankTable[i - 1]) {
+ sequential = true;
+ } else {
+ sequential = false;
+ break;
+ }
+ }
+
+ if (rankTable2 !== null && sequential === false) {
+ rankTable2.sort((a, b) => a - b);
+
+ for (let i = 1; i < rankTable2.length; i += 1) {
+ if (rankTable2[i] - 1 === rankTable2[i - 1]) {
+ sequential = true;
+ } else {
+ sequential = false;
+ break;
+ }
+ }
+ }
+
+ return sequential;
+};
+
+/**
+ *
+ * @param {Object} stats object containing the current hand with number of suits and number of ranks
+ * @returns {Boolean} true if current hand is three of a kind
+ */
+const checkThreeOfAKindHand = (input) => {
+ const nameCount = Object.values(input.name);
+
+ if (nameCount.indexOf(3) !== -1) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ *
+ * @param {Object} stats object containing the current hand with number of suits and number of ranks
+ * @returns {Boolean} true if current hand is two pair
+ */
+const checkTwoPairHand = (input) => {
+ let noOfPairs = 0;
+
+ const nameCount = Object.values(input.name);
+
+ for (let i = 0; i < nameCount.length; i += 1) {
+ if (nameCount[i] >= 2) {
+ noOfPairs += 1;
+ }
+ }
+
+ if (noOfPairs === 2) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ *
+ * @param {Object} stats object containing the current hand with number of suits and number of ranks
+ * @returns {Boolean} true if current hand is straight flush
+ */
+const checkStraightFlushHand = (input) => {
+ if (checkStraightHand(input) && checkFlushHand(input)) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ *
+ * @param {Object} stats object containing the current hand with number of suits and number of ranks
+ * @returns {Boolean} true if current hand is royal flush
+ */
+const checkRoyalFlushHand = (input) => {
+ if (checkFlushHand(input) && input.name.ace === 1 && input.name.king === 1 && input.name.queen === 1 && input.name.jack === 1 && input.name['10'] === 1) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ *
+ * @param {Object} stats.hand object containing the current hand
+ * @returns {Boolean} true if current hand contains cards of the same suit
+ */
+const isHeldCardsSameSuit = (statsHand) => {
+ const result = {
+ suit: '',
+ result: false,
+ };
+
+ let suitPlaceholder = '';
+ for (let i = 0; i < statsHand.length; i += 1) {
+ if (statsHand[i].hold === true) {
+ if (suitPlaceholder === '') {
+ suitPlaceholder = statsHand[i].suit;
+ } else if (statsHand[i].suit !== suitPlaceholder) {
+ return result;
+ }
+ }
+ }
+
+ result.suit = suitPlaceholder;
+ result.result = true;
+
+ return result;
+};
+
+/**
+ *
+ * @param {Object} stats.hand object containing the current hand
+ * @returns {Boolean} true if current hand contains cards of the same rank
+ */
+const isHeldCardsSameName = (statsHand) => {
+ let cardsAreSameName = true;
+ let namePlaceholder = '';
+ for (let i = 0; i < statsHand.length; i += 1) {
+ if (statsHand[i].hold === true) {
+ if (namePlaceholder === '') {
+ namePlaceholder = statsHand[i].name;
+ } else if (statsHand[i].name !== namePlaceholder) {
+ cardsAreSameName = false;
+ return cardsAreSameName;
+ }
+ }
+ }
+
+ return cardsAreSameName;
+};
+
+/**
+ *
+ * @param {Object} stats.hand object containing the current hand
+ * @returns {Boolean} true if current hand contains cards from the royal flush group
+ */
+const isHeldCardsRoyal = (statsHand) => {
+ const result = {
+ royalHand: {},
+ result: false,
+ };
+
+ const royalHand = {
+ ace: 0,
+ king: 0,
+ queen: 0,
+ jack: 0,
+ 10: 0,
+ };
+
+ // if held cards do not contain royal cards, return false
+ for (let i = 0; i < statsHand.length; i += 1) {
+ if (statsHand[i].hold === true) {
+ if (royalHand[statsHand[i].name] === undefined) {
+ result.result = false;
+ return result;
+ }
+ royalHand[statsHand[i].name] += 1;
+ }
+ }
+
+ if (royalHand.ace > 1
+ || royalHand.king > 1
+ || royalHand.queen > 1
+ || royalHand.jack > 1
+ || royalHand[10] > 1) {
+ result.result = false;
+
+ return result;
+ }
+
+ result.royalHand = royalHand;
+ result.result = true;
+ return result;
+};
+
+/**
+ *
+ * @param {Object} stats.hand object containing the current hand
+ * @returns {Boolean} true if lowest rank and highest rank of cards being held are within 5 of each other
+ */
+const isHeldCardsWithinStraight = (statsHand) => {
+ const result = {
+ straightHand: {},
+ diff: 0,
+ result: false,
+ };
+
+ // if there is more than 2 cards of the same rank, it is not within straight result
+ for (let i = 0; i < statsHand.length; i += 1) {
+ if (statsHand[i].hold === true) {
+ if (result.straightHand[statsHand[i].rank] === undefined) {
+ result.straightHand[statsHand[i].rank] = 1;
+ } else {
+ return result;
+ }
+ }
+ }
+
+ // if there is not more than 1 card per rank, check if the lowest rank and highest rank are within 5 of each other
+ const rankArray = Object.keys(result.straightHand);
+ const diff = parseInt(rankArray[rankArray.length - 1], 10) - parseInt(rankArray[0], 10);
+ if (diff <= 4) {
+ result.result = true;
+ result.diff = diff;
+ return result;
+ }
+
+ result.straightHand = {};
+ return result;
+};
diff --git a/scripts/functionHelper.js b/scripts/functionHelper.js
new file mode 100644
index 00000000..d59dbbaa
--- /dev/null
+++ b/scripts/functionHelper.js
@@ -0,0 +1,140 @@
+/**
+ *
+ * @param {Object} object of objects with keys from 'ace' to 'king' containing the number of cards still in the deck
+ * @returns {Array} array of stats objects
+ */
+const convertCardsLeftToStats = (cardsLeft) => {
+ const cardsLeftKeys = Object.keys(cardsLeft);
+ const cardsLeftValues = Object.values(cardsLeft);
+
+ const cleanedUpCardsLeft = [];
+
+ for (let i = 0; i < cardsLeftKeys.length; i += 1) {
+ const cardsLeftValues2 = Object.values(cardsLeftValues[i]);
+ for (let j = 0; j < cardsLeftValues2.length; j += 1) {
+ if (cardsLeftValues2[j] !== 0) {
+ const cleanedUpCardsLeftItem = {};
+ cleanedUpCardsLeftItem.name = cardsLeftKeys[i];
+
+ if (j === 0) {
+ cleanedUpCardsLeftItem.suit = 'clubs';
+ } else if (j === 1) {
+ cleanedUpCardsLeftItem.suit = 'spades';
+ } else if (j === 2) {
+ cleanedUpCardsLeftItem.suit = 'hearts';
+ } else {
+ cleanedUpCardsLeftItem.suit = 'diamonds';
+ }
+
+ if (cardsLeftKeys[i] === 'jack') {
+ cleanedUpCardsLeftItem.rank = 11;
+ } else if (cardsLeftKeys[i] === 'queen') {
+ cleanedUpCardsLeftItem.rank = 12;
+ } else if (cardsLeftKeys[i] === 'king') {
+ cleanedUpCardsLeftItem.rank = 13;
+ } else if (cardsLeftKeys[i] === 'ace') {
+ cleanedUpCardsLeftItem.rank = 14;
+ } else {
+ cleanedUpCardsLeftItem.rank = parseInt(cardsLeftKeys[i], 10);
+ }
+ cleanedUpCardsLeft.push(cleanedUpCardsLeftItem);
+ }
+ }
+ }
+
+ return cleanedUpCardsLeft;
+};
+
+/**
+ *
+ * @returns {Number} number of cards that are being held by the player and will not be replaced with fresh cards
+ */
+const countHeldCards = () => {
+ let counter = 0;
+
+ for (let i = 0; i < stats.hand.length; i += 1) {
+ if (stats.hand[i].hold === true) {
+ counter += 1;
+ }
+ }
+
+ return counter;
+};
+
+/**
+ *
+ * @returns {Number} number of cards that are to be replaced with fresh cards
+ */
+const countReplacedCards = () => {
+ let replaceCounter = 0;
+ for (let i = 0; i < stats.hand.length; i += 1) {
+ if (stats.hand[i].hold === false) {
+ replaceCounter += 1;
+ }
+ }
+
+ return replaceCounter;
+};
+
+/**
+ *
+ * @returns {Array} newDeck array contains a fresh deck of 52 cards
+ */
+const makeDeck = () => {
+ const newDeck = [];
+ const suits = ['hearts', 'diamonds', 'clubs', 'spades'];
+ const colors = ['red', 'red', 'black', 'black'];
+
+ for (let suitIndex = 0; suitIndex < suits.length; suitIndex += 1) {
+ const currentSuit = suits[suitIndex];
+ const color = colors[suitIndex];
+
+ for (let rankCounter = 2; rankCounter <= 14; rankCounter += 1) {
+ let cardName = `${rankCounter}`;
+
+ if (cardName === '14') {
+ cardName = 'ace';
+ } else if (cardName === '11') {
+ cardName = 'jack';
+ } else if (cardName === '12') {
+ cardName = 'queen';
+ } else if (cardName === '13') {
+ cardName = 'king';
+ }
+
+ const card = {
+ name: cardName,
+ suit: currentSuit,
+ rank: rankCounter,
+ pic: `./images/cards/${cardName}_of_${currentSuit}.png`,
+ color,
+ };
+
+ newDeck.push(card);
+ }
+ }
+
+ return newDeck;
+};
+
+/**
+ *
+ * @param {Array} cards containing 52 newly created cards
+ * @returns {Array} 52 shuffled cards
+ */
+const shuffleCards = (cards) => {
+ // Loop over the card deck array once
+ for (let currentIndex = 0; currentIndex < cards.length; currentIndex += 1) {
+ // Select a random index in the deck
+ const randomIndex = Math.floor(Math.random() * cards.length);
+ // Select the card that corresponds to randomIndex
+ const randomCard = cards[randomIndex];
+ // Select the card that corresponds to currentIndex
+ const currentCard = cards[currentIndex];
+ // Swap positions of randomCard and currentCard in the deck
+ cards[currentIndex] = randomCard;
+ cards[randomIndex] = currentCard;
+ }
+ // Return the shuffled deck
+ return cards;
+};
diff --git a/scripts/main.js b/scripts/main.js
new file mode 100644
index 00000000..30442aa1
--- /dev/null
+++ b/scripts/main.js
@@ -0,0 +1,634 @@
+/* eslint-disable no-undef */
+let stats = {
+ hand: [],
+ suit: {
+ clubs: 0,
+ spades: 0,
+ hearts: 0,
+ diamonds: 0,
+ },
+ name: {
+ ace: 0,
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+const rewards = {
+ royalFlush: 250,
+ straightFlush: 50,
+ fourOfAKind: 25,
+ fullHouse: 9,
+ flush: 6,
+ straight: 4,
+ threeOfAKind: 3,
+ twoPairs: 2,
+ jacksOrBetter: 1,
+};
+const probability = {
+ royalFlush: 0,
+ straightFlush: 0,
+ fourOfAKind: 0,
+ fullHouse: 0,
+ flush: 0,
+ straight: 0,
+ threeOfAKind: 0,
+ twoPairs: 0,
+ jacksOrBetter: 0,
+};
+let cardsLeft = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 3: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 4: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
+let shuffledDeck = [];
+let playerCredits = 100;
+let playerBet = 0;
+let mode = '';
+let outcome = 'Sorry you lost.';
+let foundHand = '';
+let totalCombinationsAvailable = 0;
+
+
+/**
+ *
+ * @param {String|Number} string or number representing the rank
+ * @returns {Number} number of cards left with the rank
+ */
+const getCardsLeftWithRank = (i) => {
+ let rank = i;
+
+ if (typeof (rank) === 'string') {
+ if (rank === 'king') {
+ rank = Object.values(cardsLeft.king).reduce((a, b) => a + b, 0);
+ return rank;
+ } if (rank === 'queen') {
+ rank = Object.values(cardsLeft.queen).reduce((a, b) => a + b, 0);
+ return rank;
+ } if (rank === 'jack') {
+ rank = Object.values(cardsLeft.jack).reduce((a, b) => a + b, 0);
+ return rank;
+ } if (rank === 'ace') {
+ rank = Object.values(cardsLeft.ace).reduce((a, b) => a + b, 0);
+ return rank;
+ }
+ rank = parseInt(rank, 10);
+ }
+
+ if (rank === 1) {
+ rank = Object.values(cardsLeft.ace).reduce((a, b) => a + b, 0);
+ } else if (rank === 11) {
+ rank = Object.values(cardsLeft.jack).reduce((a, b) => a + b, 0);
+ } else if (rank === 12) {
+ rank = Object.values(cardsLeft.queen).reduce((a, b) => a + b, 0);
+ } else if (rank === 13) {
+ rank = Object.values(cardsLeft.king).reduce((a, b) => a + b, 0);
+ } else if (rank === 14) {
+ rank = Object.values(cardsLeft.ace).reduce((a, b) => a + b, 0);
+ } else {
+ rank = Object.values(cardsLeft[rank]).reduce((a, b) => a + b, 0);
+ }
+
+ return rank;
+};
+
+/**
+ *
+ * run through the current hand of cards through all winning combinations starting with royal flush down to two pairs
+ * if we find any winning combination, solution will not search for other winning outcomes
+ */
+const calcHandScore = () => {
+ if (checkRoyalFlushHand(stats)) {
+ outcome = 'Royal flush found!';
+ foundHand = 'royalFlush';
+ return;
+ }
+ if (checkStraightFlushHand(stats)) {
+ outcome = 'Straight flush found!';
+ foundHand = 'straightFlush';
+ return;
+ }
+ if (checkFourOfAKindHand(stats)) {
+ outcome = 'Four of a kind found!';
+ foundHand = 'fourOfAKind';
+ return;
+ }
+ if (checkFullHouseHand(stats)) {
+ outcome = 'Full house found!';
+ foundHand = 'fullHouse';
+ return;
+ }
+ if (checkFlushHand(stats)) {
+ outcome = 'Flush found!';
+ foundHand = 'flush';
+ return;
+ }
+ if (checkStraightHand(stats)) {
+ outcome = 'Straight found!';
+ foundHand = 'straight';
+ return;
+ }
+ if (checkThreeOfAKindHand(stats)) {
+ outcome = 'Three of a kind found!';
+ foundHand = 'threeOfAKind';
+ return;
+ }
+ if (checkTwoPairHand(stats)) {
+ outcome = 'Two pairs found!';
+ foundHand = 'twoPairs';
+ }
+};
+
+/**
+ *
+ * count the number of credits that player has won if they get a winning hand
+ */
+const countPlayerCredits = () => {
+ if (outcome === 'Royal flush found!' && playerBet === 5) {
+ playerCredits += 4000;
+ } else if (outcome !== 'Sorry you lost.') {
+ playerCredits += (playerBet * rewards[foundHand]);
+ }
+
+ // if after tallying, player still has zero, game over
+ if (playerCredits === 0) {
+ gameOver();
+ } else {
+
+ }
+};
+
+/**
+ *
+ * resets game, updates instructions
+ */
+const resetGame = () => {
+ playerBet = 0;
+ mode = '';
+
+ // clear stats
+ stats.hand = [];
+ stats.suit = {
+ clubs: 0,
+ spades: 0,
+ hearts: 0,
+ diamonds: 0,
+ };
+ stats.name = {
+ ace: 0,
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ };
+
+ document.getElementById('cards').className = 'display-none';
+ document.getElementById('probabilities').className = 'display-none';
+ shuffledDeck = shuffleCards(makeDeck());
+ outcome = 'Sorry you lost.';
+};
+
+/**
+ *
+ * replace the cards that are not held in current hand with new cards from the deck
+ */
+const refreshHand = () => {
+ let drawnCard;
+
+ for (let i = 4; i >= 0; i -= 1) {
+ if (stats.hand[i] !== undefined && stats.hand[i].hold === false) {
+ // remove cards i do not want to hold first
+ stats.name[stats.hand[i].name] -= 1;
+ stats.suit[stats.hand[i].suit] -= 1;
+
+ drawnCard = shuffledDeck.pop();
+ drawnCard.hold = false;
+
+ // replace cards i do not want with new cards
+ stats.hand.splice(i, 1, drawnCard);
+
+ stats.name[drawnCard.name] += 1;
+ stats.suit[drawnCard.suit] += 1;
+
+ cardsLeft[drawnCard.name][drawnCard.suit] -= 1;
+ }
+ }
+};
+
+/**
+ *
+ * @param {Array} array of stats objects that represent the cards that are left and yet to be drawn
+ * @returns {Array} array of different combination stats objects that can be built via 5 cards
+ */
+const buildStats = (cleanedUpCardsLeft) => {
+ const statsList = [];
+
+ for (let i = 0; i < cleanedUpCardsLeft.length; i += 1) {
+ for (let j = i + 1; j < cleanedUpCardsLeft.length; j += 1) {
+ for (let k = j + 1; k < cleanedUpCardsLeft.length; k += 1) {
+ for (let l = k + 1; l < cleanedUpCardsLeft.length; l += 1) {
+ for (let m = l + 1; m < cleanedUpCardsLeft.length; m += 1) {
+ const stats = {};
+ stats.hand = [];
+ stats.name = {
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 0,
+ jack: 0,
+ king: 0,
+ queen: 0,
+ };
+ stats.suit = {
+ clubs: 0,
+ spades: 0,
+ hearts: 0,
+ diamonds: 0,
+ };
+
+ stats.name[cleanedUpCardsLeft[i].name] += 1;
+ stats.name[cleanedUpCardsLeft[j].name] += 1;
+ stats.name[cleanedUpCardsLeft[k].name] += 1;
+ stats.name[cleanedUpCardsLeft[l].name] += 1;
+ stats.name[cleanedUpCardsLeft[m].name] += 1;
+
+ stats.suit[cleanedUpCardsLeft[i].suit] += 1;
+ stats.suit[cleanedUpCardsLeft[j].suit] += 1;
+ stats.suit[cleanedUpCardsLeft[k].suit] += 1;
+ stats.suit[cleanedUpCardsLeft[l].suit] += 1;
+ stats.suit[cleanedUpCardsLeft[m].suit] += 1;
+
+ stats.hand.push(cleanedUpCardsLeft[i]);
+ stats.hand.push(cleanedUpCardsLeft[j]);
+ stats.hand.push(cleanedUpCardsLeft[k]);
+ stats.hand.push(cleanedUpCardsLeft[l]);
+ stats.hand.push(cleanedUpCardsLeft[m]);
+
+ statsList.push(stats);
+ }
+ }
+ }
+ }
+ }
+
+ return statsList;
+};
+
+/**
+ *
+ * @param {Array} array of stats objects containing the current hand with number of suits and number of ranks
+ * @returns {Object} object containing probabilities for each winning hand based on statsList
+ */
+const runStatsAgainstOutcomes = (statsList) => {
+ const statOutcome = {
+ royalFlushCombinations: 0,
+ straightFlushCombinations: 0,
+ fourOfAKindCombinations: 0,
+ fullHouseCombinations: 0,
+ flushCombinations: 0,
+ straightCombinations: 0,
+ threeOfAKindCombinations: 0,
+ twoPairCombinations: 0,
+ };
+
+ for (let i = 0; i < statsList.length; i += 1) {
+ if (checkRoyalFlushHand(statsList[i])) {
+ statOutcome.royalFlushCombinations += 1;
+ }
+ if (checkStraightFlushHand(statsList[i])) {
+ statOutcome.straightFlushCombinations += 1;
+ }
+ if (checkFourOfAKindHand(statsList[i])) {
+ statOutcome.fourOfAKindCombinations += 1;
+ }
+ if (checkFullHouseHand(statsList[i])) {
+ statOutcome.fullHouseCombinations += 1;
+ }
+ if (checkFlushHand(statsList[i])) {
+ statOutcome.flushCombinations += 1;
+ }
+ if (checkStraightHand(statsList[i])) {
+ statOutcome.straightCombinations += 1;
+ }
+ if (checkThreeOfAKindHand(statsList[i])) {
+ statOutcome.threeOfAKindCombinations += 1;
+ }
+ if (checkTwoPairHand(statsList[i])) {
+ statOutcome.twoPairCombinations += 1;
+ }
+ }
+
+ return statOutcome;
+};
+
+/**
+ *
+ * calculates the probability of each winning hand depending on what cards player hold or don't hold
+ */
+const calculateProbability = () => {
+ // take into account the hand and the amount
+ // of cards being held or to be replaced
+
+ const cardsToBeReplaced = countReplacedCards();
+ totalCombinationsAvailable = countTotalCombinations(shuffledDeck.length, cardsToBeReplaced);
+ updateTotalCombinationsAvailableUI(totalCombinationsAvailable);
+
+ if (cardsToBeReplaced === 5) {
+ // find all combinations
+ const cleanedUpCardsLeft = convertCardsLeftToStats(cardsLeft);
+ const statsList = buildStats(cleanedUpCardsLeft);
+ const statOutcome = runStatsAgainstOutcomes(statsList);
+
+ probability.royalFlush = (statOutcome.royalFlushCombinations
+ / totalCombinationsAvailable) * 100;
+ probability.straightFlush = (statOutcome.straightFlushCombinations
+ / totalCombinationsAvailable) * 100;
+ probability.fourOfAKind = (statOutcome.fourOfAKindCombinations
+ / totalCombinationsAvailable) * 100;
+ probability.fullHouse = (statOutcome.fullHouseCombinations
+ / totalCombinationsAvailable) * 100;
+ probability.flush = (statOutcome.flushCombinations
+ / totalCombinationsAvailable) * 100;
+ probability.straight = (statOutcome.straightCombinations
+ / totalCombinationsAvailable) * 100;
+ probability.threeOfAKind = (statOutcome.threeOfAKindCombinations
+ / totalCombinationsAvailable) * 100;
+ probability.twoPairs = (statOutcome.twoPairCombinations
+ / totalCombinationsAvailable) * 100;
+
+ updateProbabilityUI();
+ } else if (cardsToBeReplaced === 0) {
+ probability.royalFlush = checkRoyalFlushHand(stats) ? 100 : 0;
+ probability.straightFlush = checkStraightFlushHand(stats) ? 100 : 0;
+ probability.fourOfAKind = checkFourOfAKindHand(stats) ? 100 : 0;
+ probability.fullHouse = checkFullHouseHand(stats) ? 100 : 0;
+ probability.flush = checkFlushHand(stats) ? 100 : 0;
+ probability.straight = checkStraightHand(stats) ? 100 : 0;
+ probability.threeOfAKind = checkThreeOfAKindHand(stats) ? 100 : 0;
+ probability.twoPairs = checkTwoPairHand(stats) ? 100 : 0;
+ updateProbabilityUI();
+ } else {
+ const royalFlushCombinations = checkRoyalFlushCombinations();
+ probability.royalFlush = (royalFlushCombinations / totalCombinationsAvailable) * 100;
+
+ const straightFlushCombinations = checkStraightFlushCombinations();
+ probability.straightFlush = (straightFlushCombinations / totalCombinationsAvailable) * 100;
+
+ const fourOfAKindCombinations = checkFourOfAKindCombinations();
+ probability.fourOfAKind = fourOfAKindCombinations.alreadyWin ? 100
+ : (fourOfAKindCombinations.combinations / totalCombinationsAvailable) * 100;
+
+ const fullHouseCombinations = checkFullHouseCombinations();
+ probability.fullHouse = fullHouseCombinations.alreadyWin ? 100
+ : (fullHouseCombinations.combinations / totalCombinationsAvailable) * 100;
+
+ const flushCombinations = checkFlushCombinations();
+ probability.flush = (flushCombinations / totalCombinationsAvailable) * 100;
+
+ const straightCombinations = checkStraightCombinations();
+ probability.straight = (straightCombinations / totalCombinationsAvailable) * 100;
+
+ const threeOfAKindCombinations = checkThreeOfAKindCombinations();
+ probability.threeOfAKind = threeOfAKindCombinations.alreadyWin ? 100
+ : (threeOfAKindCombinations.combinations / totalCombinationsAvailable) * 100;
+
+ const twoPairCombinations = checkTwoPairCombinations();
+ probability.twoPairs = twoPairCombinations.alreadyWin ? 100
+ : (twoPairCombinations.combinations / totalCombinationsAvailable) * 100;
+
+ updateProbabilityUI();
+ }
+};
+
+/**
+ *
+ * bet 1 credit
+ */
+const bet1 = () => {
+ if (mode === 'finalDeal') {
+ resetGame();
+ }
+
+ if (playerBet < 5 && playerCredits !== 0) {
+ playerBet += 1;
+ playerCredits -= 1;
+
+ if (playerBet === 5) {
+ disableButton('bet-1');
+ }
+
+ disableButton('bet-5');
+ enableButton('deal');
+
+ updatePlayerBetUI();
+ updatePlayerCreditsUI();
+
+ highlightRewardColumn();
+ }
+};
+
+/**
+ *
+ * bet 5 credits
+ */
+const bet5 = () => {
+ if (mode === 'finalDeal') {
+ resetGame();
+ }
+
+ if (playerCredits >= 5) {
+ playerBet = 5;
+ playerCredits -= 5;
+ } else {
+ playerBet = playerCredits;
+ playerCredits = 0;
+ }
+
+ disableButton('bet-5');
+ disableButton('bet-1');
+ enableButton('deal');
+
+ updatePlayerBetUI();
+ updatePlayerCreditsUI();
+
+ highlightRewardColumn();
+};
+
+
+/**
+ *
+ * deal cards. depending on which stage player is at, either at first draw or second draw, update the instructions or outcomes accordingly
+ */
+const deal = () => {
+ disableButton('bet-1');
+ disableButton('bet-5');
+ disableButton('deal');
+
+ if (mode === '') {
+ mode = 'firstDeal';
+ } else if (mode === 'firstDeal') {
+ mode = 'finalDeal';
+ }
+
+ if (mode === 'firstDeal') {
+ let drawnCard;
+
+ enableButton('calculate-probability');
+
+ for (let i = 0; i < 5; i += 1) {
+ drawnCard = shuffledDeck.pop();
+ drawnCard.hold = false;
+
+ stats.hand.push(drawnCard);
+ stats.name[drawnCard.name] += 1;
+ stats.suit[drawnCard.suit] += 1;
+
+ cardsLeft[drawnCard.name][drawnCard.suit] -= 1;
+ }
+
+ updateCardsUI();
+ updateInstructions(
+ "Click on any card to hold and press Deal again.",
+ );
+ } else if (mode === 'finalDeal') {
+ refreshHand();
+ updateCardsUI();
+ calcHandScore();
+
+ updateInstructions(`${outcome} Restart by pressing Bet 1 or Bet 5 and pressing Deal after.`);
+
+ countPlayerCredits();
+ updatePlayerCreditsUI();
+
+ playerBet = 0;
+
+ updatePlayerBetUI();
+ if (playerCredits !== 0) {
+ enableButton('bet-1');
+ enableButton('bet-5');
+ }
+ }
+};
+
+
+/**
+ *
+ * start the game
+ */
+const initGame = () => {
+ shuffledDeck = shuffleCards(makeDeck());
+
+ document.getElementById('bet-1').addEventListener('click', () => bet1());
+ document.getElementById('bet-5').addEventListener('click', () => bet5());
+ document.getElementById('deal').addEventListener('click', () => deal());
+ document.getElementById('calculate-probability').addEventListener('click', () => calculateProbability());
+};
+
+
+/**
+ *
+ * game is over. update instructions
+ */
+const gameOver = () => {
+ updateInstructions('Game over.');
+};
+
+initGame();
diff --git a/scripts/testHands.js b/scripts/testHands.js
new file mode 100644
index 00000000..e4efd611
--- /dev/null
+++ b/scripts/testHands.js
@@ -0,0 +1,1513 @@
+const royalFlushHand = {
+ hand: [
+ {
+ name: 'ace',
+ suit: 'diamonds',
+ rank: 1,
+ pic: './images/cards/ace_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: 'king',
+ suit: 'diamonds',
+ rank: 13,
+ pic: './images/cards/king_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: 'queen',
+ suit: 'diamonds',
+ rank: 12,
+ pic: './images/cards/queen_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: 'jack',
+ suit: 'diamonds',
+ rank: 11,
+ pic: './images/cards/jack_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '10',
+ suit: 'diamonds',
+ rank: 10,
+ pic: './images/cards/10_of_diamonds.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 0,
+ spades: 0,
+ hearts: 0,
+ diamonds: 5,
+ },
+ name: {
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 1,
+ ace: 1,
+ jack: 1,
+ queen: 1,
+ king: 1,
+ },
+};
+
+const testStraightFlushHand1 = {
+ hand: [
+ {
+ name: '7',
+ suit: 'diamonds',
+ rank: 7,
+ pic: './images/cards/7_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '8',
+ suit: 'diamonds',
+ rank: 8,
+ pic: './images/cards/8_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '9',
+ suit: 'diamonds',
+ rank: 9,
+ pic: './images/cards/9_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: 'jack',
+ suit: 'diamonds',
+ rank: 11,
+ pic: './images/cards/jack_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '10',
+ suit: 'diamonds',
+ rank: 10,
+ pic: './images/cards/10_of_diamonds.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 0,
+ spades: 0,
+ hearts: 0,
+ diamonds: 5,
+ },
+ name: {
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 0,
+ 7: 1,
+ 8: 1,
+ 9: 1,
+ 10: 1,
+ ace: 0,
+ jack: 1,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const testStraightFlushCardsLeft1 = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 3: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 4: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
+
+const twoPairHand = {
+ hand: [
+ {
+ name: '2',
+ suit: 'hearts',
+ rank: 2,
+ pic: './images/cards/2_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'hearts',
+ rank: 4,
+ pic: './images/cards/4_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'spades',
+ rank: 2,
+ pic: './images/cards/2_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'clubs',
+ rank: 4,
+ pic: './images/cards/4_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: 'ace',
+ suit: 'hearts',
+ rank: 1,
+ pic: './images/cards/ace_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 3,
+ diamonds: 0,
+ },
+ name: {
+ 2: 2,
+ 3: 0,
+ 4: 2,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 1,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const twoPairCardsLeft = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 0,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 3: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 4: {
+ clubs: 0,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
+
+const fullHouseHand = {
+ hand: [
+ {
+ name: '2',
+ suit: 'hearts',
+ rank: 2,
+ pic: './images/cards/2_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'diamonds',
+ rank: 2,
+ pic: './images/cards/2_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'spades',
+ rank: 2,
+ pic: './images/cards/2_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'clubs',
+ rank: 4,
+ pic: './images/cards/4_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'hearts',
+ rank: 4,
+ pic: './images/cards/4_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 3,
+ 3: 0,
+ 4: 2,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 0,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const testFullHouseHand = {
+ hand: [
+ {
+ name: '2',
+ suit: 'hearts',
+ rank: 2,
+ pic: './images/cards/2_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'diamonds',
+ rank: 2,
+ pic: './images/cards/2_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'spades',
+ rank: 2,
+ pic: './images/cards/2_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'clubs',
+ rank: 4,
+ pic: './images/cards/4_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'hearts',
+ rank: 4,
+ pic: './images/cards/4_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 3,
+ 3: 0,
+ 4: 2,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 0,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const testFullHouseCardsLeft = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 0,
+ hearts: 0,
+ diamonds: 0,
+ },
+ 3: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 4: {
+ clubs: 0,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
+
+const testFourOfAKindHand = {
+ hand: [
+ {
+ name: '2',
+ suit: 'hearts',
+ rank: 2,
+ pic: './images/cards/2_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'diamonds',
+ rank: 2,
+ pic: './images/cards/2_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'spades',
+ rank: 2,
+ pic: './images/cards/2_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '3',
+ suit: 'clubs',
+ rank: 3,
+ pic: './images/cards/3_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: '6',
+ suit: 'hearts',
+ rank: 6,
+ pic: './images/cards/6_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 3,
+ 3: 1,
+ 4: 0,
+ 5: 0,
+ 6: 1,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 0,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const testFourOfAKindCardsLeft = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 0,
+ hearts: 0,
+ diamonds: 0,
+ },
+ 3: {
+ clubs: 0,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 4: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
+
+const threeOfAKindHand = {
+ hand: [
+ {
+ name: '2',
+ suit: 'hearts',
+ rank: 2,
+ pic: './images/cards/2_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'diamonds',
+ rank: 2,
+ pic: './images/cards/2_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'spades',
+ rank: 2,
+ pic: './images/cards/2_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'clubs',
+ rank: 4,
+ pic: './images/cards/4_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: '6',
+ suit: 'hearts',
+ rank: 6,
+ pic: './images/cards/6_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 3,
+ 3: 0,
+ 4: 1,
+ 5: 0,
+ 6: 1,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 0,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const threeOfAKindCardsLeft = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 0,
+ hearts: 0,
+ diamonds: 0,
+ },
+ 3: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 4: {
+ clubs: 0,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
+
+/**
+ * 2 3 4 5 6
+ */
+const straightHand1 = {
+ hand: [
+ {
+ name: '2',
+ suit: 'hearts',
+ rank: 2,
+ pic: './images/cards/2_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '3',
+ suit: 'diamonds',
+ rank: 3,
+ pic: './images/cards/3_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'spades',
+ rank: 4,
+ pic: './images/cards/4_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '5',
+ suit: 'clubs',
+ rank: 5,
+ pic: './images/cards/5_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: '6',
+ suit: 'hearts',
+ rank: 6,
+ pic: './images/cards/6_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 1,
+ 3: 1,
+ 4: 1,
+ 5: 1,
+ 6: 1,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 0,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const straightHand1CardsLeft = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 3: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ 4: {
+ clubs: 1,
+ spades: 0,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 0,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
+
+/**
+ * A 2 3 4 5
+ */
+const straightHand2 = {
+ hand: [
+ {
+ name: 'ace',
+ suit: 'hearts',
+ rank: 1,
+ pic: './images/cards/ace_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '3',
+ suit: 'diamonds',
+ rank: 3,
+ pic: './images/cards/3_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'spades',
+ rank: 4,
+ pic: './images/cards/4_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '5',
+ suit: 'clubs',
+ rank: 5,
+ pic: './images/cards/5_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'hearts',
+ rank: 2,
+ pic: './images/cards/2_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 1,
+ 3: 1,
+ 4: 1,
+ 5: 1,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 1,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const straightHand2CardsLeft = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 1,
+ hearts: 0,
+ diamonds: 1,
+ },
+ 3: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ 4: {
+ clubs: 1,
+ spades: 0,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 0,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
+
+/**
+ * 7 8 9 10 11
+ */
+const straightHand3 = {
+ hand: [
+ {
+ name: '7',
+ suit: 'hearts',
+ rank: 7,
+ pic: './images/cards/7_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '8',
+ suit: 'diamonds',
+ rank: 8,
+ pic: './images/cards/8_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '9',
+ suit: 'spades',
+ rank: 9,
+ pic: './images/cards/9_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '10',
+ suit: 'clubs',
+ rank: 10,
+ pic: './images/cards/10_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: 'jack',
+ suit: 'hearts',
+ rank: 11,
+ pic: './images/cards/jack_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 0,
+ 7: 1,
+ 8: 1,
+ 9: 1,
+ 10: 1,
+ ace: 0,
+ jack: 1,
+ queen: 0,
+ king: 0,
+ },
+};
+
+/**
+ * 10 J Q K A
+ */
+const straightHand4 = {
+ hand: [
+ {
+ name: 'ace',
+ suit: 'hearts',
+ rank: 1,
+ pic: './images/cards/ace_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: 'king',
+ suit: 'diamonds',
+ rank: 13,
+ pic: './images/cards/king_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: 'queen',
+ suit: 'spades',
+ rank: 12,
+ pic: './images/cards/queen_of_spades.png',
+ hold: false,
+ },
+ {
+ name: 'jack',
+ suit: 'clubs',
+ rank: 11,
+ pic: './images/cards/jack_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: '10',
+ suit: 'hearts',
+ rank: 10,
+ pic: './images/cards/10_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 1,
+ ace: 1,
+ jack: 1,
+ queen: 1,
+ king: 1,
+ },
+};
+
+const flushHand = {
+ hand: [
+ {
+ name: '2',
+ suit: 'hearts',
+ rank: 2,
+ pic: './images/cards/2_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'hearts',
+ rank: 4,
+ pic: './images/cards/4_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '6',
+ suit: 'hearts',
+ rank: 6,
+ pic: './images/cards/6_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '8',
+ suit: 'hearts',
+ rank: 8,
+ pic: './images/cards/8_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '10',
+ suit: 'hearts',
+ rank: 10,
+ pic: './images/cards/10_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 0,
+ spades: 0,
+ hearts: 5,
+ diamonds: 0,
+ },
+ name: {
+ 2: 1,
+ 3: 0,
+ 4: 1,
+ 5: 0,
+ 6: 1,
+ 7: 0,
+ 8: 1,
+ 9: 0,
+ 10: 1,
+ ace: 0,
+ jack: 0,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const jacksOrBetterHand = {
+ hand: [
+ {
+ name: 'jack',
+ suit: 'diamonds',
+ rank: 11,
+ pic: './images/cards/jack_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: 'jack',
+ suit: 'hearts',
+ rank: 11,
+ pic: './images/cards/jack_of_hearts.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'spades',
+ rank: 2,
+ pic: './images/cards/2_of_spades.png',
+ hold: false,
+ },
+ {
+ name: '4',
+ suit: 'clubs',
+ rank: 4,
+ pic: './images/cards/4_of_clubs.png',
+ hold: false,
+ },
+ {
+ name: '6',
+ suit: 'hearts',
+ rank: 6,
+ pic: './images/cards/6_of_hearts.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 1,
+ spades: 1,
+ hearts: 2,
+ diamonds: 1,
+ },
+ name: {
+ 2: 1,
+ 3: 0,
+ 4: 1,
+ 5: 0,
+ 6: 1,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ ace: 0,
+ jack: 2,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const testStraightFlushHand = {
+ hand: [
+ {
+ name: '10',
+ suit: 'diamonds',
+ rank: 10,
+ pic: './images/cards/10_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '2',
+ suit: 'diamonds',
+ rank: 2,
+ pic: './images/cards/2_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '9',
+ suit: 'diamonds',
+ rank: 9,
+ pic: './images/cards/9_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: 'jack',
+ suit: 'diamonds',
+ rank: 11,
+ pic: './images/cards/jack_of_diamonds.png',
+ hold: false,
+ },
+ {
+ name: '5',
+ suit: 'diamonds',
+ rank: 5,
+ pic: './images/cards/5_of_diamonds.png',
+ hold: false,
+ },
+ ],
+ suit: {
+ clubs: 0,
+ spades: 0,
+ hearts: 0,
+ diamonds: 5,
+ },
+ name: {
+ 2: 1,
+ 3: 0,
+ 4: 0,
+ 5: 1,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 1,
+ 10: 0,
+ ace: 1,
+ jack: 1,
+ queen: 0,
+ king: 0,
+ },
+};
+
+const testStraightFlushCardsLeft = {
+ ace: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 2: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ 3: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 4: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 5: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ 6: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 7: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 8: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ 9: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ 10: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ jack: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 0,
+ },
+ queen: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+ king: {
+ clubs: 1,
+ spades: 1,
+ hearts: 1,
+ diamonds: 1,
+ },
+};
diff --git a/scripts/uiHelper.js b/scripts/uiHelper.js
new file mode 100644
index 00000000..33bef24c
--- /dev/null
+++ b/scripts/uiHelper.js
@@ -0,0 +1,172 @@
+/**
+ *
+ * To disable the button so that user cannot click it
+ * @param {String} id of button to be disabled
+ */
+const disableButton = (buttonId) => {
+ document.getElementById(buttonId).className = 'nes-btn is-disabled';
+ document.getElementById(buttonId).disabled = true;
+};
+
+/**
+ *
+ * To enable the button so that user can click it
+ * @param {String} id of button to be enabled
+ */
+const enableButton = (buttonId) => {
+ document.getElementById(buttonId).classList.remove('is-disabled');
+ document.getElementById(buttonId).disabled = false;
+
+ if (buttonId === 'deal') {
+ document.getElementById(buttonId).classList.add('is-primary');
+ } else if (buttonId === 'bet-1') {
+ document.getElementById(buttonId).classList.add('is-warning');
+ } else if (buttonId === 'bet-5') {
+ document.getElementById(buttonId).classList.add('is-error');
+ } else if (buttonId === 'calculate-probability') {
+ document.getElementById(buttonId).classList.add('is-normal');
+ }
+};
+
+/**
+ *
+ * To designate cards that are to be held and cards that are to be replaced
+ * @param {String} id of card to be held
+ */
+const toggleHold = (cardId) => {
+ if (mode === 'firstDeal') {
+ if (document.getElementById(`hold-${cardId}`).className === 'unhold') {
+ document.getElementById(`hold-${cardId}`).className = 'hold';
+ stats.hand[cardId].hold = true;
+ } else {
+ document.getElementById(`hold-${cardId}`).className = 'unhold';
+ stats.hand[cardId].hold = false;
+ }
+ }
+};
+
+/**
+ *
+ * To update the display of player bet
+ */
+const updatePlayerBetUI = () => {
+ document.getElementById('player-bet').innerHTML = playerBet;
+};
+
+/**
+ *
+ * To update the display of player credits
+ */
+const updatePlayerCreditsUI = () => {
+ document.getElementById('player-credits').innerHTML = playerCredits;
+};
+
+/**
+ *
+ * To update the display of player instructions
+ */
+const updateInstructions = (instructions) => {
+ document.getElementById('instructions').innerHTML = instructions;
+};
+
+/**
+ *
+ * To update the cards displayed
+ */
+const updateCardsUI = () => {
+ let counter = 0;
+
+ if (document.getElementById('cards').className === 'display-none') {
+ document.getElementById('cards').className = 'flex';
+ }
+
+ // clear any outstanding cards
+ for (let i = 0; i < 5; i += 1) {
+ document.getElementById(`card-${i}`).innerHTML = '';
+ }
+
+ const setCards = setInterval(() => {
+ const card = document.createElement('IMG');
+ card.src = `${stats.hand[counter].pic}`;
+ card.id = `${counter}`;
+
+ const cardDiv = document.getElementById(`card-${counter}`);
+
+ card.addEventListener('click', (event) => {
+ toggleHold(event.target.id);
+ });
+
+ cardDiv.appendChild(card);
+
+ const hold = document.createElement('div');
+ hold.classList.add('unhold');
+ hold.id = `hold-${counter}`;
+ hold.innerText = 'Hold';
+
+ hold.addEventListener('click', (event) => {
+ toggleHold(event.target.id.split('-')[1]);
+ });
+
+ cardDiv.appendChild(hold);
+
+ if (counter === 4) {
+ clearInterval(setCards);
+ if (mode === 'firstDeal') {
+ enableButton('deal');
+ }
+ }
+
+ counter += 1;
+ }, 100);
+};
+
+/**
+ *
+ * To highlight the column of potential rewards depending on size of player bets
+ */
+const highlightRewardColumn = () => {
+ const scoreTable = document.getElementById('score-table');
+
+ for (let i = 0; i < scoreTable.rows.length; i += 1) {
+ for (let j = 0; j <= 5; j += 1) {
+ if (j === playerBet) {
+ scoreTable.rows[i].cells[j].style.color = '#209cee';
+ } else {
+ scoreTable.rows[i].cells[j].style.color = 'white';
+ }
+ }
+ }
+};
+
+/**
+ *
+ * To present long number properly with commas
+ * @param {Number} any number
+ * @returns {String} string of a number with properly denoted commas e.g. 1000000 -> 1,000,000
+ */
+const numberWithCommas = (x) => x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+
+/**
+ *
+ * To update the total number of combinations available with current hand and cards to be replaced
+ * @param {Number} number of card combinations
+ */
+const updateTotalCombinationsAvailableUI = (totalCombinations) => {
+ document.getElementById('total-combinations').innerHTML = numberWithCommas(totalCombinations.toFixed(0));
+};
+
+/**
+ *
+ * To update the respective probabilities for each winning hand
+ */
+const updateProbabilityUI = () => {
+ document.getElementById('probabilities').classList.remove('display-none');
+ document.getElementById('probability-royal-flush').innerHTML = Number.parseFloat(probability.royalFlush).toFixed(5);
+ document.getElementById('probability-straight-flush').innerHTML = Number.parseFloat(probability.straightFlush).toFixed(5);
+ document.getElementById('probability-four-of-a-kind').innerHTML = Number.parseFloat(probability.fourOfAKind).toFixed(5);
+ document.getElementById('probability-full-house').innerHTML = Number.parseFloat(probability.fullHouse).toFixed(5);
+ document.getElementById('probability-flush').innerHTML = Number.parseFloat(probability.flush).toFixed(5);
+ document.getElementById('probability-straight').innerHTML = Number.parseFloat(probability.straight).toFixed(5);
+ document.getElementById('probability-three-of-a-kind').innerHTML = Number.parseFloat(probability.threeOfAKind).toFixed(5);
+ document.getElementById('probability-two-pair').innerHTML = Number.parseFloat(probability.twoPairs).toFixed(5);
+};
diff --git a/styles.css b/styles.css
new file mode 100644
index 00000000..d7584862
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,81 @@
+*,
+*:before,
+*:after {
+ box-sizing: border-box;
+ font-family: "Press Start 2P", cursive;
+}
+
+body {
+ background: #212529;
+}
+
+#logo {
+ width: 100px;
+}
+
+#score-table {
+ width: 100%;
+ font-size: 12px;
+ table-layout: auto;
+}
+
+.hold {
+ color: #212529;
+ background: #f7d51d;
+ top: -50%;
+ position: relative;
+}
+
+.unhold {
+ top: -50%;
+ position: relative;
+ display: none;
+}
+
+#video-poker-machine {
+ width: 800px;
+ height: 1000px;
+ margin: 0 auto;
+ text-align: center;
+}
+
+.nes-container {
+ width: 100%;
+}
+
+.display-none {
+ display: none;
+}
+
+.flex {
+ display: flex;
+}
+
+.text-white {
+ color: white;
+}
+
+.card {
+ width: 20%;
+ padding: 5px;
+}
+
+.space-evenly {
+ justify-content: space-evenly;
+}
+
+.align-items-center {
+ align-items: center;
+}
+
+.text-align-center {
+ text-align: center;
+}
+
+img {
+ width: 100%;
+}
+
+#probabilities > p {
+ margin-bottom: 0;
+}