From d02b1f16da1585f94c678f5823ffce62be67e5c3 Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Wed, 6 Sep 2023 14:14:01 +0200 Subject: [PATCH 01/16] step one complete: Load characters onto the board --- code/script.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/code/script.js b/code/script.js index 5207730c..3950804f 100644 --- a/code/script.js +++ b/code/script.js @@ -2,6 +2,7 @@ const board = document.getElementById('board') const questions = document.getElementById('questions') const restartButton = document.getElementById('restart') +const findOutBtn = document.getElementById('findOut') // Array with all the characters, as objects const CHARACTERS = [ @@ -215,7 +216,7 @@ const generateBoard = () => { ${person.name}
Guess on ${person.name}? - +
` @@ -223,6 +224,11 @@ const generateBoard = () => { } // Randomly select a person from the characters array and set as the value of the variable called secret +/* The setSecret function randomly selects a character from the + charactersInPlay array and designates it as the "secret" character. +The random character selection is based on the index number calculated using Math.random(). Since we have 24 characters and the index starts at 0, by using the math.floor() method the highest number that can be calculated is 23, which is the last character in the array. +charactersInPlay.length = the number of elements in the array. +*/ const setSecret = () => { secret = charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)] } @@ -231,6 +237,8 @@ const setSecret = () => { const start = () => { // Here we're setting charactersInPlay array to be all the characters to start with charactersInPlay = CHARACTERS + // Invoke/use the function generateBoard to load all the characters on the board. + generateBoard(charactersInPlay); // What else should happen when we start the game? } From 7ffe696d9c8a21ae752f0a73dd80569bb3fedc6b Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Wed, 6 Sep 2023 14:20:34 +0200 Subject: [PATCH 02/16] Step 2: set a randomly chosen character from the array as the one to find --- code/script.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/code/script.js b/code/script.js index 3950804f..b5d436e7 100644 --- a/code/script.js +++ b/code/script.js @@ -224,8 +224,7 @@ const generateBoard = () => { } // Randomly select a person from the characters array and set as the value of the variable called secret -/* The setSecret function randomly selects a character from the - charactersInPlay array and designates it as the "secret" character. +/* The random character selection is based on the index number calculated using Math.random(). Since we have 24 characters and the index starts at 0, by using the math.floor() method the highest number that can be calculated is 23, which is the last character in the array. charactersInPlay.length = the number of elements in the array. */ @@ -239,7 +238,10 @@ const start = () => { charactersInPlay = CHARACTERS // Invoke/use the function generateBoard to load all the characters on the board. generateBoard(charactersInPlay); - // What else should happen when we start the game? + + //Randomly select a character from the charactersInPlay array and designate it as the "secret" character. + setSecret(); + console.log("The secret character is:", secret); } // setting the currentQuestion object when you select something in the dropdown From fe7af266957d913b3feeb5298293d356104be2aa Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Wed, 6 Sep 2023 16:59:46 +0200 Subject: [PATCH 03/16] step 3: added eventlistener for the drop-down menu and a variable that stores the value of the question that has been selected. --- code/script.js | 31 ++++++++++++++++++++++--------- scriptExplanations.js | 0 2 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 scriptExplanations.js diff --git a/code/script.js b/code/script.js index b5d436e7..2ebf2ba4 100644 --- a/code/script.js +++ b/code/script.js @@ -224,9 +224,10 @@ const generateBoard = () => { } // Randomly select a person from the characters array and set as the value of the variable called secret -/* -The random character selection is based on the index number calculated using Math.random(). Since we have 24 characters and the index starts at 0, by using the math.floor() method the highest number that can be calculated is 23, which is the last character in the array. -charactersInPlay.length = the number of elements in the array. +/* Explanation for setSecret() + The random character selection is based on the index number calculated using Math.random(). Math.random() generates decimal numbers 0>= x < 1. + Since we have 24 characters and the index starts at 0, by also using the math.floor() method (that rounds down to the closest integer) the highest number that can be calculated is 23, which is the last character in the array[]. + charactersInPlay.length = the number of elements in the array. */ const setSecret = () => { secret = charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)] @@ -238,26 +239,37 @@ const start = () => { charactersInPlay = CHARACTERS // Invoke/use the function generateBoard to load all the characters on the board. generateBoard(charactersInPlay); - + //Randomly select a character from the charactersInPlay array and designate it as the "secret" character. setSecret(); console.log("The secret character is:", secret); } // setting the currentQuestion object when you select something in the dropdown +/* EXPLANATION +const category: stores what option group (category) the question belongs to + questions.options[questions.selectedIndex] retrieves the specific element and retrieves the label attribute of that element. + So the whole expression is used to retrieve the label of the element from the option that is currently selected in the drop-down menu +*/ const selectQuestion = () => { - const category = questions.options[questions.selectedIndex].parentNode.label + const category = questions.options[questions.selectedIndex].parentNode.label; - // This variable stores what option group (category) the question belongs to. - // We also need a variable that stores the actual value of the question we've selected. - // const value = + // Variable that stores the actual value of the question that has been selected. + const value = questions.options[questions.selectedIndex].value; currentQuestion = { category: category, - // value: value + value: value } + console.log(currentQuestion); } +// Event listener for the dropdown menu +questions.addEventListener('change', selectQuestion); + + // This function should be invoked when you click on 'Find Out' button. const checkQuestion = () => { const { category, value } = currentQuestion @@ -333,3 +345,4 @@ start() // All the event listeners restartButton.addEventListener('click', start) + diff --git a/scriptExplanations.js b/scriptExplanations.js new file mode 100644 index 00000000..e69de29b From f174b28872b71e659e837045aac7bc51734496ed Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Thu, 7 Sep 2023 17:27:57 +0200 Subject: [PATCH 04/16] step 4: functioning 'find out' button and checkQuestion function (to compare values between 'secret' and the user's choice). Also added alert messages to the user which is part of step 5 --- code/script.js | 105 +++++++++++++++++++++++++++++-------- code/scriptExplanations.js | 0 2 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 code/scriptExplanations.js diff --git a/code/script.js b/code/script.js index 2ebf2ba4..f1eacba0 100644 --- a/code/script.js +++ b/code/script.js @@ -2,7 +2,8 @@ const board = document.getElementById('board') const questions = document.getElementById('questions') const restartButton = document.getElementById('restart') -const findOutBtn = document.getElementById('findOut') +const filterBtn = document.getElementById('filter') + // Array with all the characters, as objects const CHARACTERS = [ @@ -216,11 +217,12 @@ const generateBoard = () => { ${person.name}
Guess on ${person.name}? - +
` - }) + } + ) } // Randomly select a person from the characters array and set as the value of the variable called secret @@ -243,6 +245,7 @@ const start = () => { //Randomly select a character from the charactersInPlay array and designate it as the "secret" character. setSecret(); console.log("The secret character is:", secret); + console.log("secret is this data type:", typeof (secret)); } // setting the currentQuestion object when you select something in the dropdown @@ -254,41 +257,84 @@ const category: stores what option group (category) the question belongs to So the whole expression is used to retrieve the label of the element from the option that is currently selected in the drop-down menu */ const selectQuestion = () => { - const category = questions.options[questions.selectedIndex].parentNode.label; + const selectedOption = questions.options[questions.selectedIndex]; + const category = selectedOption.parentNode.label; // Variable that stores the actual value of the question that has been selected. - const value = questions.options[questions.selectedIndex].value; + const value = selectedOption.value; currentQuestion = { category: category, value: value - } - console.log(currentQuestion); + }; + console.log("This is the category and value of currentQuestion", currentQuestion); } -// Event listener for the dropdown menu -questions.addEventListener('change', selectQuestion); - // This function should be invoked when you click on 'Find Out' button. const checkQuestion = () => { - const { category, value } = currentQuestion + /* Explanation: Object destructuring + extract data from an object and assign to new variables. + Another way to do this is: + const category = currentQuestion.category; + const value = currentQuestion.value; + The destructuring makes it easier to extract data + */ + const { category, value } = currentQuestion; // Compare the currentQuestion details with the secret person details in a different manner based on category (hair/eyes or accessories/others). // See if we should keep or remove people based on that - // Then invoke filterCharacters - if (category === 'hair' || category === 'eyes') { - } else if (category === 'accessories' || category === 'other') { + /* + this is divided like this since the first two categories will have one to one comparisons while the other two categories contain properties with multiple values + */ + let keep = ""; + if (category === 'hair' || category === 'eyes') { + // Accessing the [category] property of the secret object and compare it to the value (a property of the currentQuestion object) of the player's choice to see if they match. + if (secret[category] === value) { + keep = true; + } else { + keep = false; + } + } else if (category === 'accessories' || category === 'other') { + if (secret[category].includes(value)) { // .includes() since there are multiple values + keep = true; + }else { + keep = false; } } +console.log('keep:', keep); + // Then invoke filterCharacters +filterCharacters(keep); +} // It'll filter the characters array and redraw the game board. const filterCharacters = (keep) => { const { category, value } = currentQuestion // Show the correct alert message for different categories - if (category === 'accessories') { + +if (category === 'hair') { + if (keep) { + alert( + `Yes, the person has ${value} hair! Keep all people that have ${value} hair.` + ) + } else { + alert( + `No, the person doesn't have ${value} hair! Remove all people that have ${value} hair.` + ) + } +} else if (category === 'eyes') { + if (keep) { + alert( + `Yes, the person has ${value} eyes! Keep all people that have ${value} eyes.` + ) + } else { + alert( + `No, the person doesn't have ${value} eyes! Remove all people that have ${value} eyes.` + ) + } +} else if (category === 'accessories') { if (keep) { alert( `Yes, the person wears ${value}! Keep all people that wears ${value}` @@ -298,16 +344,17 @@ const filterCharacters = (keep) => { `No, the person doesn't wear ${value}! Remove all people that wears ${value}` ) } - } else if (category === 'other') { - // Similar to the one above } else { if (keep) { - // alert popup that says something like: "Yes, the person has yellow hair! Keep all people with yellow hair" + alert( + `Yes, the person has a ${value}! Keep all people that have a ${value}.` + ) } else { - // alert popup that says something like: "No, the person doesnt have yellow hair! Remove all people with yellow hair" + alert( + `No, the person doesn't have a ${value}! Remove all people that have a ${value}.` + ) } } - // Determine what is the category // filter by category to keep or remove based on the keep variable. /* @@ -317,12 +364,15 @@ const filterCharacters = (keep) => { charactersInPlay = charactersInPlay.filter((person) => person[attribute] !== value) for accessories and other + + charactersInPlay = charactersInPlay.filter((person) => person[category].includes(value)) or charactersInPlay = charactersInPlay.filter((person) => !person[category].includes(value)) */ // Invoke a function to redraw the board with the remaining people. + generateBoard(); } // when clicking guess, the player first have to confirm that they want to make a guess. @@ -345,4 +395,17 @@ start() // All the event listeners restartButton.addEventListener('click', start) - +// Event listener for the dropdown menu +questions.addEventListener('change', selectQuestion); +// Event listener for find out-button +/* EXPLANATION, event listeners: +there are two different options: +filterBtn.addEventListener('click', checkQuestion); +or +In this one i can pass in an argument to the function: +filterBtn.addEventListener('click', () => checkQuestion()); +if I type: +filterBtn.addEventListener('click', checkQuestion()); +the function will be run immediately without Javascript listening to the event which is not what i want here. +*/ +filterBtn.addEventListener('click', () => checkQuestion()); diff --git a/code/scriptExplanations.js b/code/scriptExplanations.js new file mode 100644 index 00000000..e69de29b From 51813a23152d4ae7cbf0ba1d24bb54c527ccd419 Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Thu, 7 Sep 2023 21:34:30 +0200 Subject: [PATCH 05/16] filter() method implmented. Known bug regarding default option in the drop-down menu --- README.md | 5 ++ code/script.js | 108 +++++++++++++++++++----------------------- scriptExplanations.js | 0 3 files changed, 55 insertions(+), 58 deletions(-) delete mode 100644 scriptExplanations.js diff --git a/README.md b/README.md index 60f55e53..f2ae36b6 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,8 @@ Describe how you approached to problem, and what tools and techniques you used t ## View it live Have you deployed your project somewhere? Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. + + +## Known bugs +Choosing the default option in the drop-down menu crashes the game. +The default option works if you first choose something else and then select it. \ No newline at end of file diff --git a/code/script.js b/code/script.js index f1eacba0..4d7df3cf 100644 --- a/code/script.js +++ b/code/script.js @@ -203,7 +203,7 @@ const CHARACTERS = [ ] // Global variables -let secret +let secretCharacter let currentQuestion let charactersInPlay @@ -231,8 +231,8 @@ const generateBoard = () => { Since we have 24 characters and the index starts at 0, by also using the math.floor() method (that rounds down to the closest integer) the highest number that can be calculated is 23, which is the last character in the array[]. charactersInPlay.length = the number of elements in the array. */ -const setSecret = () => { - secret = charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)] +const setSecretCharacter = () => { + secretCharacter = charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)] } // This function to start (and restart) the game @@ -243,9 +243,9 @@ const start = () => { generateBoard(charactersInPlay); //Randomly select a character from the charactersInPlay array and designate it as the "secret" character. - setSecret(); - console.log("The secret character is:", secret); - console.log("secret is this data type:", typeof (secret)); + setSecretCharacter(); + console.log("The secret character is:", secretCharacter); + console.log("secret is this data type:", typeof (secretCharacter)); } // setting the currentQuestion object when you select something in the dropdown @@ -286,90 +286,82 @@ const checkQuestion = () => { // See if we should keep or remove people based on that /* - this is divided like this since the first two categories will have one to one comparisons while the other two categories contain properties with multiple values + This is divided like this since the first two categories will have one to one comparisons while the other two categories contain properties with multiple values */ - let keep = ""; + let keep = false; if (category === 'hair' || category === 'eyes') { - // Accessing the [category] property of the secret object and compare it to the value (a property of the currentQuestion object) of the player's choice to see if they match. - if (secret[category] === value) { + /* + We're accessing a CHARACTER object (via the variable secret) and look through its attributes until we find one that matches the category in the if statement. Once found we take the value (for example "yellow hair") and compare to the player's choice to see if the match. + */ + if (value === secretCharacter[category]) { keep = true; - } else { - keep = false; } } else if (category === 'accessories' || category === 'other') { - if (secret[category].includes(value)) { // .includes() since there are multiple values + if (secretCharacter[category].includes(value)) { // .includes() since there are multiple values keep = true; - }else { - keep = false; + } } -} -console.log('keep:', keep); + console.log('keep:', keep); // Then invoke filterCharacters -filterCharacters(keep); + filterCharacters(keep); } // It'll filter the characters array and redraw the game board. -const filterCharacters = (keep) => { +const filterCharacters = (keepParameter) => { const { category, value } = currentQuestion // Show the correct alert message for different categories - -if (category === 'hair') { - if (keep) { - alert( - `Yes, the person has ${value} hair! Keep all people that have ${value} hair.` - ) - } else { - alert( - `No, the person doesn't have ${value} hair! Remove all people that have ${value} hair.` - ) - } -} else if (category === 'eyes') { - if (keep) { - alert( - `Yes, the person has ${value} eyes! Keep all people that have ${value} eyes.` - ) - } else { - alert( - `No, the person doesn't have ${value} eyes! Remove all people that have ${value} eyes.` - ) - } -} else if (category === 'accessories') { - if (keep) { + console.log(charactersInPlay); + if (category === 'hair') { + // since keep parameter is a boolean there's no need to do an equation. + if (keepParameter) { + alert( + `Yes, the person has ${value} hair! Keep all people that have ${value} hair.` + ) + charactersInPlay = charactersInPlay.filter((person) => { person[category] === value }) + } else { + alert( + `No, the person doesn't have ${value} hair! Remove all people that have ${value} hair.` + ) + charactersInPlay = charactersInPlay.filter((person) => person[category] !== value) + } + } else if (category === 'eyes') { + if (keepParameter) { + alert( + `Yes, the person has ${value} eyes! Keep all people that have ${value} eyes.` + ) + charactersInPlay = charactersInPlay.filter((person) => { person[category] === value }) + } else { + alert( + `No, the person doesn't have ${value} eyes! Remove all people that have ${value} eyes.` + ) + charactersInPlay = charactersInPlay.filter((person) => person[category] !== value) + } + } else if (category === 'accessories') { + if (keepParameter) { alert( `Yes, the person wears ${value}! Keep all people that wears ${value}` ) + charactersInPlay = charactersInPlay.filter((person) => person[category].includes(value)) } else { alert( `No, the person doesn't wear ${value}! Remove all people that wears ${value}` ) + charactersInPlay = charactersInPlay.filter((person) => !person[category].includes(value)) } } else { - if (keep) { + if (keepParameter) { alert( `Yes, the person has a ${value}! Keep all people that have a ${value}.` ) + charactersInPlay = charactersInPlay.filter((person) => person[category].includes(value)) } else { alert( `No, the person doesn't have a ${value}! Remove all people that have a ${value}.` ) + charactersInPlay = charactersInPlay.filter((person) => !person[category].includes(value)) } } - // Determine what is the category - // filter by category to keep or remove based on the keep variable. - /* - for hair and eyes : - charactersInPlay = charactersInPlay.filter((person) => person[attribute] === value) - or - charactersInPlay = charactersInPlay.filter((person) => person[attribute] !== value) - - for accessories and other - - - charactersInPlay = charactersInPlay.filter((person) => person[category].includes(value)) - or - charactersInPlay = charactersInPlay.filter((person) => !person[category].includes(value)) - */ // Invoke a function to redraw the board with the remaining people. generateBoard(); diff --git a/scriptExplanations.js b/scriptExplanations.js deleted file mode 100644 index e69de29b..00000000 From b4ced4976db8d73d9f1004bc44edcb6acb836607 Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Thu, 7 Sep 2023 22:21:28 +0200 Subject: [PATCH 06/16] step 6: guess function implemented --- code/index.html | 13 ++++++++++--- code/script.js | 11 +++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/code/index.html b/code/index.html index 0479b061..b524490f 100644 --- a/code/index.html +++ b/code/index.html @@ -26,15 +26,22 @@

