From 6d57cd8d33227a5a86e868d932a9fb66f47a39f6 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Wed, 6 Sep 2023 10:46:01 +0200
Subject: [PATCH 01/16] Clear Step 1
---
code/script.js | 351 +++++++++++++++++++++++++------------------------
1 file changed, 177 insertions(+), 174 deletions(-)
diff --git a/code/script.js b/code/script.js
index 5207730c..00968183 100644
--- a/code/script.js
+++ b/code/script.js
@@ -1,213 +1,214 @@
// All the DOM selectors stored as short variables
-const board = document.getElementById('board')
-const questions = document.getElementById('questions')
-const restartButton = document.getElementById('restart')
+const board = document.getElementById("board");
+const questions = document.getElementById("questions");
+const restartButton = document.getElementById("restart");
+const filterButton = document.getElementById("filter");
// Array with all the characters, as objects
const CHARACTERS = [
{
- name: 'Jabala',
- img: 'images/jabala.svg',
- hair: 'hidden',
- eyes: 'hidden',
- accessories: ['glasses', 'hat'],
- other: []
+ name: "Jabala",
+ img: "images/jabala.svg",
+ hair: "hidden",
+ eyes: "hidden",
+ accessories: ["glasses", "hat"],
+ other: [],
},
{
- name: 'Jack',
- img: 'images/jack.svg',
- hair: 'hidden',
- eyes: 'blue',
- accessories: ['hat'],
- other: []
+ name: "Jack",
+ img: "images/jack.svg",
+ hair: "hidden",
+ eyes: "blue",
+ accessories: ["hat"],
+ other: [],
},
{
- name: 'Jacques',
- img: 'images/jacques.svg',
- hair: 'grey',
- eyes: 'blue',
- accessories: ['hat'],
- other: ['smoker']
+ name: "Jacques",
+ img: "images/jacques.svg",
+ hair: "grey",
+ eyes: "blue",
+ accessories: ["hat"],
+ other: ["smoker"],
},
{
- name: 'Jai',
- img: 'images/jai.svg',
- hair: 'black',
- eyes: 'brown',
+ name: "Jai",
+ img: "images/jai.svg",
+ hair: "black",
+ eyes: "brown",
accessories: [],
- other: []
+ other: [],
},
{
- name: 'Jake',
- img: 'images/jake.svg',
- hair: 'yellow',
- eyes: 'green',
- accessories: ['glasses'],
- other: []
+ name: "Jake",
+ img: "images/jake.svg",
+ hair: "yellow",
+ eyes: "green",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'James',
- img: 'images/james.svg',
- hair: 'brown',
- eyes: 'green',
- accessories: ['glasses'],
- other: []
+ name: "James",
+ img: "images/james.svg",
+ hair: "brown",
+ eyes: "green",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jana',
- img: 'images/jana.svg',
- hair: 'black',
- eyes: 'hidden',
- accessories: ['glasses'],
- other: []
+ name: "Jana",
+ img: "images/jana.svg",
+ hair: "black",
+ eyes: "hidden",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jane',
- img: 'images/jane.svg',
- hair: 'yellow',
- eyes: 'hidden',
- accessories: ['glasses'],
- other: []
+ name: "Jane",
+ img: "images/jane.svg",
+ hair: "yellow",
+ eyes: "hidden",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jaqueline',
- img: 'images/jaqueline.svg',
- hair: 'orange',
- eyes: 'green',
- accessories: ['glasses'],
- other: []
+ name: "Jaqueline",
+ img: "images/jaqueline.svg",
+ hair: "orange",
+ eyes: "green",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jazebelle',
- img: 'images/jazebelle.svg',
- hair: 'purple',
- eyes: 'hidden',
- accessories: ['glasses'],
- other: ['smoker']
+ name: "Jazebelle",
+ img: "images/jazebelle.svg",
+ hair: "purple",
+ eyes: "hidden",
+ accessories: ["glasses"],
+ other: ["smoker"],
},
{
- name: 'Jean',
- img: 'images/jean.svg',
- hair: 'brown',
- eyes: 'blue',
- accessories: ['glasses', 'hat'],
- other: ['smoker']
+ name: "Jean",
+ img: "images/jean.svg",
+ hair: "brown",
+ eyes: "blue",
+ accessories: ["glasses", "hat"],
+ other: ["smoker"],
},
{
- name: 'Jeane',
- img: 'images/jeane.svg',
- hair: 'brown',
- eyes: 'green',
- accessories: ['glasses'],
- other: []
+ name: "Jeane",
+ img: "images/jeane.svg",
+ hair: "brown",
+ eyes: "green",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jed',
- img: 'images/jed.svg',
- hair: 'orange',
- eyes: 'green',
- accessories: ['glasses', 'hat'],
- other: ['smoker']
+ name: "Jed",
+ img: "images/jed.svg",
+ hair: "orange",
+ eyes: "green",
+ accessories: ["glasses", "hat"],
+ other: ["smoker"],
},
{
- name: 'Jenni',
- img: 'images/jenni.svg',
- hair: 'white',
- eyes: 'hidden',
- accessories: ['hat'],
- other: []
+ name: "Jenni",
+ img: "images/jenni.svg",
+ hair: "white",
+ eyes: "hidden",
+ accessories: ["hat"],
+ other: [],
},
{
- name: 'Jeri',
- img: 'images/jeri.svg',
- hair: 'orange',
- eyes: 'green',
- accessories: ['glasses'],
- other: []
+ name: "Jeri",
+ img: "images/jeri.svg",
+ hair: "orange",
+ eyes: "green",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jerry',
- img: 'images/jerry.svg',
- hair: 'hidden',
- eyes: 'blue',
- accessories: ['hat'],
- other: []
+ name: "Jerry",
+ img: "images/jerry.svg",
+ hair: "hidden",
+ eyes: "blue",
+ accessories: ["hat"],
+ other: [],
},
{
- name: 'Jess',
- img: 'images/jess.svg',
- hair: 'black',
- eyes: 'blue',
- accessories: ['glasses'],
- other: []
+ name: "Jess",
+ img: "images/jess.svg",
+ hair: "black",
+ eyes: "blue",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jocelyn',
- img: 'images/jocelyn.svg',
- hair: 'black',
- eyes: 'brown',
- accessories: ['glasses'],
- other: []
+ name: "Jocelyn",
+ img: "images/jocelyn.svg",
+ hair: "black",
+ eyes: "brown",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jon',
- img: 'images/jon.svg',
- hair: 'brown',
- eyes: 'green',
- accessories: ['glasses'],
- other: []
+ name: "Jon",
+ img: "images/jon.svg",
+ hair: "brown",
+ eyes: "green",
+ accessories: ["glasses"],
+ other: [],
},
{
- name: 'Jordan',
- img: 'images/jordan.svg',
- hair: 'yellow',
- eyes: 'hidden',
- accessories: ['glasses', 'hat'],
- other: []
+ name: "Jordan",
+ img: "images/jordan.svg",
+ hair: "yellow",
+ eyes: "hidden",
+ accessories: ["glasses", "hat"],
+ other: [],
},
{
- name: 'Josephine',
- img: 'images/josephine.svg',
- hair: 'grey',
- eyes: 'brown',
+ name: "Josephine",
+ img: "images/josephine.svg",
+ hair: "grey",
+ eyes: "brown",
accessories: [],
- other: []
+ other: [],
},
{
- name: 'Josh',
- img: 'images/josh.svg',
- hair: 'yellow',
- eyes: 'green',
+ name: "Josh",
+ img: "images/josh.svg",
+ hair: "yellow",
+ eyes: "green",
accessories: [],
- other: []
+ other: [],
},
{
- name: 'Jude',
- img: 'images/jude.svg',
- hair: 'black',
- eyes: 'green',
+ name: "Jude",
+ img: "images/jude.svg",
+ hair: "black",
+ eyes: "green",
accessories: [],
- other: []
+ other: [],
},
{
- name: 'Julie',
- img: 'images/julie.svg',
- hair: 'black',
- eyes: 'brown',
- accessories: ['glasses', 'hat'],
- other: []
+ name: "Julie",
+ img: "images/julie.svg",
+ hair: "black",
+ eyes: "brown",
+ accessories: ["glasses", "hat"],
+ other: [],
},
-]
+];
// Global variables
-let secret
-let currentQuestion
-let charactersInPlay
+let secret;
+let currentQuestion;
+let charactersInPlay;
// Draw the game board
const generateBoard = () => {
- board.innerHTML = ''
+ board.innerHTML = "";
charactersInPlay.forEach((person) => {
board.innerHTML += `
@@ -218,25 +219,27 @@ const generateBoard = () => {
Guess
- `
- })
-}
+ `;
+ });
+};
// Randomly select a person from the characters array and set as the value of the variable called secret
const setSecret = () => {
- secret = charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)]
-}
+ secret =
+ 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 = CHARACTERS
+ charactersInPlay = CHARACTERS;
// What else should happen when we start the game?
-}
+ generateBoard();
+};
// setting the currentQuestion object when you select something in the dropdown
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.
@@ -245,38 +248,36 @@ const selectQuestion = () => {
currentQuestion = {
category: category,
// value: value
- }
-}
+ };
+};
// This function should be invoked when you click on 'Find Out' button.
const checkQuestion = () => {
- const { category, value } = currentQuestion
+ 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') {
-
+ if (category === "hair" || category === "eyes") {
+ } else if (category === "accessories" || category === "other") {
}
-}
+};
// It'll filter the characters array and redraw the game board.
const filterCharacters = (keep) => {
- const { category, value } = currentQuestion
+ const { category, value } = currentQuestion;
// Show the correct alert message for different categories
- if (category === 'accessories') {
+ if (category === "accessories") {
if (keep) {
alert(
`Yes, the person wears ${value}! Keep all people that wears ${value}`
- )
+ );
} else {
alert(
`No, the person doesn't wear ${value}! Remove all people that wears ${value}`
- )
+ );
}
- } else if (category === 'other') {
+ } else if (category === "other") {
// Similar to the one above
} else {
if (keep) {
@@ -301,14 +302,14 @@ const filterCharacters = (keep) => {
*/
// Invoke a function to redraw the board with the remaining people.
-}
+};
// 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.
// remember the confirm() ?
// If the player wants to guess, invoke the checkMyGuess function.
-}
+};
// If you confirm, this function is invoked
const checkMyGuess = (personToCheck) => {
@@ -316,10 +317,12 @@ const checkMyGuess = (personToCheck) => {
// 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
-}
+};
// Invokes the start function when website is loaded
-start()
+start();
// All the event listeners
-restartButton.addEventListener('click', start)
+restartButton.addEventListener("click", start);
+questions.addEventListener("change", () => console.log(options.value));
+filterButton.addEventListener("click", filterCharacters);
From 1e6e75fd2eb364764cccc61990ca93a7f8726a3b Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Wed, 6 Sep 2023 10:47:47 +0200
Subject: [PATCH 02/16] Clear Step 2
---
code/script.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/code/script.js b/code/script.js
index 00968183..4b9d3051 100644
--- a/code/script.js
+++ b/code/script.js
@@ -235,6 +235,8 @@ const start = () => {
charactersInPlay = CHARACTERS;
// What else should happen when we start the game?
generateBoard();
+ setSecret();
+ console.log(secret);
};
// setting the currentQuestion object when you select something in the dropdown
From cd26b5d8af9fe93281f59372fedadf65ddc3fea7 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Wed, 6 Sep 2023 11:24:03 +0200
Subject: [PATCH 03/16] Clear Step 3
---
code/script.js | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/code/script.js b/code/script.js
index 4b9d3051..140fccf0 100644
--- a/code/script.js
+++ b/code/script.js
@@ -245,11 +245,11 @@ const selectQuestion = () => {
// 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 =
+ const value = questions.value;
currentQuestion = {
category: category,
- // value: value
+ value: value,
};
};
@@ -257,10 +257,28 @@ const selectQuestion = () => {
const checkQuestion = () => {
const { category, value } = currentQuestion;
+ /*
+ name: "Jack",
+ img: "images/jack.svg",
+ hair: "hidden",
+ eyes: "blue",
+ accessories: ["hat"],
+ othe
+ */
+
// 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") {
+ category === "hair"
+ ? (charactersInPlay = CHARACTERS.filter(
+ (person) => person.hair === value
+ ))
+ : (charactersInPlay = CHARACTERS.filter(
+ (person) => person.eyes === value
+ ));
+ charactersInPlay = CHARACTERS.filter((person) => person.hair === value);
+ generateBoard();
} else if (category === "accessories" || category === "other") {
}
};
@@ -326,5 +344,5 @@ start();
// All the event listeners
restartButton.addEventListener("click", start);
-questions.addEventListener("change", () => console.log(options.value));
-filterButton.addEventListener("click", filterCharacters);
+questions.addEventListener("change", selectQuestion);
+filterButton.addEventListener("click", checkQuestion);
From 995f70f1d33352cbc08c03d26b676c3859b17ae5 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Wed, 6 Sep 2023 12:19:55 +0200
Subject: [PATCH 04/16] add list that progressively filters for each question
---
code/script.js | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/code/script.js b/code/script.js
index 140fccf0..98865f82 100644
--- a/code/script.js
+++ b/code/script.js
@@ -205,6 +205,7 @@ const CHARACTERS = [
let secret;
let currentQuestion;
let charactersInPlay;
+let filteredList;
// Draw the game board
const generateBoard = () => {
@@ -271,15 +272,24 @@ const checkQuestion = () => {
// Then invoke filterCharacters
if (category === "hair" || category === "eyes") {
category === "hair"
- ? (charactersInPlay = CHARACTERS.filter(
+ ? (filteredList = charactersInPlay.filter(
(person) => person.hair === value
))
- : (charactersInPlay = CHARACTERS.filter(
+ : (filteredList = charactersInPlay.filter(
(person) => person.eyes === value
));
- charactersInPlay = CHARACTERS.filter((person) => person.hair === value);
+ charactersInPlay = filteredList;
generateBoard();
} else if (category === "accessories" || category === "other") {
+ category === "accessories"
+ ? (filteredList = charactersInPlay.filter((person) =>
+ person.accessories.includes(value)
+ ))
+ : (filteredList = charactersInPlay.filter((person) =>
+ person.other.includes(value)
+ ));
+ charactersInPlay = filteredList;
+ generateBoard();
}
};
From a8d12417b0fc866f8d48aae6f76927b02a9af4c1 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Wed, 6 Sep 2023 12:27:53 +0200
Subject: [PATCH 05/16] add more options to filter characters by
---
code/index.html | 18 ++++++++++++++++--
code/script.js | 8 ++++----
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/code/index.html b/code/index.html
index 0479b061..6e3a89f3 100644
--- a/code/index.html
+++ b/code/index.html
@@ -12,7 +12,9 @@
- RESTART
+
+ RESTART
+
Does the person have
brown hair
yellow hair
+ grey hair
+ purple hair
+ white hair
+ black hair
+ orange hair
hidden eyes
+ blue eyes
+ green eyes
+ brown eyes
glasses
+ wears a hat
a smoking habit
+ has a beard
@@ -56,7 +68,9 @@ Does the person have
alt="Guess Who"
/>
- PLAY AGAIN
+
+ PLAY AGAIN
+
diff --git a/code/script.js b/code/script.js
index 98865f82..0d6f27ed 100644
--- a/code/script.js
+++ b/code/script.js
@@ -20,7 +20,7 @@ const CHARACTERS = [
hair: "hidden",
eyes: "blue",
accessories: ["hat"],
- other: [],
+ other: ["beard"],
},
{
name: "Jacques",
@@ -28,7 +28,7 @@ const CHARACTERS = [
hair: "grey",
eyes: "blue",
accessories: ["hat"],
- other: ["smoker"],
+ other: ["smoker", "beard"],
},
{
name: "Jai",
@@ -109,7 +109,7 @@ const CHARACTERS = [
hair: "orange",
eyes: "green",
accessories: ["glasses", "hat"],
- other: ["smoker"],
+ other: ["smoker", "beard"],
},
{
name: "Jenni",
@@ -189,7 +189,7 @@ const CHARACTERS = [
hair: "black",
eyes: "green",
accessories: [],
- other: [],
+ other: ["beard"],
},
{
name: "Julie",
From 05e710fbb80ba65c706f4d50c5d43e42e3a6b813 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Wed, 6 Sep 2023 12:31:31 +0200
Subject: [PATCH 06/16] add even more options to filter characters by
---
code/index.html | 1 +
code/script.js | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/code/index.html b/code/index.html
index 6e3a89f3..f6d59dd9 100644
--- a/code/index.html
+++ b/code/index.html
@@ -45,6 +45,7 @@ Does the person have
glasses
wears a hat
+ has a parrot
diff --git a/code/script.js b/code/script.js
index 0d6f27ed..a0ed9b8e 100644
--- a/code/script.js
+++ b/code/script.js
@@ -20,7 +20,7 @@ const CHARACTERS = [
hair: "hidden",
eyes: "blue",
accessories: ["hat"],
- other: ["beard"],
+ other: ["beard", "parrot"],
},
{
name: "Jacques",
From e8d3ad163c7f17ba71f6b7cb006b4daa191f561e Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Sat, 9 Sep 2023 15:51:42 +0200
Subject: [PATCH 07/16] enable winOrLose screen
---
code/index.html | 6 ++++++
code/script.js | 49 ++++++++++++++++++++++++++++++++++++++-----------
code/style.css | 15 +++++++++++----
3 files changed, 55 insertions(+), 15 deletions(-)
diff --git a/code/index.html b/code/index.html
index f6d59dd9..207e24c8 100644
--- a/code/index.html
+++ b/code/index.html
@@ -25,6 +25,7 @@
Does the person have
+ Please choose an option:
brown hair
yellow hair
@@ -69,6 +70,11 @@ Does the person have
alt="Guess Who"
/>
+
PLAY AGAIN
diff --git a/code/script.js b/code/script.js
index a0ed9b8e..553a6f56 100644
--- a/code/script.js
+++ b/code/script.js
@@ -3,6 +3,11 @@ const board = document.getElementById("board");
const questions = document.getElementById("questions");
const restartButton = document.getElementById("restart");
const filterButton = document.getElementById("filter");
+const guessButton = document.querySelector(".filled-button");
+const winOrLoseWrapper = document.querySelector(".win-or-lose-wrapper");
+const winOrLoseText = document.getElementById("winOrLoseText");
+const playAgain = document.getElementById("playAgain");
+const nicelyDone = document.getElementById("nicely-done");
// Array with all the characters, as objects
const CHARACTERS = [
@@ -205,7 +210,6 @@ const CHARACTERS = [
let secret;
let currentQuestion;
let charactersInPlay;
-let filteredList;
// Draw the game board
const generateBoard = () => {
@@ -228,6 +232,7 @@ const generateBoard = () => {
const setSecret = () => {
secret =
charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)];
+ console.log(secret.name);
};
// This function to start (and restart) the game
@@ -257,15 +262,8 @@ const selectQuestion = () => {
// This function should be invoked when you click on 'Find Out' button.
const checkQuestion = () => {
const { category, value } = currentQuestion;
-
- /*
- name: "Jack",
- img: "images/jack.svg",
- hair: "hidden",
- eyes: "blue",
- accessories: ["hat"],
- othe
- */
+ //an array that gets filled with filtered content from charactersInPlay depending on a user's guesses
+ let filteredList;
// 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
@@ -278,6 +276,8 @@ const checkQuestion = () => {
: (filteredList = charactersInPlay.filter(
(person) => person.eyes === value
));
+
+ //in order to initialize the generateBoard function properly, charactersInPlay is changed.
charactersInPlay = filteredList;
generateBoard();
} else if (category === "accessories" || category === "other") {
@@ -339,16 +339,42 @@ const guess = (personToConfirm) => {
// store the interaction from the player in a variable.
// remember the confirm() ?
// If the player wants to guess, invoke the checkMyGuess function.
+ let confirmAnswer = confirm(`Do you think that it is ${secret.name}?`);
+
+ if (confirmAnswer) {
+ 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
+ personToCheck === secret.name
+ ? correctGuess()
+ : (winOrLoseText.innerHTML += `
+ Yea, no. Better luck next time. The correct person was ${secret.name}`);
+ //winOrLose.style.display = "flex";
+ winOrLoseWrapper.style.display = "flex";
+ board.style.display = "none";
// 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
};
+const correctGuess = () => {
+ winOrLoseText.innerHTML += `
+ You are correct!`;
+ nicelyDone.style.display = "flex";
+ winOrLoseWrapper.style.display = "flex";
+ board.style.display = "none";
+};
+
+const resetTheGame = () => {
+ board.style.display = "flex";
+ winOrLoseWrapper.style.display = "none";
+ questions.selectedIndex = 0;
+ start();
+};
+
// Invokes the start function when website is loaded
start();
@@ -356,3 +382,4 @@ start();
restartButton.addEventListener("click", start);
questions.addEventListener("change", selectQuestion);
filterButton.addEventListener("click", checkQuestion);
+playAgain.addEventListener("click", resetTheGame);
diff --git a/code/style.css b/code/style.css
index 1602adfe..86d5b204 100644
--- a/code/style.css
+++ b/code/style.css
@@ -8,7 +8,7 @@ body {
display: flex;
margin: 0;
padding: 0;
- font-family: 'Montserrat', sans-serif;
+ font-family: "Montserrat", sans-serif;
}
h1 {
@@ -34,7 +34,7 @@ select {
display: block;
border: none;
font-size: 22px;
- font-family: 'Montserrat';
+ font-family: "Montserrat";
color: var(--secondary);
width: 100%;
margin: 24px 0;
@@ -117,7 +117,7 @@ button {
border: 2px solid var(--primary);
border-radius: 50px;
font-size: 16px;
- font-family: 'Montserrat';
+ font-family: "Montserrat";
font-weight: bold;
padding: 17px 27px;
cursor: pointer;
@@ -168,7 +168,7 @@ button {
text-align: center;
}
-.win-or-lose img {
+.win-or-lose.guess-who-icon {
align-self: flex-start;
margin-left: 15%;
}
@@ -177,6 +177,13 @@ button {
margin-bottom: 32px;
}
+#nicely-done {
+ width: 400px;
+ height: auto;
+ margin-bottom: 3rem;
+ display: none;
+}
+
@media (max-width: 768px) {
body {
flex-direction: column;
From 3d2efd061abe5773eecdb10e87cf04c2254038f3 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Sat, 9 Sep 2023 15:54:42 +0200
Subject: [PATCH 08/16] clean up checkMyGuess and reset select on restart
---
code/script.js | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/code/script.js b/code/script.js
index 553a6f56..02f6316d 100644
--- a/code/script.js
+++ b/code/script.js
@@ -348,16 +348,7 @@ const guess = (personToConfirm) => {
// If you confirm, this function is invoked
const checkMyGuess = (personToCheck) => {
- personToCheck === secret.name
- ? correctGuess()
- : (winOrLoseText.innerHTML += `
- Yea, no. Better luck next time. The correct person was ${secret.name}`);
- //winOrLose.style.display = "flex";
- winOrLoseWrapper.style.display = "flex";
- board.style.display = "none";
- // 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
+ personToCheck === secret.name ? correctGuess() : wrongGuess();
};
const correctGuess = () => {
@@ -367,6 +358,12 @@ const correctGuess = () => {
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
};
+const wrongGuess = () => {
+ winOrLoseText.innerHTML += `
+ Yea, no. Better luck next time. The correct person was ${secret.name}`;
+ winOrLoseWrapper.style.display = "flex";
+ board.style.display = "none";
+};
const resetTheGame = () => {
board.style.display = "flex";
From 3ca3e57ad5fc8883025117b51a0bf87437d04527 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Sat, 9 Sep 2023 17:26:38 +0200
Subject: [PATCH 09/16] implement filter-function in correct method. still have
to tweak filtering on accessories and other
---
code/index.html | 1 +
code/script.js | 106 ++++++++++++++++++++++++++++++++++++------------
2 files changed, 80 insertions(+), 27 deletions(-)
diff --git a/code/index.html b/code/index.html
index 207e24c8..1310af09 100644
--- a/code/index.html
+++ b/code/index.html
@@ -34,6 +34,7 @@ Does the person have
white hair
black hair
orange hair
+ hidden hair
diff --git a/code/script.js b/code/script.js
index 02f6316d..1c19ba39 100644
--- a/code/script.js
+++ b/code/script.js
@@ -257,64 +257,115 @@ const selectQuestion = () => {
category: category,
value: value,
};
+
+ console.log(secret[category] === value);
+ console.log(currentQuestion);
};
// This function should be invoked when you click on 'Find Out' button.
const checkQuestion = () => {
const { category, value } = currentQuestion;
- //an array that gets filled with filtered content from charactersInPlay depending on a user's guesses
- let filteredList;
// 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") {
- category === "hair"
- ? (filteredList = charactersInPlay.filter(
- (person) => person.hair === value
- ))
- : (filteredList = charactersInPlay.filter(
- (person) => person.eyes === value
- ));
- //in order to initialize the generateBoard function properly, charactersInPlay is changed.
- charactersInPlay = filteredList;
- generateBoard();
- } else if (category === "accessories" || category === "other") {
- category === "accessories"
- ? (filteredList = charactersInPlay.filter((person) =>
- person.accessories.includes(value)
- ))
- : (filteredList = charactersInPlay.filter((person) =>
- person.other.includes(value)
- ));
- charactersInPlay = filteredList;
- generateBoard();
- }
+ // if (category === "hair") {
+ // filterCharacters("hair");
+ // } else if (category === "eyes") {
+
+ // }
+ console.log(category);
+ console.log(value);
+ filterCharacters(category);
+
+ //in order to initialize the generateBoard function properly, charactersInPlay is changed.
+
+ generateBoard();
};
// It'll filter the characters array and redraw the game board.
const filterCharacters = (keep) => {
const { category, value } = currentQuestion;
+ keep = secret[category] === value;
// Show the correct alert message for different categories
if (category === "accessories") {
if (keep) {
alert(
`Yes, the person wears ${value}! Keep all people that wears ${value}`
);
+ charactersInPlay = charactersInPlay.filter((person) =>
+ person.accessories.includes(value)
+ );
+ generateBoard();
} else {
alert(
`No, the person doesn't wear ${value}! Remove all people that wears ${value}`
);
+ charactersInPlay = charactersInPlay.filter(
+ (person) => !person.accessories.includes(value)
+ );
+ generateBoard();
}
} 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}`
+ );
+ charactersInPlay = charactersInPlay.filter((person) =>
+ person.other.includes(value)
+ );
+ generateBoard();
} 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}`
+ );
+ charactersInPlay = charactersInPlay.filter(
+ (person) => !person.other.includes(value)
+ );
+ generateBoard();
}
+ } else if (category === "eyes") {
+ if (keep) {
+ alert(
+ `Yes, the person has a ${value}! Keep all people that have ${value} eyes`
+ );
+ charactersInPlay = charactersInPlay.filter((person) =>
+ person.eyes.includes(value)
+ );
+ generateBoard();
+ } else {
+ alert(
+ `No, the person doesn't have ${value} eyes! Remove all people that have ${value} eyes`
+ );
+ charactersInPlay = charactersInPlay.filter(
+ (person) => !person.eyes.includes(value)
+ );
+ generateBoard();
+ }
+ // alert popup that says something like: "Yes, the person has yellow hair! Keep all people with yellow hair"
+ } else if (category === "hair") {
+ if (keep) {
+ alert(
+ `Yes, the person has ${value} hair! Keep all people that have ${value} hair`
+ );
+ charactersInPlay = charactersInPlay.filter((person) =>
+ person.hair.includes(value)
+ );
+ generateBoard();
+ } else {
+ alert(
+ `No, the person doesn't have ${value} hair! Remove all people that have ${value} hair`
+ );
+ charactersInPlay = charactersInPlay.filter(
+ (person) => !person.hair.includes(value)
+ );
+ generateBoard();
+ }
+ // alert popup that says something like: "Yes, the person has yellow hair! Keep all people with yellow hair"
+ } else {
+ // alert popup that says something like: "No, the person doesnt have yellow hair! Remove all people with yellow hair"
}
// Determine what is the category
@@ -358,6 +409,7 @@ const correctGuess = () => {
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
};
+
const wrongGuess = () => {
winOrLoseText.innerHTML += `
Yea, no. Better luck next time. The correct person was ${secret.name}`;
From 7acc8fdb6f17c70bed14e966be7ff3019f145b10 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Sun, 10 Sep 2023 14:12:35 +0200
Subject: [PATCH 10/16] fix filtering, add scoreboard
---
code/index.html | 20 ++++++++++--
code/script.js | 86 +++++++++++++++++++++++++++++++++++--------------
code/style.css | 22 +++++++++++++
3 files changed, 101 insertions(+), 27 deletions(-)
diff --git a/code/index.html b/code/index.html
index 1310af09..a1de56d6 100644
--- a/code/index.html
+++ b/code/index.html
@@ -46,17 +46,31 @@ Does the person have
glasses
- wears a hat
- has a parrot
+ a hat
a smoking habit
- has a beard
+ a beard
+ a parrot
FIND OUT
+
diff --git a/code/script.js b/code/script.js
index 1c19ba39..864b6ccb 100644
--- a/code/script.js
+++ b/code/script.js
@@ -8,6 +8,9 @@ const winOrLoseWrapper = document.querySelector(".win-or-lose-wrapper");
const winOrLoseText = document.getElementById("winOrLoseText");
const playAgain = document.getElementById("playAgain");
const nicelyDone = document.getElementById("nicely-done");
+const guesses = document.getElementById("guess");
+const win = document.getElementById("win");
+const lose = document.getElementById("lose");
// Array with all the characters, as objects
const CHARACTERS = [
@@ -210,6 +213,9 @@ const CHARACTERS = [
let secret;
let currentQuestion;
let charactersInPlay;
+let totalGuesses = 0;
+let totalWins = 0;
+let totalLosses = 0;
// Draw the game board
const generateBoard = () => {
@@ -243,6 +249,8 @@ const start = () => {
generateBoard();
setSecret();
console.log(secret);
+ totalGuesses = 0;
+ guesses.innerHTML = `${totalGuesses}`;
};
// setting the currentQuestion object when you select something in the dropdown
@@ -264,44 +272,60 @@ const selectQuestion = () => {
// This function should be invoked when you click on 'Find Out' button.
const checkQuestion = () => {
- const { category, value } = currentQuestion;
+ if (questions.selectedIndex === 0) {
+ alert(`You have to select an option`);
+ } else {
+ 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
+ // 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") {
- // filterCharacters("hair");
- // } else if (category === "eyes") {
+ filterCharacters(category);
- // }
- console.log(category);
- console.log(value);
- filterCharacters(category);
+ //in order to initialize the generateBoard function properly, charactersInPlay is changed.
- //in order to initialize the generateBoard function properly, charactersInPlay is changed.
+ generateBoard();
- generateBoard();
+ //Increases the amount of total guesses by 1 and displays it in the DOM
+ totalGuesses++;
+ guesses.innerHTML = `${totalGuesses}`;
+ }
};
// It'll filter the characters array and redraw the game board.
const filterCharacters = (keep) => {
const { category, value } = currentQuestion;
- keep = secret[category] === value;
+
+ if (category === "accessories" || category === "other") {
+ keep = secret[category].includes(value);
+ } else {
+ keep = secret[category] === value;
+ }
// Show the correct alert message for different categories
if (category === "accessories") {
if (keep) {
- alert(
- `Yes, the person wears ${value}! Keep all people that wears ${value}`
- );
+ if (value === "hat") {
+ alert(
+ `Yes, the person has a ${value}! Keep all people with a ${value}`
+ );
+ } else {
+ alert(`Yes, the person wears ${value}! Keep all people with ${value}`);
+ }
charactersInPlay = charactersInPlay.filter((person) =>
person.accessories.includes(value)
);
generateBoard();
} else {
- alert(
- `No, the person doesn't wear ${value}! Remove all people that wears ${value}`
- );
+ if (value === "hat") {
+ alert(
+ `No, the person doesn't have a ${value}! Remove all people with a ${value}`
+ );
+ } else {
+ alert(
+ `No, the person doesn't wear ${value}! Remove all people with ${value}`
+ );
+ }
charactersInPlay = charactersInPlay.filter(
(person) => !person.accessories.includes(value)
);
@@ -310,9 +334,16 @@ const filterCharacters = (keep) => {
} else if (category === "other") {
// Similar to the one above
if (keep) {
- alert(
- `Yes, the person has a ${value}! Keep all people that have a ${value}`
- );
+ if (value === "smoker") {
+ alert(
+ `Yes, the person has a smoking habit! Keep all people that have a smoking habit`
+ );
+ } else {
+ alert(
+ `Yes, the person has a ${value}! Keep all people that have a ${value}`
+ );
+ }
+
charactersInPlay = charactersInPlay.filter((person) =>
person.other.includes(value)
);
@@ -329,11 +360,12 @@ const filterCharacters = (keep) => {
} else if (category === "eyes") {
if (keep) {
alert(
- `Yes, the person has a ${value}! Keep all people that have ${value} eyes`
+ `Yes, the person has ${value} eyes! Keep all people that have ${value} eyes`
);
charactersInPlay = charactersInPlay.filter((person) =>
person.eyes.includes(value)
);
+
generateBoard();
} else {
alert(
@@ -408,6 +440,9 @@ const correctGuess = () => {
nicelyDone.style.display = "flex";
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
+ //Adds 1 to the value of total wins and displays it in the DOM
+ totalWins++;
+ win.innerHTML = `${totalWins}`;
};
const wrongGuess = () => {
@@ -415,6 +450,9 @@ const wrongGuess = () => {
Yea, no. Better luck next time. The correct person was ${secret.name}`;
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
+ //Adds 1 to the value of total losses and displays it in the DOM
+ totalLosses++;
+ lose.innerHTML = `${totalLosses}`;
};
const resetTheGame = () => {
diff --git a/code/style.css b/code/style.css
index 86d5b204..1f1c4436 100644
--- a/code/style.css
+++ b/code/style.css
@@ -184,6 +184,28 @@ button {
display: none;
}
+/****** Scoreboard ******/
+.scoreboard {
+ color: white;
+ width: 100%;
+ margin-top: 4rem;
+ display: flex;
+ flex-direction: column;
+}
+
+#totalGuesses,
+#totalWins,
+#totalLosses {
+ align-self: center;
+}
+
+#guess,
+#win,
+#lose {
+ display: flex;
+ justify-content: center;
+}
+
@media (max-width: 768px) {
body {
flex-direction: column;
From 7768f4444f31b43a41164672af9dd3051e30fe67 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Sun, 10 Sep 2023 14:35:46 +0200
Subject: [PATCH 11/16] add prompt for player name
---
code/index.html | 2 +-
code/script.js | 20 ++++++++++++++++----
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/code/index.html b/code/index.html
index a1de56d6..d4fe5f26 100644
--- a/code/index.html
+++ b/code/index.html
@@ -21,7 +21,7 @@
src="images/guess-who-bubble.png"
alt="Guess Who"
/>
-
+
Does the person have
diff --git a/code/script.js b/code/script.js
index 864b6ccb..297a7b2b 100644
--- a/code/script.js
+++ b/code/script.js
@@ -11,6 +11,7 @@ const nicelyDone = document.getElementById("nicely-done");
const guesses = document.getElementById("guess");
const win = document.getElementById("win");
const lose = document.getElementById("lose");
+const playerName = document.getElementById("playerName");
// Array with all the characters, as objects
const CHARACTERS = [
@@ -216,6 +217,7 @@ let charactersInPlay;
let totalGuesses = 0;
let totalWins = 0;
let totalLosses = 0;
+let namePrompt;
// Draw the game board
const generateBoard = () => {
@@ -436,7 +438,9 @@ const checkMyGuess = (personToCheck) => {
const correctGuess = () => {
winOrLoseText.innerHTML += `
- You are correct!`;
+ Nicely done ${namePrompt}!
+
+ It took you ${totalGuesses} guesses to reach the correct answer.`;
nicelyDone.style.display = "flex";
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
@@ -447,7 +451,7 @@ const correctGuess = () => {
const wrongGuess = () => {
winOrLoseText.innerHTML += `
- Yea, no. Better luck next time. The correct person was ${secret.name}`;
+ Yea, no. Better luck next time, ${namePrompt}. The correct person was ${secret.name}`;
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
//Adds 1 to the value of total losses and displays it in the DOM
@@ -462,8 +466,16 @@ const resetTheGame = () => {
start();
};
-// Invokes the start function when website is loaded
-start();
+//a function that asks the player's name and starts the game.
+//this only asks the players the first time they play and not on every reset
+const startGame = () => {
+ start();
+ namePrompt = prompt("What is your name?");
+ playerName.textContent = `${namePrompt},`;
+};
+
+// Invokes the startGame function when website is loaded
+startGame();
// All the event listeners
restartButton.addEventListener("click", start);
From da097025832238e2c1a7b40458b97bb6f1e924b6 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Sun, 10 Sep 2023 15:11:11 +0200
Subject: [PATCH 12/16] add timer
---
code/index.html | 4 ++++
code/script.js | 54 +++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 50 insertions(+), 8 deletions(-)
diff --git a/code/index.html b/code/index.html
index d4fe5f26..0094515f 100644
--- a/code/index.html
+++ b/code/index.html
@@ -62,6 +62,10 @@ Does the person have
Guesses
0
+
Wins
0
diff --git a/code/script.js b/code/script.js
index 297a7b2b..790f6793 100644
--- a/code/script.js
+++ b/code/script.js
@@ -12,6 +12,7 @@ const guesses = document.getElementById("guess");
const win = document.getElementById("win");
const lose = document.getElementById("lose");
const playerName = document.getElementById("playerName");
+const timer = document.getElementById("timer");
// Array with all the characters, as objects
const CHARACTERS = [
@@ -218,6 +219,9 @@ let totalGuesses = 0;
let totalWins = 0;
let totalLosses = 0;
let namePrompt;
+let minutes = 0;
+let seconds = 0;
+let timerInterval;
// Draw the game board
const generateBoard = () => {
@@ -253,6 +257,7 @@ const start = () => {
console.log(secret);
totalGuesses = 0;
guesses.innerHTML = `${totalGuesses}`;
+ timerStart();
};
// setting the currentQuestion object when you select something in the dropdown
@@ -437,10 +442,17 @@ const checkMyGuess = (personToCheck) => {
};
const correctGuess = () => {
- winOrLoseText.innerHTML += `
- Nicely done ${namePrompt}!
-
- It took you ${totalGuesses} guesses to reach the correct answer.`;
+ if (namePrompt !== ``) {
+ winOrLoseText.innerHTML += `
+ Nicely done ${namePrompt}!
+
+ It took you ${totalGuesses} guesses to reach the correct answer.`;
+ } else {
+ winOrLoseText.innerHTML += `
+ Nicely done!
+
+ It took you ${totalGuesses} guesses to reach the correct answer.`;
+ }
nicelyDone.style.display = "flex";
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
@@ -450,8 +462,13 @@ const correctGuess = () => {
};
const wrongGuess = () => {
- winOrLoseText.innerHTML += `
- Yea, no. Better luck next time, ${namePrompt}. The correct person was ${secret.name}`;
+ if (namePrompt !== ``) {
+ winOrLoseText.innerHTML += `
+ Yea, no. Better luck next time, ${namePrompt}. The correct person was ${secret.name}`;
+ } else {
+ winOrLoseText.innerHTML += `
+ Yea, no. Better luck next time. The correct person was ${secret.name}`;
+ }
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
//Adds 1 to the value of total losses and displays it in the DOM
@@ -466,12 +483,33 @@ const resetTheGame = () => {
start();
};
-//a function that asks the player's name and starts the game.
+const timerStart = () => {
+ if (!timerInterval) {
+ timerInterval = setInterval(updateTimer, 1000);
+ }
+};
+
+const updateTimer = () => {
+ seconds++;
+ if (seconds === 60) {
+ minutes++;
+ seconds = 0;
+ }
+ updateTimerDisplay();
+};
+
+const updateTimerDisplay = () => {
+ timer.textContent = `${minutes}m ${seconds}s`;
+};
+
+//asks the player's name and starts the game.
//this only asks the players the first time they play and not on every reset
const startGame = () => {
start();
namePrompt = prompt("What is your name?");
- playerName.textContent = `${namePrompt},`;
+ if (namePrompt !== "") {
+ playerName.textContent = `${namePrompt},`;
+ }
};
// Invokes the startGame function when website is loaded
From 58b5bac27fd415756f6ab00ae783ccb87250c9e3 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Sun, 10 Sep 2023 16:59:43 +0200
Subject: [PATCH 13/16] add display of timer in winorlose, reset timer on
reset, reset text in winorlose on reset
---
code/script.js | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/code/script.js b/code/script.js
index 790f6793..7fd5c366 100644
--- a/code/script.js
+++ b/code/script.js
@@ -429,10 +429,11 @@ const guess = (personToConfirm) => {
// store the interaction from the player in a variable.
// remember the confirm() ?
// If the player wants to guess, invoke the checkMyGuess function.
- let confirmAnswer = confirm(`Do you think that it is ${secret.name}?`);
+ let confirmAnswer = confirm(`Do you think that it is ${personToConfirm}?`);
if (confirmAnswer) {
checkMyGuess(personToConfirm);
+ timerStart();
}
};
@@ -446,12 +447,14 @@ const correctGuess = () => {
winOrLoseText.innerHTML += `
Nicely done ${namePrompt}!
- It took you ${totalGuesses} guesses to reach the correct answer.`;
+ It took you ${totalGuesses} guesses to reach the correct answer.
+ Time played: ${timePlayed()}`;
} else {
winOrLoseText.innerHTML += `
Nicely done!
- It took you ${totalGuesses} guesses to reach the correct answer.`;
+ It took you ${totalGuesses} guesses to reach the correct answer.
+ Time played: ${timePlayed()}`;
}
nicelyDone.style.display = "flex";
winOrLoseWrapper.style.display = "flex";
@@ -464,10 +467,14 @@ const correctGuess = () => {
const wrongGuess = () => {
if (namePrompt !== ``) {
winOrLoseText.innerHTML += `
- Yea, no. Better luck next time, ${namePrompt}. The correct person was ${secret.name}`;
+ Yea, no. Better luck next time, ${namePrompt}. The correct person was ${
+ secret.name
+ }.
+ Time played: ${timePlayed()}`;
} else {
winOrLoseText.innerHTML += `
- Yea, no. Better luck next time. The correct person was ${secret.name}`;
+ Yea, no. Better luck next time. The correct person was ${secret.name}.
+ Time played: ${timePlayed()}`;
}
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
@@ -479,7 +486,10 @@ const wrongGuess = () => {
const resetTheGame = () => {
board.style.display = "flex";
winOrLoseWrapper.style.display = "none";
+ winOrLoseText.innerHTML = ``;
questions.selectedIndex = 0;
+ seconds = 0;
+ minutes = 0;
start();
};
@@ -502,6 +512,14 @@ const updateTimerDisplay = () => {
timer.textContent = `${minutes}m ${seconds}s`;
};
+const timePlayed = () => {
+ if (minutes < 1) {
+ return `${seconds}s`;
+ } else {
+ return `${minutes}m ${seconds}s`;
+ }
+};
+
//asks the player's name and starts the game.
//this only asks the players the first time they play and not on every reset
const startGame = () => {
From e0af7504840ebf9ee913fe05d2614d4d8d639d68 Mon Sep 17 00:00:00 2001
From: Andrej <72137459+andrkavr@users.noreply.github.com>
Date: Sun, 10 Sep 2023 19:11:12 +0200
Subject: [PATCH 14/16] add sound files, comments and various changes
---
code/index.html | 45 ++++--
code/script.js | 141 +++++++++++-------
code/sounds/announcement-sound-4-21464.mp3 | Bin 0 -> 123715 bytes
code/sounds/fail-144746.mp3 | Bin 0 -> 129567 bytes
code/sounds/fail-jingle-stereo-mix-88784.mp3 | Bin 0 -> 142560 bytes
code/sounds/success-fanfare-trumpets-6185.mp3 | Bin 0 -> 78240 bytes
code/style.css | 20 +--
7 files changed, 125 insertions(+), 81 deletions(-)
create mode 100644 code/sounds/announcement-sound-4-21464.mp3
create mode 100644 code/sounds/fail-144746.mp3
create mode 100644 code/sounds/fail-jingle-stereo-mix-88784.mp3
create mode 100644 code/sounds/success-fanfare-trumpets-6185.mp3
diff --git a/code/index.html b/code/index.html
index 0094515f..4f9dc226 100644
--- a/code/index.html
+++ b/code/index.html
@@ -9,6 +9,19 @@
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
rel="stylesheet"
/>
+
+
+
+
@@ -58,21 +71,25 @@ Does the person have
FIND OUT
-
-
Guesses
-
0
+
-
-
-
diff --git a/code/script.js b/code/script.js
index 7fd5c366..9fbb00b4 100644
--- a/code/script.js
+++ b/code/script.js
@@ -13,6 +13,11 @@ const win = document.getElementById("win");
const lose = document.getElementById("lose");
const playerName = document.getElementById("playerName");
const timer = document.getElementById("timer");
+const questionSection = document.querySelector(".question-section");
+const playCorrect = document.getElementById("soundCorrect");
+const playWrong = document.getElementById("soundFail");
+const playLose = document.getElementById("soundLose");
+const playWin = document.getElementById("soundWin");
// Array with all the characters, as objects
const CHARACTERS = [
@@ -244,54 +249,48 @@ const generateBoard = () => {
const setSecret = () => {
secret =
charactersInPlay[Math.floor(Math.random() * charactersInPlay.length)];
- console.log(secret.name);
+ //console.log(secret.name);
};
-// This function to start (and restart) the game
+// This function to start the game
const start = () => {
// Here we're setting charactersInPlay array to be all the characters to start with
charactersInPlay = CHARACTERS;
- // What else should happen when we start the game?
generateBoard();
+ //The secret person is set
setSecret();
- console.log(secret);
+ //Makes sure that the totalGuess counter is reset if not at 0
totalGuesses = 0;
guesses.innerHTML = `${totalGuesses}`;
+ //Starts the timer for a new round
timerStart();
};
// setting the currentQuestion object when you select something in the dropdown
const selectQuestion = () => {
+ // This variables store what option group (category) the question belongs to and what the value is.
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 = questions.value;
+ //The above variables are then used to modify currentQuestion
currentQuestion = {
category: category,
value: value,
};
-
- console.log(secret[category] === value);
- console.log(currentQuestion);
};
-// This function should be invoked when you click on 'Find Out' button.
+// This function is invoked when you click on 'Find Out' button.
const checkQuestion = () => {
+ //A check to make sure that the player chooses something to filter by
if (questions.selectedIndex === 0) {
alert(`You have to select an option`);
} else {
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
-
+ //the filterCharacters function is called and uses the category to filter the characters
filterCharacters(category);
- //in order to initialize the generateBoard function properly, charactersInPlay is changed.
-
+ //charactersInPlay is changed based on the filtering and then the board gets generated again based on the remaining characters.
generateBoard();
//Increases the amount of total guesses by 1 and displays it in the DOM
@@ -300,18 +299,25 @@ const checkQuestion = () => {
}
};
-// It'll filter the characters array and redraw the game board.
+//Filters the characters array and redraws the game board.
const filterCharacters = (keep) => {
+ //Uses the category and value to check if they correspond with the secret character in some way
const { category, value } = currentQuestion;
+ //If the category is either accessories or other, filtering has to be done differently as they are arrays
+ //If the value of the player's guess matches the secret character, keep is set to true
if (category === "accessories" || category === "other") {
keep = secret[category].includes(value);
} else {
keep = secret[category] === value;
}
- // Show the correct alert message for different categories
+ // Filters by category
if (category === "accessories") {
+ // If keep is true, the characters in the list that contain that value will remain while the others are removed
if (keep) {
+ //playSound(playCorrect);
+ //lets the player know that their guess is correct.
+ //There are two alerts for correct and wrong for better grammar
if (value === "hat") {
alert(
`Yes, the person has a ${value}! Keep all people with a ${value}`
@@ -319,11 +325,17 @@ const filterCharacters = (keep) => {
} else {
alert(`Yes, the person wears ${value}! Keep all people with ${value}`);
}
+ //Modifies charactersInPlay to contain the filtered version and generates the board again
charactersInPlay = charactersInPlay.filter((person) =>
person.accessories.includes(value)
);
+
generateBoard();
} else {
+ //playSound(playWrong);
+ //Lets the player know that their guess is incorrect.
+ //There are two alerts for correct and wrong for better grammar
+
if (value === "hat") {
alert(
`No, the person doesn't have a ${value}! Remove all people with a ${value}`
@@ -333,14 +345,18 @@ const filterCharacters = (keep) => {
`No, the person doesn't wear ${value}! Remove all people with ${value}`
);
}
+ //Removes all the characters with the incorrect value and filters charactersInPlay
charactersInPlay = charactersInPlay.filter(
(person) => !person.accessories.includes(value)
);
+
+ //Generates the board again
generateBoard();
}
} else if (category === "other") {
// Similar to the one above
if (keep) {
+ //playSound(playCorrect);
if (value === "smoker") {
alert(
`Yes, the person has a smoking habit! Keep all people that have a smoking habit`
@@ -356,6 +372,7 @@ const filterCharacters = (keep) => {
);
generateBoard();
} else {
+ //playSound(playWrong);
alert(
`No, the person doesn't have a ${value}! Remove all people that have a ${value}`
);
@@ -365,7 +382,9 @@ const filterCharacters = (keep) => {
generateBoard();
}
} else if (category === "eyes") {
+ //Filters based the eyes value and the generates the board again based on a filtered list of charactersInPlay
if (keep) {
+ //playSound(playCorrect);
alert(
`Yes, the person has ${value} eyes! Keep all people that have ${value} eyes`
);
@@ -375,6 +394,7 @@ const filterCharacters = (keep) => {
generateBoard();
} else {
+ //playSound(playWrong);
alert(
`No, the person doesn't have ${value} eyes! Remove all people that have ${value} eyes`
);
@@ -385,7 +405,10 @@ const filterCharacters = (keep) => {
}
// alert popup that says something like: "Yes, the person has yellow hair! Keep all people with yellow hair"
} else if (category === "hair") {
+ //Filters based the hair value and the generates the board again based on a filtered list of charactersInPlay
+
if (keep) {
+ //playSound(playCorrect);
alert(
`Yes, the person has ${value} hair! Keep all people that have ${value} hair`
);
@@ -394,6 +417,7 @@ const filterCharacters = (keep) => {
);
generateBoard();
} else {
+ //playSound(playWrong);
alert(
`No, the person doesn't have ${value} hair! Remove all people that have ${value} hair`
);
@@ -402,105 +426,112 @@ const filterCharacters = (keep) => {
);
generateBoard();
}
- // alert popup that says something like: "Yes, the person has yellow hair! Keep all people with yellow hair"
- } else {
- // alert popup that says something like: "No, the person doesnt have yellow hair! Remove all people with yellow hair"
}
-
- // 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.
};
-// when clicking guess, the player first have to confirm that they want to make a guess.
+// when clicking guess, the player is asked to confirm their guess of the secret character.
const guess = (personToConfirm) => {
- // store the interaction from the player in a variable.
- // remember the confirm() ?
- // If the player wants to guess, invoke the checkMyGuess function.
+ // Stores the interaction from the player in a confirm() ?
let confirmAnswer = confirm(`Do you think that it is ${personToConfirm}?`);
+ // If the player wants to guess, invokes the checkMyGuess function.
if (confirmAnswer) {
checkMyGuess(personToConfirm);
- timerStart();
}
};
-// If you confirm, this function is invoked
+// If a guess is confirmed, this function is invoked
const checkMyGuess = (personToCheck) => {
+ //Checks if the guessed character has the same name as the secret character
personToCheck === secret.name ? correctGuess() : wrongGuess();
};
+//This is called if the guess is correct
const correctGuess = () => {
- if (namePrompt !== ``) {
+ //Doesn't invoke the name if the namePrompt is empty, null or undefined
+ if (namePrompt !== `` && namePrompt !== undefined && namePrompt !== null) {
+ totalGuesses++;
+ //Plays a victory sound
+ playSound(playWin);
winOrLoseText.innerHTML += `
Nicely done ${namePrompt}!
- It took you ${totalGuesses} guesses to reach the correct answer.
+ It took you ${totalGuesses} guess(es) to reach the correct answer.
Time played: ${timePlayed()}`;
} else {
+ totalGuesses++;
+ playSound(playWin);
winOrLoseText.innerHTML += `
Nicely done!
- It took you ${totalGuesses} guesses to reach the correct answer.
+ It took you ${totalGuesses} guess(es) to reach the correct answer.
Time played: ${timePlayed()}`;
}
+ //Displays the winOrLose-section
nicelyDone.style.display = "flex";
winOrLoseWrapper.style.display = "flex";
+
+ //Hides the board and the questionSection
board.style.display = "none";
+ questionSection.style.display = "none";
//Adds 1 to the value of total wins and displays it in the DOM
+ //This is saved until the user refreshes the window
totalWins++;
win.innerHTML = `${totalWins}`;
};
+//This is called if the guess is incorrect
const wrongGuess = () => {
- if (namePrompt !== ``) {
+ if (namePrompt !== `` && namePrompt !== undefined && namePrompt !== null) {
+ playSound(playLose);
winOrLoseText.innerHTML += `
Yea, no. Better luck next time, ${namePrompt}. The correct person was ${
secret.name
}.
Time played: ${timePlayed()}`;
} else {
+ playSound(playLose);
winOrLoseText.innerHTML += `
Yea, no. Better luck next time. The correct person was ${secret.name}.
Time played: ${timePlayed()}`;
}
winOrLoseWrapper.style.display = "flex";
board.style.display = "none";
+ questionSection.style.display = "none";
//Adds 1 to the value of total losses and displays it in the DOM
totalLosses++;
lose.innerHTML = `${totalLosses}`;
};
+//Resets the game
const resetTheGame = () => {
- board.style.display = "flex";
+ //Clears and hides the winOrLose section
winOrLoseWrapper.style.display = "none";
winOrLoseText.innerHTML = ``;
+ nicelyDone.style.display = "none";
+ //Displays the board and questionSection again
+ board.style.display = "flex";
+ questionSection.style.display = "flex";
+
+ //Resets the timer and the index of the question selector and finally calls the start function
questions.selectedIndex = 0;
seconds = 0;
minutes = 0;
start();
};
+//Starts the timer. Sets the timeInterval if it hasn't already been done
const timerStart = () => {
if (!timerInterval) {
+ //Updates every second
timerInterval = setInterval(updateTimer, 1000);
}
};
const updateTimer = () => {
+ //Increases by one every second
seconds++;
+ //if 60 seconds have passed, increases the minutes and sets seconds to 0 again
if (seconds === 60) {
minutes++;
seconds = 0;
@@ -508,10 +539,12 @@ const updateTimer = () => {
updateTimerDisplay();
};
+//Updates the timer in the DOM
const updateTimerDisplay = () => {
timer.textContent = `${minutes}m ${seconds}s`;
};
+//Provides the info for the winOrLose screen
const timePlayed = () => {
if (minutes < 1) {
return `${seconds}s`;
@@ -520,12 +553,18 @@ const timePlayed = () => {
}
};
-//asks the player's name and starts the game.
+//Plays a sound for the player depending if they are correct, wrong, have lost or have won
+const playSound = (sound) => {
+ sound.play();
+};
+
+//Asks the player's name and starts the game.
//this only asks the players the first time they play and not on every reset
const startGame = () => {
start();
namePrompt = prompt("What is your name?");
- if (namePrompt !== "") {
+ //Will display the player's name on the screen if namePrompt isn't empty, null or undefined
+ if (namePrompt !== `` && namePrompt !== undefined && namePrompt !== null) {
playerName.textContent = `${namePrompt},`;
}
};
diff --git a/code/sounds/announcement-sound-4-21464.mp3 b/code/sounds/announcement-sound-4-21464.mp3
new file mode 100644
index 0000000000000000000000000000000000000000..927f1ca0f8b92d610cd9de0799b510614ccc9f9a
GIT binary patch
literal 123715
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