From de88986279a9dd0bb9c4f8f1e60f6bdfd23d0e96 Mon Sep 17 00:00:00 2001 From: Nuuggs <69680070+Nuuggs@users.noreply.github.com> Date: Sun, 10 Oct 2021 17:22:58 +0800 Subject: [PATCH 1/7] completed base game --- package-lock.json | 2 +- script.js | 187 +++++++++++++++++++++++++++++++++++++++++++++- styles.css | 10 +++ 3 files changed, 197 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e29994..36e87f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "match-game-swe1", + "name": "match-game-bootcamp", "version": "1.0.0", "lockfileVersion": 1, "requires": true, diff --git a/script.js b/script.js index e2d0297..b84450a 100644 --- a/script.js +++ b/script.js @@ -1 +1,186 @@ -// Please implement exercise logic here +// GLOBAL VARIABLES +const boardSize = 4; +const board = []; +let firstCard = null; +let firstCardElement; +let deck; + +// GAMEPLAY LOGIC +const squareClick = (cardElement, column, row) => { + console.log(cardElement); + + console.log('FIRST CARD DOM ELEMENT', firstCard); + + console.log('BOARD CLICKED CARD', board[column][row]); + + const clickedCard = board[column][row]; + + // user clicked same square - tell user to pick another + if (cardElement.innerText !== '') { + return; + } + + // first turn + if (firstCard === null) { + console.log('first turn'); + firstCard = clickedCard; + // turn this card over + cardElement.innerText = firstCard.name; + + // hold onto this for later when it may not match + firstCardElement = cardElement; + + // second turn + } else { + console.log('second turn'); + if ( + clickedCard.name === firstCard.name + && clickedCard.suit === firstCard.suit + ) { + console.log('match'); + + // turn this card over + cardElement.innerText = clickedCard.name; + } else { + console.log('NOT a match'); + + // turn this card back over + firstCardElement.innerText = ''; + } + + // reset the first card + firstCard = null; + } +}; + +// GAME INITIALISATION LOGIC +// create all the board elements that will go on the screen +// return the built board +const buildBoardElements = (board) => { + // create the element that everything will go inside of + const boardElement = document.createElement('div'); + + // give it a class for CSS purposes + boardElement.classList.add('board'); + + // use the board data structure we passed in to create the correct size board + for (let i = 0; i < board.length; i += 1) { + // make a var for just this row of cards + const row = board[i]; + + // make an element for this row of cards + const rowElement = document.createElement('div'); + rowElement.classList.add('row'); + + // make all the squares for this row + for (let j = 0; j < row.length; j += 1) { + // create the square element + const square = document.createElement('div'); + + // set a class for CSS purposes + square.classList.add('square'); + + // set the click event + // eslint-disable-next-line + square.addEventListener('click', (event) => { + // we will want to pass in the card element so + // that we can change how it looks on screen, i.e., + // "turn the card over" + squareClick(event.currentTarget, i, j); + }); + + rowElement.appendChild(square); + } + boardElement.appendChild(rowElement); + } + + return boardElement; +}; + +const makeDeck = () => { + // create the empty deck at the beginning + const newDeck = []; + const suits = ['hearts', 'diamonds', 'clubs', 'spades']; + + for (let suitIndex = 0; suitIndex < suits.length; suitIndex += 1) { + // make a variable of the current suit + const currentSuit = suits[suitIndex]; + console.log(`current suit: ${currentSuit}`); + + // loop to create all cards in this suit + // rank 1-13 + for (let rankCounter = 1; rankCounter <= 13; rankCounter += 1) { + // Convert rankCounter to string + let cardName = `${rankCounter}`; + + // 1, 11, 12 ,13 + if (cardName === '1') { + cardName = 'ace'; + } else if (cardName === '11') { + cardName = 'jack'; + } else if (cardName === '12') { + cardName = 'queen'; + } else if (cardName === '13') { + cardName = 'king'; + } + + // make a single card object variable + const card = { + name: cardName, + suit: currentSuit, + rank: rankCounter, + }; + + console.log(`rank: ${rankCounter}`); + + // add the card to the deck + newDeck.push(card); // add double the cards to the deck + newDeck.push(card); + } + } + return newDeck; +}; + +// Get a random index ranging from 0 (inclusive) to max (exclusive). +const getRandomIndex = (max) => Math.floor(Math.random() * max); +// Shuffle an array of 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 = 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; +}; + +const initGame = () => { + // create this special deck by getting the doubled cards and + // making a smaller array that is ( boardSize squared ) number of cards + const doubleDeck = makeDeck(); + console.log(doubleDeck); + const deckSubset = doubleDeck.slice(0, boardSize * boardSize); + deck = shuffleCards(deckSubset); + console.log(deck); + + // deal the cards out to the board data structure + for (let i = 0; i < boardSize; i += 1) { + board.push([]); + for (let j = 0; j < boardSize; j += 1) { + board[i].push(deck.pop()); + } + } + console.log(board); + const boardEl = buildBoardElements(board); + + document.body.appendChild(boardEl); +}; + +initGame(); diff --git a/styles.css b/styles.css index 04e7110..e9bdddb 100644 --- a/styles.css +++ b/styles.css @@ -1,3 +1,13 @@ body { background-color: pink; } + +.square { + padding: 10px; + margin: 10px; + background-color: white; + display: inline-block; + height: 10px; + width: 10px; + vertical-align: top; +} From c4a34fffafadcbce966cd7498fee2a0d8fd8ed53 Mon Sep 17 00:00:00 2001 From: Nuuggs <69680070+Nuuggs@users.noreply.github.com> Date: Sun, 10 Oct 2021 20:46:10 +0800 Subject: [PATCH 2/7] completed introduction requirements --- script.js | 75 +++++++++++++++++++++++++++++++++++++++++------------- styles.css | 34 +++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 20 deletions(-) diff --git a/script.js b/script.js index b84450a..f339807 100644 --- a/script.js +++ b/script.js @@ -4,6 +4,8 @@ const board = []; let firstCard = null; let firstCardElement; let deck; +const gameInterface = document.createElement('div'); +gameInterface.classList.add('gameUi'); // GAMEPLAY LOGIC const squareClick = (cardElement, column, row) => { @@ -25,11 +27,13 @@ const squareClick = (cardElement, column, row) => { console.log('first turn'); firstCard = clickedCard; // turn this card over - cardElement.innerText = firstCard.name; + cardElement.innerText = `${firstCard.displayName} + ${firstCard.symbol}`; // hold onto this for later when it may not match firstCardElement = cardElement; + gameInterface.innerText = `You picked ${firstCard.name} of ${firstCard.suit}. Let's hope you pick its pair, click on another blank card!`; // second turn } else { console.log('second turn'); @@ -40,12 +44,17 @@ const squareClick = (cardElement, column, row) => { console.log('match'); // turn this card over - cardElement.innerText = clickedCard.name; + cardElement.innerText = `${clickedCard.displayName} + ${clickedCard.symbol}`; + + gameInterface.innerText = 'They matched, well done!! On to the next pair!'; } else { console.log('NOT a match'); // turn this card back over firstCardElement.innerText = ''; + + gameInterface.innerText = 'It did not match, try again!'; } // reset the first card @@ -80,6 +89,11 @@ const buildBoardElements = (board) => { // set a class for CSS purposes square.classList.add('square'); + // color + if (square.suit === 'diamonds' || square.suit === 'hearts') { + square.classList.add('red'); + } + // set the click event // eslint-disable-next-line square.addEventListener('click', (event) => { @@ -97,23 +111,30 @@ const buildBoardElements = (board) => { return boardElement; }; -const makeDeck = () => { - // create the empty deck at the beginning +const createDeck = () => { + // newDeck array to contain cards const newDeck = []; - const suits = ['hearts', 'diamonds', 'clubs', 'spades']; + + // outer loop. four suits; suit symbols; suit colors + const suits = ['diamonds', 'clubs', 'hearts', 'spades']; + const suitSymbols = ['♦️', '♣️', '♥️', '♠️']; for (let suitIndex = 0; suitIndex < suits.length; suitIndex += 1) { - // make a variable of the current suit const currentSuit = suits[suitIndex]; - console.log(`current suit: ${currentSuit}`); + const currentSymbol = suitSymbols[suitIndex]; - // loop to create all cards in this suit - // rank 1-13 + let suitColor = ''; + if (currentSuit === 'diamonds' || currentSuit === 'hearts') { + suitColor = 'red'; + } else if (currentSuit === 'clubs' || currentSuit === 'spades') { + suitColor = 'black'; + } + // inner loop. 1 to 13 ranks; for (let rankCounter = 1; rankCounter <= 13; rankCounter += 1) { - // Convert rankCounter to string + // Define card names let cardName = `${rankCounter}`; - - // 1, 11, 12 ,13 + let shortName = `${rankCounter}`; + // Define exceptions for card name if (cardName === '1') { cardName = 'ace'; } else if (cardName === '11') { @@ -124,20 +145,33 @@ const makeDeck = () => { cardName = 'king'; } - // make a single card object variable + // Define exceptions for display name + if (shortName === '1') { + shortName = 'A'; + } else if (shortName === '11') { + shortName = 'J'; + } else if (shortName === '12') { + shortName = 'Q'; + } else if (shortName === '13') { + shortName = 'K'; + } + + // Create Card const card = { name: cardName, suit: currentSuit, rank: rankCounter, + symbol: currentSymbol, + color: suitColor, + displayName: shortName, }; - console.log(`rank: ${rankCounter}`); - - // add the card to the deck - newDeck.push(card); // add double the cards to the deck + // add card to deck through push function. newDeck.push(card); + newDeck.push(card); // for pairs } } + return newDeck; }; @@ -164,7 +198,12 @@ const shuffleCards = (cards) => { const initGame = () => { // create this special deck by getting the doubled cards and // making a smaller array that is ( boardSize squared ) number of cards - const doubleDeck = makeDeck(); + document.body.appendChild(gameInterface); + gameInterface.innerText = `Hello, welcome to Match Game. + The rules are simple, find all the pairs to win! + + Click to begin playing :)`; + const doubleDeck = createDeck(); console.log(doubleDeck); const deckSubset = doubleDeck.slice(0, boardSize * boardSize); deck = shuffleCards(deckSubset); diff --git a/styles.css b/styles.css index e9bdddb..0cefe8f 100644 --- a/styles.css +++ b/styles.css @@ -1,13 +1,43 @@ body { background-color: pink; } +.gameUi { + font-size: large; + font-family: Cambria, Cochin, Georgia, Times, "Times New Roman", serif; +} .square { padding: 10px; margin: 10px; background-color: white; display: inline-block; - height: 10px; - width: 10px; + height: 50px; + width: 50px; vertical-align: top; + text-align: center; + font-weight: bold; + border-radius: 10px; + border-color: teal; + border-style: solid; + color: red; +} + +.suit { + margin: 5px; + font-size: 20px; +} + +.name { + margin: 5px; + font-size: 24px; + font-weight: bold; + font-family: sans-serif; +} + +.red { + color: red; +} + +.black { + color: black; } From 67bbb084b28ca7f853a3dde5dc788fe314bce6e4 Mon Sep 17 00:00:00 2001 From: Nuuggs <69680070+Nuuggs@users.noreply.github.com> Date: Sun, 10 Oct 2021 20:51:31 +0800 Subject: [PATCH 3/7] completed base game - setTimeout --- script.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/script.js b/script.js index f339807..725d8a1 100644 --- a/script.js +++ b/script.js @@ -51,8 +51,15 @@ const squareClick = (cardElement, column, row) => { } else { console.log('NOT a match'); - // turn this card back over - firstCardElement.innerText = ''; + // turn this card over + cardElement.innerText = `${clickedCard.displayName} + ${clickedCard.symbol}`; + + // turn this both cards back over AFTER DELAY + setTimeout(() => { + firstCardElement.innerText = ''; + cardElement.innerText = ''; + }, 3000); gameInterface.innerText = 'It did not match, try again!'; } From e0bd94c26b72c3aa8317d355ff9ab5b55fafb412 Mon Sep 17 00:00:00 2001 From: Nuuggs <69680070+Nuuggs@users.noreply.github.com> Date: Sun, 10 Oct 2021 20:55:00 +0800 Subject: [PATCH 4/7] completed comfortable - timed messages --- script.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/script.js b/script.js index 725d8a1..c031edd 100644 --- a/script.js +++ b/script.js @@ -42,15 +42,17 @@ const squareClick = (cardElement, column, row) => { && clickedCard.suit === firstCard.suit ) { console.log('match'); + gameInterface.innerText = 'They matched, well done!! On to the next pair!'; // turn this card over cardElement.innerText = `${clickedCard.displayName} ${clickedCard.symbol}`; - - gameInterface.innerText = 'They matched, well done!! On to the next pair!'; + setTimeout(() => { + gameInterface.innerText = ''; + }, 3000); } else { console.log('NOT a match'); - + gameInterface.innerText = 'It did not match, try again!'; // turn this card over cardElement.innerText = `${clickedCard.displayName} ${clickedCard.symbol}`; @@ -59,9 +61,8 @@ const squareClick = (cardElement, column, row) => { setTimeout(() => { firstCardElement.innerText = ''; cardElement.innerText = ''; + gameInterface.innerText = ''; }, 3000); - - gameInterface.innerText = 'It did not match, try again!'; } // reset the first card From 78954a46f8cba5a33ff2a8686a8921677a5b1244 Mon Sep 17 00:00:00 2001 From: Nuuggs <69680070+Nuuggs@users.noreply.github.com> Date: Sun, 10 Oct 2021 21:31:13 +0800 Subject: [PATCH 5/7] completed more comfortable: match game timer --- script.js | 35 ++++++++++++++++++++++++++++++++++- styles.css | 8 ++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/script.js b/script.js index c031edd..3e02c98 100644 --- a/script.js +++ b/script.js @@ -1,13 +1,36 @@ // GLOBAL VARIABLES -const boardSize = 4; +const boardSize = 6; const board = []; let firstCard = null; let firstCardElement; let deck; const gameInterface = document.createElement('div'); gameInterface.classList.add('gameUi'); +let playerWin; +const delayInMilliseconds = 1000; +const gameTimer = document.createElement('div'); +gameTimer.classList.add('timer'); +let timeCounter = 180; +let timerStarted = 0; // GAMEPLAY LOGIC +const startCountdownTimer = () => { + console.log('timer started!'); + timerStarted = 1; + const ref = setInterval(() => { + timeCounter -= 1; + console.log(timeCounter); + console.log(delayInMilliseconds); + gameTimer.innerText = `GAME TIME LIMIT + ${timeCounter}`; + if (timeCounter === 0) { + clearInterval(ref); + playerWin = 0; + gameInterface.innerText = 'Time is up, you lost! Try again?'; + } + }, delayInMilliseconds); +}; + const squareClick = (cardElement, column, row) => { console.log(cardElement); @@ -17,6 +40,12 @@ const squareClick = (cardElement, column, row) => { const clickedCard = board[column][row]; + // first click start timer. + if (timerStarted === 0) { + timerStarted = 1; + startCountdownTimer(); + } + // user clicked same square - tell user to pick another if (cardElement.innerText !== '') { return; @@ -206,7 +235,11 @@ const shuffleCards = (cards) => { const initGame = () => { // create this special deck by getting the doubled cards and // making a smaller array that is ( boardSize squared ) number of cards + document.body.appendChild(gameTimer); document.body.appendChild(gameInterface); + gameTimer.innerText = `GAME TIME LIMIT + ${timeCounter}`; + gameInterface.innerText = `Hello, welcome to Match Game. The rules are simple, find all the pairs to win! diff --git a/styles.css b/styles.css index 0cefe8f..4d19e0d 100644 --- a/styles.css +++ b/styles.css @@ -41,3 +41,11 @@ body { .black { color: black; } + +.timer { + margin-bottom: 10px; + font-weight: bold; + color: chocolate; + font-family: monospace; + font-size: 20px; +} From 58e14a88eebbc27bd43dfae41405dd0dbf657827 Mon Sep 17 00:00:00 2001 From: Nuuggs <69680070+Nuuggs@users.noreply.github.com> Date: Sun, 10 Oct 2021 22:10:42 +0800 Subject: [PATCH 6/7] completed more comfortable: enter username --- script.js | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/script.js b/script.js index 3e02c98..2b80c15 100644 --- a/script.js +++ b/script.js @@ -4,15 +4,24 @@ const board = []; let firstCard = null; let firstCardElement; let deck; + +// Game interface const gameInterface = document.createElement('div'); gameInterface.classList.add('gameUi'); -let playerWin; + +// Timer const delayInMilliseconds = 1000; const gameTimer = document.createElement('div'); gameTimer.classList.add('timer'); let timeCounter = 180; let timerStarted = 0; +// Username +let username; + +// Win-Lose +let playerWin; + // GAMEPLAY LOGIC const startCountdownTimer = () => { console.log('timer started!'); @@ -78,7 +87,7 @@ const squareClick = (cardElement, column, row) => { ${clickedCard.symbol}`; setTimeout(() => { gameInterface.innerText = ''; - }, 3000); + }, (delayInMilliseconds * 3)); } else { console.log('NOT a match'); gameInterface.innerText = 'It did not match, try again!'; @@ -91,7 +100,7 @@ const squareClick = (cardElement, column, row) => { firstCardElement.innerText = ''; cardElement.innerText = ''; gameInterface.innerText = ''; - }, 3000); + }, (delayInMilliseconds * 3)); } // reset the first card @@ -240,7 +249,7 @@ const initGame = () => { gameTimer.innerText = `GAME TIME LIMIT ${timeCounter}`; - gameInterface.innerText = `Hello, welcome to Match Game. + gameInterface.innerText = `Hello ${username}, welcome to Match Game. The rules are simple, find all the pairs to win! Click to begin playing :)`; @@ -263,4 +272,31 @@ const initGame = () => { document.body.appendChild(boardEl); }; -initGame(); +const preGame = () => { + // Username + const userInputDisplay = document.createElement('div'); + document.body.appendChild(userInputDisplay); + + const pregameMessage = document.createElement('p'); + userInputDisplay.appendChild(pregameMessage); + pregameMessage.innerText = ''; + + const usernameBox = document.createElement('input'); + usernameBox.setAttribute('type', 'text'); + usernameBox.setAttribute('placeholder', 'type your name here'); + // set id to retrieve user's name + usernameBox.setAttribute('id', 'username'); + userInputDisplay.appendChild(usernameBox); + + const inputButton = document.createElement('button'); + inputButton.innerText = 'submit name'; + userInputDisplay.appendChild(inputButton); + inputButton.addEventListener('click', () => { + const userInput = document.querySelector('#username'); + console.log(userInput); + username = userInput.value; + document.body.removeChild(userInputDisplay); + initGame(); + }); +}; +preGame(); From be251743b7e8b70472d12e6008b1fd3cb33257f5 Mon Sep 17 00:00:00 2001 From: Nuuggs <69680070+Nuuggs@users.noreply.github.com> Date: Sun, 10 Oct 2021 22:20:56 +0800 Subject: [PATCH 7/7] added canClick logic --- script.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/script.js b/script.js index 2b80c15..e079a18 100644 --- a/script.js +++ b/script.js @@ -16,6 +16,9 @@ gameTimer.classList.add('timer'); let timeCounter = 180; let timerStarted = 0; +// Click Validation +let canClick = true; + // Username let username; @@ -90,7 +93,9 @@ const squareClick = (cardElement, column, row) => { }, (delayInMilliseconds * 3)); } else { console.log('NOT a match'); - gameInterface.innerText = 'It did not match, try again!'; + gameInterface.innerText = `It did not match, try again! + You have a 3 seconds penalty and must wait until the cards flip back.`; + canClick = false; // turn this card over cardElement.innerText = `${clickedCard.displayName} ${clickedCard.symbol}`; @@ -100,6 +105,7 @@ const squareClick = (cardElement, column, row) => { firstCardElement.innerText = ''; cardElement.innerText = ''; gameInterface.innerText = ''; + canClick = true; }, (delayInMilliseconds * 3)); } @@ -146,7 +152,9 @@ const buildBoardElements = (board) => { // we will want to pass in the card element so // that we can change how it looks on screen, i.e., // "turn the card over" - squareClick(event.currentTarget, i, j); + if (canClick === true) { + squareClick(event.currentTarget, i, j); + } }); rowElement.appendChild(square);