Does the person have

- + + + + + + - + + + - + diff --git a/code/script.js b/code/script.js index 4d7df3cf..e9a0494e 100644 --- a/code/script.js +++ b/code/script.js @@ -370,16 +370,27 @@ const filterCharacters = (keepParameter) => { // when clicking guess, the player first have to confirm that they want to make a guess. const guess = (personToConfirm) => { // store the interaction from the player in a variable. + console.log("guess= ", personToConfirm); // remember the confirm() ? +let result = confirm(`Are you sure you want to pick ${personToConfirm}?`); // If the player wants to guess, invoke the checkMyGuess function. + if (result){ + checkMyGuess(personToConfirm); + } } // If you confirm, this function is invoked const checkMyGuess = (personToCheck) => { // 1. Check if the personToCheck is the same as the secret person's name + if(personToCheck === secretCharacter.name) { + alert("Yay! That was correct! Congratz!") + } else { + alert("Oh, no! That was the wrong answer! Better luck next time!") + } // 2. Set a Message to show in the win or lose section accordingly // 3. Show the win or lose section // 4. Hide the game board + board.style.visibility = 'hidden' } // Invokes the start function when website is loaded From 1271afac669fbf6329ce6d4ce277e157de8fb239 Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Thu, 7 Sep 2023 22:22:27 +0200 Subject: [PATCH 07/16] first version completed --- code/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/script.js b/code/script.js index e9a0494e..e8c86e54 100644 --- a/code/script.js +++ b/code/script.js @@ -318,7 +318,7 @@ const filterCharacters = (keepParameter) => { alert( `Yes, the person has ${value} hair! Keep all people that have ${value} hair.` ) - charactersInPlay = charactersInPlay.filter((person) => { person[category] === value }) + charactersInPlay = charactersInPlay.filter((person) => person[category] === value) } else { alert( `No, the person doesn't have ${value} hair! Remove all people that have ${value} hair.` From 54a48c0fa8034d9d4d84939bba41225f2c73c625 Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Fri, 8 Sep 2023 09:25:20 +0200 Subject: [PATCH 08/16] added a workaround for the bug that the default option can't be selected first --- code/index.html | 1 + code/script.js | 17 ++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/index.html b/code/index.html index b524490f..2cbe664f 100644 --- a/code/index.html +++ b/code/index.html @@ -23,6 +23,7 @@

Does the person have

- - - - - - - - - - - - - - - + + + + + + - - - + + + + + + + + + + + + - + + + + + - @@ -58,11 +61,11 @@

Does the person have

- Guess Who + /> -->

diff --git a/code/script.js b/code/script.js index 48068311..4c7bea79 100644 --- a/code/script.js +++ b/code/script.js @@ -11,201 +11,176 @@ const playAgainBtn = document.getElementById("playAgain") // Array with all the characters, as objects -const CHARACTERS = [ +const POKEMON = [ { - name: 'Jabala', - img: 'images/jabala.svg', - hair: 'hidden', - eyes: 'hidden', - accessories: ['glasses', 'hat'], - other: [] + name: 'Pikachu', + img: 'images/Pikachu.png', + color: 'yellow', + type: ['electric'], + other: ['tail'] }, { - name: 'Jack', - img: 'images/jack.svg', - hair: 'hidden', - eyes: 'blue', - accessories: ['hat'], - other: [] + name: 'Ninetales', + img: 'images/Ninetales.png', + color: 'yellow', + type: ['fire'], + other: ['tail'] }, { - name: 'Jacques', - img: 'images/jacques.svg', - hair: 'grey', - eyes: 'blue', - accessories: ['hat'], - other: ['smoker'] + name: 'Beedrill', + img: 'images/Beedrill.png', + color: 'yellow', + type: ['bug', 'poison'], + other: ['stinger'] }, { - name: 'Jai', - img: 'images/jai.svg', - hair: 'black', - eyes: 'brown', - accessories: [], - other: [] + name: 'Meowth', + img: 'images/Meowth.png', + color: 'yellow', + type: ['normal'], + other: ['tail'] }, { - name: 'Jake', - img: 'images/jake.svg', - hair: 'yellow', - eyes: 'green', - accessories: ['glasses'], - other: [] + name: 'Ponyta', + img: 'images/Ponyta.png', + color: 'yellow', + type: ['fire'], + other: ['tail', 'flame'] }, { - name: 'James', - img: 'images/james.svg', - hair: 'brown', - eyes: 'green', - accessories: ['glasses'], + name: 'Jigglypuff', + img: 'images/Jigglypuff.png', + color: 'pink', + type: ['normal', 'fairy'], other: [] }, { - name: 'Jana', - img: 'images/jana.svg', - hair: 'black', - eyes: 'hidden', - accessories: ['glasses'], - other: [] + name: 'Mew', + img: 'images/Mew.png', + color: 'pink', + type: ['psychic'], + other: ['tail'] }, { - name: 'Jane', - img: 'images/jane.svg', - hair: 'yellow', - eyes: 'hidden', - accessories: ['glasses'], - other: [] + name: 'Clefairy', + img: 'images/Clefairy.png', + color: 'pink', + type: ['fairy'], + other: ['tail'] }, { - name: 'Jaqueline', - img: 'images/jaqueline.svg', - hair: 'orange', - eyes: 'green', - accessories: ['glasses'], - other: [] + name: 'Chansey', + img: 'images/Chansey.png', + color: 'pink', + type: ['normal'], + other: ['tail'] }, - { - name: 'Jazebelle', - img: 'images/jazebelle.svg', - hair: 'purple', - eyes: 'hidden', - accessories: ['glasses'], - other: ['smoker'] + name: 'Squirtle', + img: 'images/Squirtle.png', + color: 'blue', + type: ['water'], + other: ['tail'] }, { - name: 'Jean', - img: 'images/jean.svg', - hair: 'brown', - eyes: 'blue', - accessories: ['glasses', 'hat'], - other: ['smoker'] + name: 'Gloom', + img: 'images/Gloom.png', + color: 'blue', + type: ['grass', 'poison'], + other: ['plant'] }, { - name: 'Jeane', - img: 'images/jeane.svg', - hair: 'brown', - eyes: 'green', - accessories: ['glasses'], - other: [] + name: 'Vaporeon', + img: 'images/Vaporeon.png', + color: 'blue', + type: ['water'], + other: ['tail', 'fin'] }, { - name: 'Jed', - img: 'images/jed.svg', - hair: 'orange', - eyes: 'green', - accessories: ['glasses', 'hat'], - other: ['smoker'] + name: 'Seadra', + img: 'images/Seadra.png', + color: 'blue', + type: ['water'], + other: ['tail', 'fin'] }, { - name: 'Jenni', - img: 'images/jenni.svg', - hair: 'white', - eyes: 'hidden', - accessories: ['hat'], - other: [] + name: 'Lapras', + img: 'images/Lapras.png', + color: 'blue', + type: ['water', 'ice'], + other: ['tail', 'fin'] }, { - name: 'Jeri', - img: 'images/jeri.svg', - hair: 'orange', - eyes: 'green', - accessories: ['glasses'], + name: 'Poliwhirl', + img: 'images/Poliwhirl.png', + color: 'blue', + type: ['water'], other: [] }, { - name: 'Jerry', - img: 'images/jerry.svg', - hair: 'hidden', - eyes: 'blue', - accessories: ['hat'], - other: [] + name: 'Charmander', + img: 'images/Charmander.png', + color: 'red', + type: ['fire'], + other: ['tail', 'flame'] }, { - name: 'Jess', - img: 'images/jess.svg', - hair: 'black', - eyes: 'blue', - accessories: ['glasses'], - other: [] + name: 'Vileplume', + img: 'images/Vileplume.png', + color: 'blue', + type: ['grass', 'poison'], + other: ['plant'] }, { - name: 'Jocelyn', - img: 'images/jocelyn.svg', - hair: 'black', - eyes: 'brown', - accessories: ['glasses'], - other: [] - }, + name: 'Electabuzz', + img: 'images/Electabuzz.png', + color: 'yellow', + type: ['electric'], + other: ['tail'], + }, { - name: 'Jon', - img: 'images/jon.svg', - hair: 'brown', - eyes: 'green', - accessories: ['glasses'], - other: [] + name: 'Flareon', + img: 'images/Flareon.png', + color: 'red', + type: ['fire'], + other: ['tail'] }, { - name: 'Jordan', - img: 'images/jordan.svg', - hair: 'yellow', - eyes: 'hidden', - accessories: ['glasses', 'hat'], + name: 'Krabby', + img: 'images/Krabby.png', + color: 'red', + type: ['water'], other: [] }, { - name: 'Josephine', - img: 'images/josephine.svg', - hair: 'grey', - eyes: 'brown', - accessories: [], - other: [] + name: 'Seaking', + img: 'images/Seaking.png', + color: 'red', + type: ['water'], + other: ['fin'] }, { - name: 'Josh', - img: 'images/josh.svg', - hair: 'yellow', - eyes: 'green', - accessories: [], - other: [] + name: 'Bulbasaur', + img: 'images/Bulbasaur.png', + color: 'green', + type: ['grass', 'poison'], + other: ['plant'] }, { - name: 'Jude', - img: 'images/jude.svg', - hair: 'black', - eyes: 'green', - accessories: [], - other: [] + name: 'Caterpie', + img: 'images/Caterpie.png', + color: 'green', + type: ['bug'], + other: ['tail'] }, { - name: 'Julie', - img: 'images/julie.svg', - hair: 'black', - eyes: 'brown', - accessories: ['glasses', 'hat'], - other: [] + name: 'Scyther', + img: 'images/Scyther.png', + color: 'green', + type: ['bug', 'flying'], + other: ['tail'] }, -] +]; // Global variables let secretCharacter @@ -215,14 +190,14 @@ let charactersInPlay // Draw the game board const generateBoard = () => { board.innerHTML = '' - charactersInPlay.forEach((person) => { + charactersInPlay.forEach((pokemon) => { board.innerHTML += `
-

${person.name}

- ${person.name} +

${pokemon.name}

+ ${pokemon.name}
- Guess on ${person.name}? - + Guess on ${pokemon.name}? +
` @@ -243,7 +218,7 @@ const setSecretCharacter = () => { // This function to start (and restart) the game const start = () => { // Here we're setting charactersInPlay array to be all the characters to start with - charactersInPlay = CHARACTERS + charactersInPlay = POKEMON // Invoke/use the function generateBoard to load all the characters on the board. generateBoard(charactersInPlay); @@ -296,11 +271,11 @@ const checkQuestion = () => { We're accessing a CHARACTER object (via the variable secretCharacter) and look through its attributes until we find one that matches the category in the if statement. Once found we take the value (for example "yellow hair") and compare that to the player's choice to see if the match.*/ let keep = false; //Chose "false" to make the code below easier for me to read (and avoid !) - if (category === 'hair' || category === 'eyes') { + if (category === 'color') { if (value === secretCharacter[category]) { keep = true; } - } else if (category === 'accessories' || category === 'other') { + } else if (category === 'type'|| category === 'other') { if (secretCharacter[category].includes(value)) { // .includes() since there are multiple values keep = true; } @@ -315,80 +290,67 @@ const filterCharacters = (keepParam) => { const { category, value } = currentQuestion // Show the correct alert message for different categories console.log(charactersInPlay); - if (category === 'hair') { + if (category === 'color') { // since keep parameter is a boolean there's no need to do an equation. if (keepParam) { alert( - `Yes, the person has ${value} hair! Keep all people that have ${value} hair.` + `Yes, the pokemon is ${value}! Keep all pokemon that are ${value}.` ) - charactersInPlay = charactersInPlay.filter((person) => person[category] === value) + charactersInPlay = charactersInPlay.filter((pokemon) => pokemon[category] === value) } else { alert( - `No, the person doesn't have ${value} hair! Remove all people that have ${value} hair.` + `No, the pokemon isn't ${value}! Remove all pokemon that are ${value}.` ) - charactersInPlay = charactersInPlay.filter((person) => person[category] !== value) + charactersInPlay = charactersInPlay.filter((pokemon) => pokemon[category] !== value) } - } else if (category === 'eyes') { + } else if (category === 'type') { if (keepParam) { alert( - `Yes, the person has ${value} eyes! Keep all people that have ${value} eyes.` + `Yes, the pokemon has the ${value} type! Keep all pokemon that have the ${value} type.` ) - charactersInPlay = charactersInPlay.filter((person) => { person[category] === value }) + charactersInPlay = charactersInPlay.filter((pokemon) => pokemon[category].includes(value)) } else { alert( - `No, the person doesn't have ${value} eyes! Remove all people that have ${value} eyes.` + `No, the pokemon doesn't have the ${value} type! Remove all pokemon that have the ${value} type.` ) - charactersInPlay = charactersInPlay.filter((person) => person[category] !== value) - } - } else if (category === 'accessories') { - if (keepParam) { - alert( - `Yes, the person wears ${value}! Keep all people that wears ${value}` - ) - charactersInPlay = charactersInPlay.filter((person) => person[category].includes(value)) - } else { - alert( - `No, the person doesn't wear ${value}! Remove all people that wears ${value}` - ) - charactersInPlay = charactersInPlay.filter((person) => !person[category].includes(value)) + charactersInPlay = charactersInPlay.filter((pokemon) => !pokemon[category].includes(value)) } } else { if (keepParam) { alert( - `Yes, the person has a ${value}! Keep all people that have a ${value}.` + `Yes, the pokemon has a ${value}! Keep all pokemon that have a ${value}.` ) - charactersInPlay = charactersInPlay.filter((person) => person[category].includes(value)) + charactersInPlay = charactersInPlay.filter((pokemon) => pokemon[category].includes(value)) } else { alert( - `No, the person doesn't have a ${value}! Remove all people that have a ${value}.` + `No, the pokemon doesn't have a ${value}! Remove all pokemon that have a ${value}.` ) - charactersInPlay = charactersInPlay.filter((person) => !person[category].includes(value)) + charactersInPlay = charactersInPlay.filter((pokemon) => !pokemon[category].includes(value)) } } - // Invoke a function to redraw the board with the remaining people. generateBoard(); } // when clicking guess, the player first have to confirm that they want to make a guess. -const guess = (personToConfirm) => { +const guess = (pokemonToConfirm) => { // store the interaction from the player in a variable. - console.log("guess= ", personToConfirm); + console.log("guess= ", pokemonToConfirm); // remember the confirm() ? - let result = confirm(`Are you sure you want to pick ${personToConfirm}?`); + let result = confirm(`Are you sure you want to pick ${pokemonToConfirm}?`); // If the player wants to guess, invoke the checkMyGuess function. if (result) { - checkMyGuess(personToConfirm); + checkMyGuess(pokemonToConfirm); } } // If you confirm, this function is invoked -const checkMyGuess = (personToCheck) => { +const checkMyGuess = (pokemonToCheck) => { board.style.display = "none"; winOrLose.style.display = "flex"; - if (personToCheck === secretCharacter.name) { - winOrLoseText.innerHTML = `Yay! ${personToCheck} was correct! Congratz!`; + if (pokemonToCheck === secretCharacter.name) { + winOrLoseText.innerHTML = `Yay! ${pokemonToCheck} was correct! Congratz!`; } else { winOrLoseText.innerHTML = `Oh, no! ${secretCharacter.name} was the right answer! Better luck next time!`; } diff --git a/code/style.css b/code/style.css index 1602adfe..383439b4 100644 --- a/code/style.css +++ b/code/style.css @@ -1,7 +1,7 @@ /* Global css variables used for colors */ :root { - --primary: #a259ff; - --secondary: #b0a6ff; + --primary: #e6ae5a; + --secondary: #5a9ca4; } body { @@ -73,7 +73,14 @@ select { justify-content: space-between; } +.pokemonImage { + height: 130px; + width: 130px; + object-fit: contain; +} + .card p { + color: #297383; text-align: center; margin-bottom: 0; font-size: 16px; @@ -145,6 +152,13 @@ button { color: var(--primary); } +#counterDiv { + font-size: 18px; + margin: 24px 0; + width: 100%; + color: white; +} + /****** WIN OR LOSE SECTION ******/ .win-or-lose-wrapper { display: none; @@ -222,7 +236,15 @@ button { .card .guess span { display: none; } - + .pokemonImage { + height: 100px; + width: 100px; + object-fit: contain; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } .card .guess .filled-button { padding: 6px 11px; margin-bottom: 1px; From 576215a3880353c212096a1145f25a52fea42152 Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Sun, 10 Sep 2023 10:21:50 +0200 Subject: [PATCH 13/16] added new images and did some styling of buttons and text changes --- code/images/guess-who-bubble.png | Bin 5745 -> 0 bytes code/images/guess_who_bubble.png | Bin 0 -> 27001 bytes code/images/jabala.svg | 1 - code/images/jack.svg | 95 ------------------ code/images/jacques.svg | 93 ----------------- code/images/jai.svg | 104 ------------------- code/images/jake.svg | 103 ------------------- code/images/james.svg | 95 ------------------ code/images/jana.svg | 1 - code/images/jane.svg | 1 - code/images/jaqueline.svg | 165 ------------------------------- code/images/jazebelle.svg | 1 - code/images/jean.svg | 128 ------------------------ code/images/jeane.svg | 65 ------------ code/images/jed.svg | 110 --------------------- code/images/jenni.svg | 91 ----------------- code/images/jeri.svg | 81 --------------- code/images/jerry.svg | 60 ----------- code/images/jess.svg | 52 ---------- code/images/jia.svg | 52 ---------- code/images/jocelyn.svg | 100 ------------------- code/images/jodi.svg | 101 ------------------- code/images/joe.svg | 70 ------------- code/images/jolee.svg | 79 --------------- code/images/jon.svg | 54 ---------- code/images/jordan.svg | 81 --------------- code/images/josephine.svg | 61 ------------ code/images/josh.svg | 68 ------------- code/images/jude.svg | 61 ------------ code/images/julie.svg | 118 ---------------------- code/index.html | 60 ++++++----- code/script.js | 3 + code/style.css | 32 +++--- 33 files changed, 52 insertions(+), 2134 deletions(-) delete mode 100644 code/images/guess-who-bubble.png create mode 100644 code/images/guess_who_bubble.png delete mode 100644 code/images/jabala.svg delete mode 100644 code/images/jack.svg delete mode 100644 code/images/jacques.svg delete mode 100644 code/images/jai.svg delete mode 100644 code/images/jake.svg delete mode 100644 code/images/james.svg delete mode 100644 code/images/jana.svg delete mode 100644 code/images/jane.svg delete mode 100644 code/images/jaqueline.svg delete mode 100644 code/images/jazebelle.svg delete mode 100644 code/images/jean.svg delete mode 100644 code/images/jeane.svg delete mode 100644 code/images/jed.svg delete mode 100644 code/images/jenni.svg delete mode 100644 code/images/jeri.svg delete mode 100644 code/images/jerry.svg delete mode 100644 code/images/jess.svg delete mode 100644 code/images/jia.svg delete mode 100644 code/images/jocelyn.svg delete mode 100644 code/images/jodi.svg delete mode 100644 code/images/joe.svg delete mode 100644 code/images/jolee.svg delete mode 100644 code/images/jon.svg delete mode 100644 code/images/jordan.svg delete mode 100644 code/images/josephine.svg delete mode 100644 code/images/josh.svg delete mode 100644 code/images/jude.svg delete mode 100644 code/images/julie.svg diff --git a/code/images/guess-who-bubble.png b/code/images/guess-who-bubble.png deleted file mode 100644 index c19ee1d58725d5f820231eca4cafb7d4c1f46ea3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5745 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

lk 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 54 \ No newline at end of file diff --git a/code/images/jack.svg b/code/images/jack.svg deleted file mode 100644 index 68dfb982..00000000 --- a/code/images/jack.svg +++ /dev/null @@ -1,95 +0,0 @@ - - - - -Artboard 9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jacques.svg b/code/images/jacques.svg deleted file mode 100644 index f20284a2..00000000 --- a/code/images/jacques.svg +++ /dev/null @@ -1,93 +0,0 @@ - - - - -3 pipe - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jai.svg b/code/images/jai.svg deleted file mode 100644 index 9c4eaeed..00000000 --- a/code/images/jai.svg +++ /dev/null @@ -1,104 +0,0 @@ - - - - -2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jake.svg b/code/images/jake.svg deleted file mode 100644 index 060d9b9c..00000000 --- a/code/images/jake.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - -Artboard 25 copy 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/james.svg b/code/images/james.svg deleted file mode 100644 index 1a994dd1..00000000 --- a/code/images/james.svg +++ /dev/null @@ -1,95 +0,0 @@ - - - - -Artboard 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jana.svg b/code/images/jana.svg deleted file mode 100644 index 957ef822..00000000 --- a/code/images/jana.svg +++ /dev/null @@ -1 +0,0 @@ -Artboard 1 copy 2 \ No newline at end of file diff --git a/code/images/jane.svg b/code/images/jane.svg deleted file mode 100644 index 41ff91b0..00000000 --- a/code/images/jane.svg +++ /dev/null @@ -1 +0,0 @@ -Artboard 21 \ No newline at end of file diff --git a/code/images/jaqueline.svg b/code/images/jaqueline.svg deleted file mode 100644 index 1ebb90dc..00000000 --- a/code/images/jaqueline.svg +++ /dev/null @@ -1,165 +0,0 @@ - - - - -Artboard 25 copy 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jazebelle.svg b/code/images/jazebelle.svg deleted file mode 100644 index 15e30e0d..00000000 --- a/code/images/jazebelle.svg +++ /dev/null @@ -1 +0,0 @@ -Artboard 25 copy 6 \ No newline at end of file diff --git a/code/images/jean.svg b/code/images/jean.svg deleted file mode 100644 index 8fa89d9f..00000000 --- a/code/images/jean.svg +++ /dev/null @@ -1,128 +0,0 @@ - - - - -Artboard 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jeane.svg b/code/images/jeane.svg deleted file mode 100644 index a07a294e..00000000 --- a/code/images/jeane.svg +++ /dev/null @@ -1,65 +0,0 @@ - - - - -Artboard 25 copy 7 - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jed.svg b/code/images/jed.svg deleted file mode 100644 index 501ee116..00000000 --- a/code/images/jed.svg +++ /dev/null @@ -1,110 +0,0 @@ - - - - -3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jenni.svg b/code/images/jenni.svg deleted file mode 100644 index a6c50108..00000000 --- a/code/images/jenni.svg +++ /dev/null @@ -1,91 +0,0 @@ - - - - -Artboard 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jeri.svg b/code/images/jeri.svg deleted file mode 100644 index ac0c395f..00000000 --- a/code/images/jeri.svg +++ /dev/null @@ -1,81 +0,0 @@ - - - - -Artboard 21 copy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jerry.svg b/code/images/jerry.svg deleted file mode 100644 index f0c8e641..00000000 --- a/code/images/jerry.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - -Artboard 1 copy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jess.svg b/code/images/jess.svg deleted file mode 100644 index f845b976..00000000 --- a/code/images/jess.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - -Artboard 25 copy - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jia.svg b/code/images/jia.svg deleted file mode 100644 index 7e313924..00000000 --- a/code/images/jia.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - -Artboard 10 - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jocelyn.svg b/code/images/jocelyn.svg deleted file mode 100644 index dd08f3ef..00000000 --- a/code/images/jocelyn.svg +++ /dev/null @@ -1,100 +0,0 @@ - - - - -Artboard 21 copy 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jodi.svg b/code/images/jodi.svg deleted file mode 100644 index 864f7be1..00000000 --- a/code/images/jodi.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - - -Artboard 21 copy 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/joe.svg b/code/images/joe.svg deleted file mode 100644 index b2878ffc..00000000 --- a/code/images/joe.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - -Artboard 54 copy - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jolee.svg b/code/images/jolee.svg deleted file mode 100644 index d2048e28..00000000 --- a/code/images/jolee.svg +++ /dev/null @@ -1,79 +0,0 @@ - - - - -Artboard 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jon.svg b/code/images/jon.svg deleted file mode 100644 index 8138984b..00000000 --- a/code/images/jon.svg +++ /dev/null @@ -1,54 +0,0 @@ - - - - -Artboard 25 - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jordan.svg b/code/images/jordan.svg deleted file mode 100644 index 2b7b6bf4..00000000 --- a/code/images/jordan.svg +++ /dev/null @@ -1,81 +0,0 @@ - - - - -Artboard 54 copy 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/josephine.svg b/code/images/josephine.svg deleted file mode 100644 index a0f28f58..00000000 --- a/code/images/josephine.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - -Artboard 25 copy 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/josh.svg b/code/images/josh.svg deleted file mode 100644 index de676a8c..00000000 --- a/code/images/josh.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/images/jude.svg b/code/images/jude.svg deleted file mode 100644 index 64252cb3..00000000 --- a/code/images/jude.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - -Artboard 25 copy 5 - - - - - - - - - - - - - - - - - - - diff --git a/code/images/julie.svg b/code/images/julie.svg deleted file mode 100644 index 253eb566..00000000 --- a/code/images/julie.svg +++ /dev/null @@ -1,118 +0,0 @@ - - - - -Artboard 54 copy 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/index.html b/code/index.html index f6d0a286..f39f4c9c 100644 --- a/code/index.html +++ b/code/index.html @@ -13,46 +13,47 @@

@@ -61,11 +62,6 @@

Who's that Pokémon?

-

diff --git a/code/script.js b/code/script.js index 4c7bea79..6536ed16 100644 --- a/code/script.js +++ b/code/script.js @@ -362,6 +362,9 @@ start() // Counter for number of guesses +/* Explanation + createElement and AppendChild are used when you want to dynamically create and insert new elements into the DOM or when you need to update specific parts of an element's content without replacing its entire content. += innerHTML is used when you want to update the content of an existing HTML element, replacing its content with new HTML. +*/ let counter = 0; let counterDiv = document.createElement("div"); counterDiv.id = "counterDiv"; diff --git a/code/style.css b/code/style.css index 383439b4..e21b3e1e 100644 --- a/code/style.css +++ b/code/style.css @@ -12,7 +12,7 @@ body { } h1 { - font-size: 42px; + font-size: 40px; font-weight: 500; line-height: 48px; margin: 10px 0; @@ -41,7 +41,7 @@ select { } .guess-who-icon { - width: 126px; + width: 180px; } .board-wrapper { @@ -59,13 +59,20 @@ select { align-content: center; } +#counterDiv { + font-size: 18px; + margin: 24px 0; + width: 100%; + color: white; +} + /****** CARD ******/ .card { width: 135px; height: 165px; overflow: hidden; border: 3px solid var(--secondary); - border-radius: 4px; + border-radius: 8px; margin: 3px; display: flex; flex-direction: column; @@ -120,9 +127,16 @@ select { } /****** BUTTONS ******/ + +.buttonWrapper { + width: 100%; + display: flex; + justify-content: space-evenly; +} + button { border: 2px solid var(--primary); - border-radius: 50px; + border-radius: 16px; font-size: 16px; font-family: 'Montserrat'; font-weight: bold; @@ -135,11 +149,13 @@ button { } .outlined-button { + background-color: transparent; color: var(--primary); align-self: flex-end; } + .filled-button, .outlined-button:hover { background-color: var(--primary); @@ -152,12 +168,6 @@ button { color: var(--primary); } -#counterDiv { - font-size: 18px; - margin: 24px 0; - width: 100%; - color: white; -} /****** WIN OR LOSE SECTION ******/ .win-or-lose-wrapper { @@ -209,7 +219,7 @@ button { } .guess-who-icon { - width: 51px; + width: 150px; } .board-wrapper { From 08e6eb18cdeb7a1a1f1bf1b9861eb9e0aaf481bf Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Sun, 10 Sep 2023 11:42:16 +0200 Subject: [PATCH 14/16] removed a lot of comments/explanations to another file --- code/index.html | 4 + code/script.js | 55 +---- code/scriptExplanations.js | 420 +++++++++++++++++++++++++++++++++++++ code/style.css | 12 +- 4 files changed, 442 insertions(+), 49 deletions(-) diff --git a/code/index.html b/code/index.html index f39f4c9c..957ee03b 100644 --- a/code/index.html +++ b/code/index.html @@ -54,6 +54,10 @@

Does the Pokémon have

+ +
+ +
diff --git a/code/script.js b/code/script.js index 6536ed16..7496d502 100644 --- a/code/script.js +++ b/code/script.js @@ -8,6 +8,7 @@ const filterBtn = document.getElementById('filter') const winOrLose = document.getElementById("winOrLose") const winOrLoseText = document.getElementById("winOrLoseText") const playAgainBtn = document.getElementById("playAgain") +const timerAndCounter = document.getElementById("timerAndCounterWrapper") // Array with all the characters, as objects @@ -137,7 +138,7 @@ const POKEMON = [ color: 'yellow', type: ['electric'], other: ['tail'], - }, + }, { name: 'Flareon', img: 'images/Flareon.png', @@ -206,11 +207,6 @@ const generateBoard = () => { } // Randomly select a person from the characters array and set as the value of the variable called secret -/* Explanation for setSecret() - The random character selection is based on the index number calculated using Math.random(). Math.random() generates decimal numbers 0>= x < 1. - Since we have 24 characters and the index starts at 0, by also using the math.floor() method (that rounds down to the closest integer) the highest number that can be calculated is 23, which is the last character in the array[]. - charactersInPlay.length = the number of elements in the array. -*/ const setSecretCharacter = () => { secretCharacter = charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)] } @@ -229,13 +225,6 @@ const start = () => { } // setting the currentQuestion object when you select something in the dropdown -/* EXPLANATION -const category: stores what option group (category) the question belongs to - questions.options[questions.selectedIndex] retrieves the specific element and retrieves the label attribute of that element. - So the whole expression is used to retrieve the label of the element from the option that is currently selected in the drop-down menu -*/ const selectQuestion = () => { const selectedOption = questions.options[questions.selectedIndex]; const category = selectedOption.parentNode.label; @@ -254,28 +243,15 @@ const selectQuestion = () => { // This function should be invoked when you click on 'Find Out' button. const checkQuestion = () => { - /* Explanation: Object destructuring - extract data from an object and assign to new variables. - Another way to do this is: - const category = currentQuestion.category; - const value = currentQuestion.value; - The destructuring makes it easier to extract data - */ const { category, value } = currentQuestion; // Compare the currentQuestion details with the secret person details in a different manner based on category (hair/eyes or accessories/others). // See if we should keep or remove people based on that - - /* Explanations - This is divided like this since the first two categories will have one to one comparisons while the other two categories contain properties with multiple values. - For the hair/eyes category: - We're accessing a CHARACTER object (via the variable secretCharacter) and look through its attributes until we find one that matches the category in the if statement. Once found we take the value (for example "yellow hair") and compare that to the player's choice to see if the match.*/ - let keep = false; //Chose "false" to make the code below easier for me to read (and avoid !) if (category === 'color') { if (value === secretCharacter[category]) { keep = true; } - } else if (category === 'type'|| category === 'other') { + } else if (category === 'type' || category === 'other') { if (secretCharacter[category].includes(value)) { // .includes() since there are multiple values keep = true; } @@ -349,23 +325,18 @@ const checkMyGuess = (pokemonToCheck) => { board.style.display = "none"; winOrLose.style.display = "flex"; - if (pokemonToCheck === secretCharacter.name) { - winOrLoseText.innerHTML = `Yay! ${pokemonToCheck} was correct! Congratz!`; - } else { - winOrLoseText.innerHTML = `Oh, no! ${secretCharacter.name} was the right answer! Better luck next time!`; - } + winOrLoseText.innerHTML = + (pokemonToCheck === secretCharacter.name) + ? `Yay! ${pokemonToCheck} was correct! Congratz!` + : `Oh, no! ${secretCharacter.name} was the right answer! Better luck next time!`; } // Invokes the start function when website is loaded start() - - // Counter for number of guesses -/* Explanation - createElement and AppendChild are used when you want to dynamically create and insert new elements into the DOM or when you need to update specific parts of an element's content without replacing its entire content. += innerHTML is used when you want to update the content of an existing HTML element, replacing its content with new HTML. -*/ let counter = 0; + let counterDiv = document.createElement("div"); counterDiv.id = "counterDiv"; @@ -382,16 +353,6 @@ questionSection.appendChild(counterDiv); // All the event listeners -/* EXPLANATION, event listeners: -there are two different options: -filterBtn.addEventListener('click', checkQuestion); -or -In this one i can pass in an argument to the function: -filterBtn.addEventListener('click', () => checkQuestion()); -if I type: -filterBtn.addEventListener('click', checkQuestion()); -the function will be run immediately without Javascript listening to the event which is not what i want here. -*/ filterBtn.addEventListener('click', () => { counter++; // Increase counter by 1 // Updates the textnode since that text is static and the counter number won't go up without this update diff --git a/code/scriptExplanations.js b/code/scriptExplanations.js index e69de29b..fdd2d8e5 100644 --- a/code/scriptExplanations.js +++ b/code/scriptExplanations.js @@ -0,0 +1,420 @@ +// All the DOM selectors stored as short variables +const board = document.getElementById('board') +const questionSection = document.getElementById('question-section') +const boardWrapper = document.getElementById('board-wrapper') +const questions = document.getElementById('questions') +const restartButton = document.getElementById('restart') +const filterBtn = document.getElementById('filter') +const winOrLose = document.getElementById("winOrLose") +const winOrLoseText = document.getElementById("winOrLoseText") +const playAgainBtn = document.getElementById("playAgain") +const timerAndCounter = document.getElementById("timerAndCounterWrapper") + + +// Array with all the characters, as objects +const POKEMON = [ + { + name: 'Pikachu', + img: 'images/Pikachu.png', + color: 'yellow', + type: ['electric'], + other: ['tail'] + }, + { + name: 'Ninetales', + img: 'images/Ninetales.png', + color: 'yellow', + type: ['fire'], + other: ['tail'] + }, + { + name: 'Beedrill', + img: 'images/Beedrill.png', + color: 'yellow', + type: ['bug', 'poison'], + other: ['stinger'] + }, + { + name: 'Meowth', + img: 'images/Meowth.png', + color: 'yellow', + type: ['normal'], + other: ['tail'] + }, + { + name: 'Ponyta', + img: 'images/Ponyta.png', + color: 'yellow', + type: ['fire'], + other: ['tail', 'flame'] + }, + { + name: 'Jigglypuff', + img: 'images/Jigglypuff.png', + color: 'pink', + type: ['normal', 'fairy'], + other: [] + }, + { + name: 'Mew', + img: 'images/Mew.png', + color: 'pink', + type: ['psychic'], + other: ['tail'] + }, + { + name: 'Clefairy', + img: 'images/Clefairy.png', + color: 'pink', + type: ['fairy'], + other: ['tail'] + }, + { + name: 'Chansey', + img: 'images/Chansey.png', + color: 'pink', + type: ['normal'], + other: ['tail'] + }, + { + name: 'Squirtle', + img: 'images/Squirtle.png', + color: 'blue', + type: ['water'], + other: ['tail'] + }, + { + name: 'Gloom', + img: 'images/Gloom.png', + color: 'blue', + type: ['grass', 'poison'], + other: ['plant'] + }, + { + name: 'Vaporeon', + img: 'images/Vaporeon.png', + color: 'blue', + type: ['water'], + other: ['tail', 'fin'] + }, + { + name: 'Seadra', + img: 'images/Seadra.png', + color: 'blue', + type: ['water'], + other: ['tail', 'fin'] + }, + { + name: 'Lapras', + img: 'images/Lapras.png', + color: 'blue', + type: ['water', 'ice'], + other: ['tail', 'fin'] + }, + { + name: 'Poliwhirl', + img: 'images/Poliwhirl.png', + color: 'blue', + type: ['water'], + other: [] + }, + { + name: 'Charmander', + img: 'images/Charmander.png', + color: 'red', + type: ['fire'], + other: ['tail', 'flame'] + }, + { + name: 'Vileplume', + img: 'images/Vileplume.png', + color: 'blue', + type: ['grass', 'poison'], + other: ['plant'] + }, + { + name: 'Electabuzz', + img: 'images/Electabuzz.png', + color: 'yellow', + type: ['electric'], + other: ['tail'], + }, + { + name: 'Flareon', + img: 'images/Flareon.png', + color: 'red', + type: ['fire'], + other: ['tail'] + }, + { + name: 'Krabby', + img: 'images/Krabby.png', + color: 'red', + type: ['water'], + other: [] + }, + { + name: 'Seaking', + img: 'images/Seaking.png', + color: 'red', + type: ['water'], + other: ['fin'] + }, + { + name: 'Bulbasaur', + img: 'images/Bulbasaur.png', + color: 'green', + type: ['grass', 'poison'], + other: ['plant'] + }, + { + name: 'Caterpie', + img: 'images/Caterpie.png', + color: 'green', + type: ['bug'], + other: ['tail'] + }, + { + name: 'Scyther', + img: 'images/Scyther.png', + color: 'green', + type: ['bug', 'flying'], + other: ['tail'] + }, +]; + +// Global variables +let secretCharacter +let currentQuestion +let charactersInPlay + +// Draw the game board +const generateBoard = () => { + board.innerHTML = '' + charactersInPlay.forEach((pokemon) => { + board.innerHTML += ` +
+

${pokemon.name}

+ ${pokemon.name} +
+ Guess on ${pokemon.name}? + +
+
+ ` + } + ) +} + +// Randomly select a person from the characters array and set as the value of the variable called secret +/* Explanation for setSecret() + The random character selection is based on the index number calculated using Math.random(). Math.random() generates decimal numbers 0>= x < 1. + Since we have 24 characters and the index starts at 0, by also using the math.floor() method (that rounds down to the closest integer) the highest number that can be calculated is 23, which is the last character in the array[]. + charactersInPlay.length = the number of elements in the array. +*/ +const setSecretCharacter = () => { + secretCharacter = charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)] +} + +// This function to start (and restart) the game +const start = () => { + // Here we're setting charactersInPlay array to be all the characters to start with + charactersInPlay = POKEMON + // Invoke/use the function generateBoard to load all the characters on the board. + generateBoard(charactersInPlay); + + //Randomly select a character from the charactersInPlay array and designate it as the "secret" character. + setSecretCharacter(); + console.log("The secret character is:", secretCharacter); + console.log("secret is this data type:", typeof (secretCharacter)); +} + +// setting the currentQuestion object when you select something in the dropdown +/* EXPLANATION +const category: stores what option group (category) the question belongs to + questions.options[questions.selectedIndex] retrieves the specific element and retrieves the label attribute of that element. + So the whole expression is used to retrieve the label of the element from the option that is currently selected in the drop-down menu +*/ +const selectQuestion = () => { + const selectedOption = questions.options[questions.selectedIndex]; + const category = selectedOption.parentNode.label; + + // Variable that stores the actual value of the question that has been selected. + const value = selectedOption.value; + + currentQuestion = { + category: category, + value: value + }; + + console.log("This is the category and value of currentQuestion", currentQuestion); +} + + +// This function should be invoked when you click on 'Find Out' button. +const checkQuestion = () => { + /* Explanation: Object destructuring + extract data from an object and assign to new variables. + Another way to do this is: + const category = currentQuestion.category; + const value = currentQuestion.value; + The destructuring makes it easier to extract data + */ + const { category, value } = currentQuestion; + // Compare the currentQuestion details with the secret person details in a different manner based on category (hair/eyes or accessories/others). + // See if we should keep or remove people based on that + + /* Explanations + This is divided like this since the first two categories will have one to one comparisons while the other two categories contain properties with multiple values. + For the hair/eyes category: + We're accessing a CHARACTER object (via the variable secretCharacter) and look through its attributes until we find one that matches the category in the if statement. Once found we take the value (for example "yellow hair") and compare that to the player's choice to see if the match.*/ + + let keep = false; //Chose "false" to make the code below easier for me to read (and avoid !) + if (category === 'color') { + if (value === secretCharacter[category]) { + keep = true; + } + } else if (category === 'type' || category === 'other') { + if (secretCharacter[category].includes(value)) { // .includes() since there are multiple values + keep = true; + } + } + console.log('keep:', keep); + // Then invoke filterCharacters + filterCharacters(keep); +} + +// It'll filter the characters array and redraw the game board. +const filterCharacters = (keepParam) => { + const { category, value } = currentQuestion + // Show the correct alert message for different categories + console.log(charactersInPlay); + if (category === 'color') { + // since keep parameter is a boolean there's no need to do an equation. + if (keepParam) { + alert( + `Yes, the pokemon is ${value}! Keep all pokemon that are ${value}.` + ) + charactersInPlay = charactersInPlay.filter((pokemon) => pokemon[category] === value) + } else { + alert( + `No, the pokemon isn't ${value}! Remove all pokemon that are ${value}.` + ) + charactersInPlay = charactersInPlay.filter((pokemon) => pokemon[category] !== value) + } + } else if (category === 'type') { + if (keepParam) { + alert( + `Yes, the pokemon has the ${value} type! Keep all pokemon that have the ${value} type.` + ) + charactersInPlay = charactersInPlay.filter((pokemon) => pokemon[category].includes(value)) + } else { + alert( + `No, the pokemon doesn't have the ${value} type! Remove all pokemon that have the ${value} type.` + ) + charactersInPlay = charactersInPlay.filter((pokemon) => !pokemon[category].includes(value)) + } + } else { + if (keepParam) { + alert( + `Yes, the pokemon has a ${value}! Keep all pokemon that have a ${value}.` + ) + charactersInPlay = charactersInPlay.filter((pokemon) => pokemon[category].includes(value)) + } else { + alert( + `No, the pokemon doesn't have a ${value}! Remove all pokemon that have a ${value}.` + ) + charactersInPlay = charactersInPlay.filter((pokemon) => !pokemon[category].includes(value)) + } + } + // Invoke a function to redraw the board with the remaining people. + generateBoard(); +} + +// when clicking guess, the player first have to confirm that they want to make a guess. +const guess = (pokemonToConfirm) => { + // store the interaction from the player in a variable. + console.log("guess= ", pokemonToConfirm); + // remember the confirm() ? + let result = confirm(`Are you sure you want to pick ${pokemonToConfirm}?`); + // If the player wants to guess, invoke the checkMyGuess function. + if (result) { + checkMyGuess(pokemonToConfirm); + } +} + +// If you confirm, this function is invoked +const checkMyGuess = (pokemonToCheck) => { + board.style.display = "none"; + winOrLose.style.display = "flex"; + +/* Old code: + if (pokemonToCheck === secretCharacter.name) { + winOrLoseText.innerHTML = `Yay! ${pokemonToCheck} was correct! Congratz!`; + } else { + winOrLoseText.innerHTML = `Oh, no! ${secretCharacter.name} was the right answer! Better luck next time!`; + } +*/ + winOrLoseText.innerHTML = + (pokemonToCheck === secretCharacter.name) + ? `Yay! ${pokemonToCheck} was correct! Congratz!` + : `Oh, no! ${secretCharacter.name} was the right answer! Better luck next time!`; +} + +// Invokes the start function when website is loaded +start() + +// Counter for number of guesses +/* Explanation + createElement and AppendChild are used when you want to dynamically create and insert new elements into the DOM or when you need to update specific parts of an element's content without replacing its entire content. += innerHTML is used when you want to update the content of an existing HTML element, replacing its content with new HTML. +*/ +let counter = 0; + +/* I tried using createElement and appendchild for the counter and it worked but I'm going to add the element to the html file since it should always be visible and it's an easier solution +let counterDiv = document.createElement("div"); +counterDiv.id = "counterDiv"; + +let numberOfGuessesText = 'Number of guesses: '; +let counterText = document.createTextNode(`${numberOfGuessesText} ${counter}`); +counterText.id = "counterElement"; + +// Append the text node to the div. +// The new node will be last in the list of children. +counterDiv.appendChild(counterText); + +// Append the div to the aside section. +questionSection.appendChild(counterDiv); +*/ + +// All the event listeners +/* EXPLANATION, event listeners: +there are two different options: +filterBtn.addEventListener('click', checkQuestion); +or +In this one i can pass in an argument to the function: +filterBtn.addEventListener('click', () => checkQuestion()); +if I type: +filterBtn.addEventListener('click', checkQuestion()); +the function will be run immediately without Javascript listening to the event which is not what i want here. +*/ +filterBtn.addEventListener('click', () => { + counter++; // Increase counter by 1 + // Updates the textnode since that text is static and the counter number won't go up without this update + counterText.textContent = `${numberOfGuessesText} ${counter}`; + checkQuestion(); +}); +restartButton.addEventListener('click', () => { + location.reload(); + start(); +}) +// Event listener for the dropdown menu +questions.addEventListener('change', selectQuestion); +// Event listener for find out-button +playAgainBtn.addEventListener('click', () => { + winOrLose.style.display = "none"; + board.style.display = "flex"; + location.reload(); + start(); +}) \ No newline at end of file diff --git a/code/style.css b/code/style.css index e21b3e1e..f1ff7087 100644 --- a/code/style.css +++ b/code/style.css @@ -41,7 +41,7 @@ select { } .guess-who-icon { - width: 180px; + width: 200px; } .board-wrapper { @@ -59,10 +59,18 @@ select { align-content: center; } +.timerAndCounterWrapper { + margin-top: 24px; + border-radius: 16px; + padding: 0 27px; + width: 100%; + height: 200px; + border: 3px solid var(--primary); +} + #counterDiv { font-size: 18px; margin: 24px 0; - width: 100%; color: white; } From f992b68bf4312ac5189000b941e6f3f32b9be765 Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Sun, 10 Sep 2023 13:38:19 +0200 Subject: [PATCH 15/16] finished the design --- README.md | 5 ----- code/index.html | 3 --- code/script.js | 45 ++++++++++++++------------------------ code/scriptExplanations.js | 1 - code/style.css | 25 ++++++++++----------- 5 files changed, 28 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index f2ae36b6..60f55e53 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,3 @@ Describe how you approached to problem, and what tools and techniques you used t ## View it live Have you deployed your project somewhere? Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. - - -## Known bugs -Choosing the default option in the drop-down menu crashes the game. -The default option works if you first choose something else and then select it. \ No newline at end of file diff --git a/code/index.html b/code/index.html index 957ee03b..02dc8899 100644 --- a/code/index.html +++ b/code/index.html @@ -55,9 +55,6 @@

Does the Pokémon have

-
- -
diff --git a/code/script.js b/code/script.js index 7496d502..2e27fe7d 100644 --- a/code/script.js +++ b/code/script.js @@ -8,10 +8,9 @@ const filterBtn = document.getElementById('filter') const winOrLose = document.getElementById("winOrLose") const winOrLoseText = document.getElementById("winOrLoseText") const playAgainBtn = document.getElementById("playAgain") -const timerAndCounter = document.getElementById("timerAndCounterWrapper") -// Array with all the characters, as objects +// Array with all the pokemon, as objects const POKEMON = [ { name: 'Pikachu', @@ -206,25 +205,23 @@ const generateBoard = () => { ) } -// Randomly select a person from the characters array and set as the value of the variable called secret +// Randomly select a pokemon from the POKEMON array and set as the value of the variable called secretCharacter const setSecretCharacter = () => { secretCharacter = charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)] } -// This function to start (and restart) the game +// Function to start (and restart) the game const start = () => { - // Here we're setting charactersInPlay array to be all the characters to start with + // Setting the charactersInPlay array to be all the characters to start with charactersInPlay = POKEMON - // Invoke/use the function generateBoard to load all the characters on the board. + // Invoking/using the function generateBoard to load all the characters on the board. generateBoard(charactersInPlay); //Randomly select a character from the charactersInPlay array and designate it as the "secret" character. setSecretCharacter(); - console.log("The secret character is:", secretCharacter); - console.log("secret is this data type:", typeof (secretCharacter)); } -// setting the currentQuestion object when you select something in the dropdown +// Setting the currentQuestion object when something is selected in the dropdown menu const selectQuestion = () => { const selectedOption = questions.options[questions.selectedIndex]; const category = selectedOption.parentNode.label; @@ -236,17 +233,13 @@ const selectQuestion = () => { category: category, value: value }; - - console.log("This is the category and value of currentQuestion", currentQuestion); } - -// This function should be invoked when you click on 'Find Out' button. +// This function is invoked when the find-out button is clicked. const checkQuestion = () => { const { category, value } = currentQuestion; - // Compare the currentQuestion details with the secret person details in a different manner based on category (hair/eyes or accessories/others). - // See if we should keep or remove people based on that - let keep = false; //Chose "false" to make the code below easier for me to read (and avoid !) + // Comparing the currentQuestion details with the secret pokemon details based on category (color, type and other). Based on that the board will be filtered and characters removed/kept. + let keep = false; //Chose "false" to make the code below easier to read (and to avoid !) if (category === 'color') { if (value === secretCharacter[category]) { keep = true; @@ -256,16 +249,14 @@ const checkQuestion = () => { keep = true; } } - console.log('keep:', keep); - // Then invoke filterCharacters + filterCharacters(keep); } -// It'll filter the characters array and redraw the game board. +// Filter the characters array and redraw the game board. const filterCharacters = (keepParam) => { const { category, value } = currentQuestion // Show the correct alert message for different categories - console.log(charactersInPlay); if (category === 'color') { // since keep parameter is a boolean there's no need to do an equation. if (keepParam) { @@ -304,31 +295,27 @@ const filterCharacters = (keepParam) => { charactersInPlay = charactersInPlay.filter((pokemon) => !pokemon[category].includes(value)) } } - // Invoke a function to redraw the board with the remaining people. + // Invoke a function to redraw the board with the remaining pokemon. generateBoard(); } // when clicking guess, the player first have to confirm that they want to make a guess. const guess = (pokemonToConfirm) => { - // store the interaction from the player in a variable. - console.log("guess= ", pokemonToConfirm); - // remember the confirm() ? let result = confirm(`Are you sure you want to pick ${pokemonToConfirm}?`); - // If the player wants to guess, invoke the checkMyGuess function. + // If the player wants to guess, the checkMyGuess function is invoked. if (result) { checkMyGuess(pokemonToConfirm); } } -// If you confirm, this function is invoked const checkMyGuess = (pokemonToCheck) => { board.style.display = "none"; winOrLose.style.display = "flex"; winOrLoseText.innerHTML = - (pokemonToCheck === secretCharacter.name) - ? `Yay! ${pokemonToCheck} was correct! Congratz!` - : `Oh, no! ${secretCharacter.name} was the right answer! Better luck next time!`; + (pokemonToCheck === secretCharacter.name) + ? `Yay! ${pokemonToCheck} was correct! Congratz!` + : `Oh, no! ${secretCharacter.name} was the right answer! Better luck next time!`; } // Invokes the start function when website is loaded diff --git a/code/scriptExplanations.js b/code/scriptExplanations.js index fdd2d8e5..c9af1f35 100644 --- a/code/scriptExplanations.js +++ b/code/scriptExplanations.js @@ -8,7 +8,6 @@ const filterBtn = document.getElementById('filter') const winOrLose = document.getElementById("winOrLose") const winOrLoseText = document.getElementById("winOrLoseText") const playAgainBtn = document.getElementById("playAgain") -const timerAndCounter = document.getElementById("timerAndCounterWrapper") // Array with all the characters, as objects diff --git a/code/style.css b/code/style.css index f1ff7087..6925e71f 100644 --- a/code/style.css +++ b/code/style.css @@ -12,7 +12,7 @@ body { } h1 { - font-size: 40px; + font-size: 30px; font-weight: 500; line-height: 48px; margin: 10px 0; @@ -37,11 +37,11 @@ select { font-family: 'Montserrat'; color: var(--secondary); width: 100%; - margin: 24px 0; + margin-bottom: 48px; } .guess-who-icon { - width: 200px; + width: 300px; } .board-wrapper { @@ -59,18 +59,10 @@ select { align-content: center; } -.timerAndCounterWrapper { - margin-top: 24px; - border-radius: 16px; - padding: 0 27px; - width: 100%; - height: 200px; - border: 3px solid var(--primary); -} #counterDiv { font-size: 18px; - margin: 24px 0; + margin: 48px 0; color: white; } @@ -227,7 +219,7 @@ button { } .guess-who-icon { - width: 150px; + width: 240px; } .board-wrapper { @@ -237,6 +229,7 @@ button { .game-board { width: 100%; max-width: 750px; + justify-content: center; } .card { @@ -250,7 +243,13 @@ button { position: absolute; justify-content: flex-end; } + #counterDiv { + margin: 24px 0; + } + select { + margin-bottom: 24px; + } .card .guess span { display: none; } From 7f5ef2e8f6a118ad06f07ef373aade040c78a1ed Mon Sep 17 00:00:00 2001 From: veronica astrom Date: Sun, 10 Sep 2023 13:56:55 +0200 Subject: [PATCH 16/16] updated the README --- README.md | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 60f55e53..6568ddd1 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,38 @@ -# Project Name -Replace this readme with your own information about your project. +# Pokémon Guess Who -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +This repository contains a web-based game called Pokémon Guess Who, where players try to guess the hidden Pokémon character by asking questions based on characteristics like color, type, and other attributes. -## The problem +## The Problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +The main tools and techniques used in this project include: + +- HTML, CSS, and JavaScript for building the user interface and game logic. +- DOM manipulation to update the game board and display messages. +- Random selection of the secret Pokémon character at the start of the game. +- Filtering of Pokémon characters based on player questions. +- A counter to keep track of the number of guesses made by the player. + +## View It Live + +You can play Pokémon Guess Who live by visiting the following link: [Pokémon Guess Who Game](https://pokemon-guess-who.netlify.app/) + +## Future Improvements + +If more time were available, the following enhancements could be made to the game: + +1. **Difficulty Levels:** Enhance gameplay with multiple difficulty levels. Each level will feature a different number of Pokémon characters on the board, making the game more challenging as players progress. + +2. **Immersive Audio:** Elevate the gaming experience with sound effects for actions like correct guesses, wrong guesses, and question selection. + +3. **Personalized Start Page:** Implement a start screen where players can select a trainer/avatar and add their name. + +4. **Diverse Questions:** Expand the range of question categories and attributes, offering players a broader variety of gameplay. + +5. **Interactive Chatbot:** Improve the user interface by replacing alert messages with an interactive chatbot on the side of the screen. The chatbot will engage players, provide feedback, and display choices and progress in a user-friendly manner. + +6. **Time Challenge:** Add a timer to track how quickly players guess the hidden Pokémon character. The timer creates an element of time pressure and competition, encouraging strategic decision-making. + +7. **High Score System:** Implement a high-score system that records the number of guesses made and the time taken to guess the correct Pokémon character. -## View it live -Have you deployed your project somewhere? Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.