diff --git a/click.mp3 b/click.mp3
new file mode 100644
index 00000000..c5e33298
Binary files /dev/null and b/click.mp3 differ
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..b6618292
--- /dev/null
+++ b/index.html
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/losesound.mp3 b/losesound.mp3
new file mode 100644
index 00000000..ba193f44
Binary files /dev/null and b/losesound.mp3 differ
diff --git a/pokercardback.svg b/pokercardback.svg
new file mode 100644
index 00000000..07435329
--- /dev/null
+++ b/pokercardback.svg
@@ -0,0 +1,1554 @@
+
+
\ No newline at end of file
diff --git a/scoretable.js b/scoretable.js
new file mode 100644
index 00000000..10dbbcae
--- /dev/null
+++ b/scoretable.js
@@ -0,0 +1,80 @@
+let pointsList = [
+ {hand:'royal flush', points: 250},
+ {hand: 'straight flush', points: 50},
+ {hand: 'four of a kind', points: 25},
+ {hand: 'fullhouse', points: 9},
+ {hand: 'flush', points: 6},
+ {hand: 'straight', points: 4},
+ {hand: 'three of a kind', points: 3},
+ {hand: 'two pair', points: 2},
+ {hand: 'jacks or better', points: 1},
+ {hand: 'lose', points:0}]
+
+let bet = [1,2,3,4,5]
+let heading = ["bet amount", "1", "2", "3", "4 "," 5"]
+let betAmt=1;
+let count = 0;
+
+const betButton = document.getElementById("bet")
+betButton.innerText = `Bet: ${betAmt}`
+
+const scoreTable = document.getElementById("scoretable")
+/**
+ * Function to create the scoretable
+ */
+const createTable = ()=>{
+for(let j = 0; j <= bet.length; j +=1){
+ const column = document.createElement('div')
+ for (let i = 1; i <= pointsList.length; i +=1){
+ const row = document.createElement('p')
+
+ if ((i-1)===0) {
+ row.innerText = heading[j]
+ }
+ else if (j === 0) {
+ row.innerText = pointsList[i-2].hand
+ } else {
+ row.innerText = pointsList[i-2].points * (j)
+ }
+ column.append(row)
+
+ }
+ scoreTable.append(column)
+}
+}
+
+/**
+ * A function to highligh the relevant column in the score table based on the bet input
+ * @param {number} bet
+ */
+const highlightScore =(betAmt)=>{
+ Array.from(document.querySelectorAll('#scoretable div')).forEach(e=>e.removeAttribute('id'))
+
+ if (betAmt <=5){
+ document.querySelector('#scoretable div:nth-child('+ (betAmt+1) +')').id = "highlight"
+ }
+
+ betButton.innerText = `Bet: ${betAmt}`
+}
+
+
+
+
+/**
+ * A function to check if the bet number < points available.
+ * @param {number} betAmt
+ * @param {number} pointsNum
+ * if bet exceeds, player cannot proceed until the bet is changed. If bet does not exceed, player is prompted to deal and start.
+ */
+
+const checkBet =(betAmt, pointsNum) => {
+
+ if(betAmt > pointsNum) {
+ output("bet exceeds available amount.")
+ dealButton.disabled = true
+ } else if(gameEnd === false ){
+ output ("press deal to start.")
+ console.log("checkbet")
+ dealButton.disabled = false
+ }
+}
diff --git a/script.js b/script.js
new file mode 100644
index 00000000..9bafa327
--- /dev/null
+++ b/script.js
@@ -0,0 +1,428 @@
+
+/**
+ * Global variables
+ */
+const cardContainer = document.getElementById("card-container")
+const cardsInContainer = document.getElementsByClassName("card")
+const cardsBackInContainer = document.getElementsByClassName("cardback")
+
+const resetButton = document.getElementById("reset")
+const winRate = document.getElementById("winrate")
+const dealButton = document.getElementById("deal")
+dealButton.innerText = `Deal`
+
+
+const cardName = document.getElementsByClassName("name")
+const cardSuit = document.getElementsByClassName("suit")
+const cardBody = document.getElementsByClassName("body")
+const holdText = document.getElementsByClassName("hold")
+
+const pointsAmt = document.getElementById("points")
+let clickAudio = document.getElementById("clickAudio")
+const winSound = document.getElementById("winSound")
+const loseSound = document.getElementById("loseSound")
+
+let hold = false;
+let playerHand = Array(5).fill(hold)
+let pointsNum = 100
+let gamesPlayed = 0
+let gamesWon = 0
+let gameEnd = false
+let deck;
+
+let deckCheck = []
+
+/**
+ * A function to generate a random index ranging from 0 (inclusive) to max (exclusive).
+ * @param max {number} maximum number (exclusive)
+ * @returns random index
+ */
+
+const getRandomIndex = (max) => Math.floor(Math.random() * max);
+
+/**
+ * A function to shuffle an array of cards
+ * @param cards {array}
+ * @returns {array} the shuffled deck
+ */
+
+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 = getRandomIndex(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;
+};
+
+/**
+ * A function to make a deck
+ * @returns {array} an unshuffled deck
+ */
+
+const makeDeck = () => {
+ // Initialise an empty deck array
+ const newDeck = [];
+ // Initialise an array of the 4 suits in our deck. We will loop over this array.
+ const suits = ['hearts', 'diamonds', 'clubs', 'spades'];
+ const symbols = ['♥', '♦', '♣', '♠']
+
+ // Loop over the suits array
+ for (let suitIndex = 0; suitIndex < suits.length; suitIndex += 1) {
+ // Store the current suit in a variable
+ const currentSuit = suits[suitIndex];
+ const suitSymbol = symbols[suitIndex]
+ let colour = "black"
+ if(suitIndex <= 1){
+ colour = "red"
+ }
+
+ // Loop from 1 to 13 to create all cards for a given suit
+ // Notice rankCounter starts at 1 and not 0, and ends at 13 and not 12.
+ // This is an example of a loop without an array.
+ for (let rankCounter = 1; rankCounter <= 13; rankCounter += 1) {
+ // By default, the card name is the same as rankCounter
+ let cardName = `${rankCounter}`;
+
+ // If rank is 1, 11, 12, or 13, set cardName to the ace or face card's name
+ if (cardName === '1') {
+ cardName = 'A';
+ } else if (cardName === '11') {
+ cardName = 'J';
+ } else if (cardName === '12') {
+ cardName = 'Q';
+ } else if (cardName === '13') {
+ cardName = 'K';
+ }
+ // Create a new card with the current name, suit, and rank
+ const card = {
+ name: cardName,
+ suit: currentSuit,
+ suitSymbol,
+ rank: rankCounter,
+ colour,
+ hold
+ };
+ // Add the new card to the deck
+ newDeck.push(card);
+ }
+ }
+
+ // Return the completed card deck
+ return newDeck;
+};
+
+let index = []
+
+/**
+ * A function to check for flushes and straights
+ * @param {array} playerHand
+ * returns if hand is straight flush, flush, or straight
+ */
+const flushCheck = (playerHand)=>{
+
+ playerHand.sort((a, b) => parseFloat(a.rank) - parseFloat(b.rank));
+ const suitTally = new Set(playerHand.map(function (hand) {
+ return hand.suit
+ }))
+
+ let flushCount = 0
+ for (let i =1 ; i < playerHand.length; i +=1){
+ if(playerHand[i-1].rank + 1 === playerHand[i].rank){
+ flushCount += 1
+ }
+ }
+
+ if(suitTally.size === 1){
+ index.push(4)
+ // console.log(`flush`)
+ if(flushCount === 4){
+ index.push(1)
+ // console.log(`straight flush`)
+ }
+ if(playerHand[0].rank + 12 === playerHand[4].rank && flushCount === 3){
+ index.push(0)
+ }
+ } else {
+ if(playerHand[0].rank + 12 === playerHand[4].rank && flushCount === 3 || (flushCount === 4)){
+ index.push(5)
+ // console.log(`straight`)
+ }
+ }
+ console.log(index)
+}
+
+/**
+ * A function to check for situations where there is >=2 of the same cardRank
+ * @param {array} playerHand
+ * returns all other conditions except high card
+ */
+const cardTally = (playerHand) =>{
+ let cardRankTally = {}
+ // Loop over hand
+ for (let i = 0; i < playerHand.length; i += 1) {
+ let cardRank = playerHand[i].rank;
+ // If we have seen the card name before, increment its count
+ if (cardRank in cardRankTally) {
+ cardRankTally[cardRank] += 1;
+ }
+ // Else, initialise count of this suit name to 1
+ else {
+ cardRankTally[cardRank] = 1;
+ }
+ }
+ console.log(cardRankTally)
+
+ let uniqueCardRanks = Object.keys(cardRankTally).length
+ let [key1, value1] = Object.entries(cardRankTally)[0]
+ let [key2, value2] = Object.entries(cardRankTally)[1]
+ console.log(uniqueCardRanks)
+
+ if(uniqueCardRanks === 5){
+ index.push(9)
+ console.log('lose')
+
+ }
+ //either four of a kind or full house
+ if(uniqueCardRanks === 2){
+ //four of a kind
+ if(value1 === 4 || value2 === 4){
+ index.push(2)
+ // console.log("four of a kind")
+ } else {
+ //fullhouse
+ index.push(3)
+ // console.log("fullhouse")
+ }
+ }
+ //either three of a kind or 2 pair
+ else if (uniqueCardRanks === 3){
+ if (value1 === 2 || value2 === 2){
+ index.push(7)
+ // console.log("two pair")
+ } else{
+ index.push(6)
+ // console.log("three of a kind")
+ }
+ }
+ else if (uniqueCardRanks === 4){
+ let highPair;
+ for (cardRank in cardRankTally){
+ if(cardRankTally[cardRank] === 2){
+ highPair = cardRank
+ }
+ console.log(highPair)
+ }
+ if(highPair >= 11 || highPair == 1){
+ index.push(8)
+ console.log('jacks or better')
+ } else{
+ index.push(9)
+ console.log('lose')
+ }
+
+ }
+ console.log(index)
+}
+
+/**
+ * A function to for output to abstract complexity of DOM manipulation away from game logic
+ * @param {string} message
+ */
+const output = (message) => {
+ document.getElementById("results").innerText = message
+};
+
+/**
+ * A function to check player's hand for number of cards & number of desginated 'hold' cards and to return the required number of cards.
+ * Also checks hand for end score afterthe second 'deal'
+ * @param {array} playerHand
+ * returns player's hand with 5 cards
+ */
+const deal = (playerHand) =>{
+
+ for (let i = 0; i < playerHand.length; i +=1){
+
+ holdText[i].innerText = ""
+ if( playerHand[i] === false || playerHand[i].hold === false){
+ console.log(playerHand)
+
+ if(playerHand[i].hold === false){
+
+ cardsInContainer[i].classList.toggle("toggle-full")
+ }
+
+ cardName[i].innerText = ""
+ cardSuit[i].innerText = ""
+ cardBody[i].innerText = ""
+ playerHand[i] = deck.pop()
+ cardsInContainer[i].classList.remove("red", "black")
+
+ cardName[i].innerText = playerHand[i].name
+ cardSuit[i].innerText = playerHand[i].suitSymbol
+ cardBody[i].innerText = playerHand[i].suitSymbol
+ cardsInContainer[i].classList.add(playerHand[i].colour)
+
+ let holdClick = 0
+
+ if(gameEnd === false){
+
+ cardsInContainer[i].addEventListener('click', ()=>{
+
+ if (count === 1){
+ clickAudio.play()
+ holdClick +=1;
+ if(holdClick % 2 !== 0){
+ playerHand[i].hold = true
+ holdText[i].innerText = "✋"
+ } else {
+ playerHand[i].hold = false
+ holdText[i].innerText = ""
+ }
+ }
+ })
+ }
+ }
+ deckCheck.push(playerHand[i])
+ console.log(deckCheck)
+ playerHand[i].hold = false
+
+ }
+ output("click cards to hold.")
+ if(gameEnd === true){
+ cardsInContainer.disabled = true
+ }
+ if (count === 2){
+ calcHandScore(playerHand)
+ count = 0
+ index = []
+ // betButton.disabled = false;
+ }
+ console.log(deck.length)
+}
+
+/**
+ * A function to check if deck is almost out of cards (<5 cards) or if a player is out of points to play
+ * @param {array} deck
+ * @param {number} pointsNum
+ * results in the game ending if either of the above conditions are true.
+ */
+const checkEndGame =(deck, pointsNum)=>{
+ console.log(pointsNum)
+ if(deck.length >= 5 && pointsNum > 0){
+ Array.from(document.querySelectorAll('#card-container .card')).forEach(e=>e.classList.add("toggle-half"))
+ } else {
+ gameEnd = true
+ betButton.disabled = true
+ dealButton.disabled = true
+ cardContainer.style.pointerEvents = "none"
+
+ resetButton.style.animation = "glowing 1300ms infinite"
+ setTimeout(()=>{
+ if (deck.length < 5) {
+ console.log(deck.length)
+ calcHandScore(playerHand)
+ setTimeout(output("out of cards! game ends!"), 1500)
+ // output("out of cards! game ends!")
+ } else if (pointsNum <= 0) {
+ output ("out of points! game ends!")
+ }
+ }, 1500)
+ }
+}
+
+
+/**
+ * A function to check for all winning conditions, including high card
+ * @param {array} playerHand
+ * returns resulting points
+ */
+let winningIndex;
+
+const calcHandScore = (playerHand) => {
+ gamesPlayed +=1
+
+ flushCheck(playerHand)
+ cardTally(playerHand)
+ winningIndex = Math.min(...index)
+ let pointsWagered = pointsList[winningIndex].points * betAmt
+ console.log(pointsNum)
+ if (winningIndex < 9){
+ pointsNum = pointsNum + pointsWagered
+ gamesWon +=1
+ winSound.play()
+ } else {
+ pointsNum = pointsNum - betAmt
+ loseSound.play()
+ }
+
+ pointsAmt.innerText = `Points: ${pointsNum}`
+ winRate.innerText = `Wins: ${gamesWon}/${gamesPlayed}`
+
+ output(`${pointsList[winningIndex].hand}! ${pointsWagered} points!`)
+
+ dealButton.disabled = true
+ betButton.disabled = true
+ const timeout = setTimeout(()=>{
+ console.log('timeout')
+ checkBet(betAmt, pointsNum)
+ if(gameEnd === false){
+ betButton.disabled = false
+ }
+ }
+ , 2000)
+
+}
+
+/**
+ * A function to initialise the game
+ * Highlights the column with bet 1
+ * Add event listeners to buttons
+ */
+const initGame =()=>{
+ createTable()
+ document.querySelector('#scoretable div:nth-child('+ (2) +')').id = "highlight"
+ output ("press deal to start.")
+
+ deck = shuffleCards(makeDeck())
+ pointsAmt.innerText = `Points: ${pointsNum}`
+
+ dealButton.addEventListener('click', ()=>{
+ clickAudio.play()
+ console.log(betAmt)
+ count += 1
+ console.log(betAmt)
+ if (count > 0) {
+ betButton.disabled = true;
+ }
+ deal(playerHand)
+ checkEndGame(deck, pointsNum)
+
+})
+ betButton.addEventListener('click', ()=>{
+ clickAudio.play()
+ console.log(betAmt)
+ if(betAmt === 5){
+ betAmt = 0
+ }
+ betAmt +=1
+ checkBet(betAmt,pointsNum)
+ highlightScore(betAmt)
+ })
+
+ resetButton.addEventListener('click', ()=>{
+ clickAudio.play()
+ setTimeout(()=>window.location.reload(),500)
+})
+
+}
+
+initGame()
\ No newline at end of file
diff --git a/style.css b/style.css
new file mode 100644
index 00000000..28e1805f
--- /dev/null
+++ b/style.css
@@ -0,0 +1,226 @@
+audio {
+ display: none;
+}
+body {
+ background-color: #0652dd;
+ font-family: "Alfa Slab One", cursive;
+ margin: 1vh, 1vw;
+ box-sizing: border-box;
+ width: 100vw;
+ height: 97vh;
+}
+header {
+ font-size: 8vh;
+ text-align: center;
+ -webkit-text-stroke: 3px white;
+ position: relative;
+ z-index: 2;
+ letter-spacing: 8px;
+ margin: 1vh auto;
+ font-family: "Press Start 2P", cursive;
+}
+
+#scoretable {
+ margin: auto 25vw;
+ display: grid;
+ grid-template-columns: repeat(6, 1fr);
+ grid-auto-rows: minmax(10vw, auto);
+ font-family: "Nanum Gothic", sans-serif;
+ font-size: 1.3vh;
+ text-transform: uppercase;
+ color: white;
+ text-align: center;
+ background-color: #a3cb38;
+ /* height: 40vh; */
+}
+
+#scoretable > div:nth-child(1) {
+ padding-left: 8%;
+ text-align: left;
+}
+
+#scoretable > div {
+ border: 2px dotted #009432;
+}
+div > p {
+ height: 1.2vh;
+ padding: 2px;
+}
+
+#highlight {
+ background-color: white;
+ color: #009432;
+}
+.linear-wipe {
+ text-align: center;
+
+ background: linear-gradient(
+ to right,
+ #fff 20%,
+ #ffc312 30%,
+ #f79f1f 70%,
+ #fff 90%
+ );
+ background-size: 200% auto;
+
+ color: #000;
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+
+ animation: shine 1s linear infinite;
+}
+@keyframes shine {
+ to {
+ background-position: 100% center;
+ }
+}
+
+#results {
+ /* height: 10vh; */
+ margin: 2vh auto;
+ text-align: center;
+ line-height: 3vh;
+ font-size: 2vh;
+ color: white;
+ text-transform: uppercase;
+ /* -webkit-text-stroke: 1px black; */
+ font-family: "Press Start 2P", cursive;
+}
+.card {
+ width: 80px;
+ height: 112px;
+ margin: 0px 10px;
+ position: relative;
+ transition: transform 1s;
+ transform-style: preserve-3d;
+ perspective: 1000px;
+ /* animation: animate 2s; */
+ background-color: transparent;
+ color: black;
+}
+
+.cardback,
+.cardfront {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ border-radius: 10px;
+ border: 2px solid black;
+ background-color: white;
+ top: 0px;
+ left: 0px;
+ padding: 5px;
+
+ backface-visibility: hidden;
+}
+.cardback {
+ /* background-color: white; */
+ border-radius: 10px;
+ transform: rotateY(180deg);
+}
+
+.cardfront img {
+ width: 100%;
+ height: 100%;
+}
+
+.toggle-half {
+ transform: rotateY(180deg);
+}
+
+div .toggle-full {
+ transform: rotateY(540deg);
+}
+
+div .toggle-none {
+ transform: rotateY(0deg);
+}
+.red {
+ color: #f93e3b;
+}
+
+.body {
+ text-align: center;
+ font-size: 6vh;
+ position: absolute;
+ top: 35%;
+ right: 25%;
+}
+
+.hold {
+ position: absolute;
+ bottom: 60%;
+ right: 5%;
+ font-size: 200%;
+ /* color: #3eda79;
+ -webkit-text-stroke: 1px white;
+ font-size: 2vh; */
+ /* letter-spacing: 1px;*/
+ /* z-index: 99; */
+}
+
+.in-active {
+ display: none;
+}
+#numbers {
+ display: flex;
+ justify-content: space-between;
+ margin: auto 28vw;
+ align-items: center;
+ font-size: 1.5vh;
+ color: white;
+ height: 10vh;
+ font-family: "Press Start 2P", cursive;
+}
+
+button {
+ /* margin: -8px 50px; */
+ background-color: #ffc312;
+ width: 12vh;
+ height: 7vh;
+ border-radius: 15px;
+ font-family: "Alfa Slab One", cursive;
+ font-size: 80%;
+ color: black;
+ border-width: 5px;
+}
+
+#bet,
+#deal {
+ animation: glowing 1300ms infinite;
+}
+#bet:disabled,
+#deal:disabled {
+ animation: none;
+}
+
+@keyframes glowing {
+ 0% {
+ color: black;
+ box-shadow: 0 0 3px white;
+ }
+ 50% {
+ color: black;
+ box-shadow: 0 0 10px white;
+ }
+ 100% {
+ color: black;
+ box-shadow: 0 0 3px white;
+ }
+}
+
+#reset {
+ background-color: #ea2027;
+ color: #ffc312;
+}
+
+@media (min-width: 768px) {
+ .container > .row {
+ padding: 0.5vh;
+ }
+
+ #results {
+ min-height: 4vh;
+ }
+}
diff --git a/winsound.mp3 b/winsound.mp3
new file mode 100644
index 00000000..00c27dd4
Binary files /dev/null and b/winsound.mp3 differ