diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95eadf4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# PyCharm +.idea/ + +# Mac OSX +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5f5b040 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [2022] [Andy Wu] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..43ff390 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Chimpanzee Test + +[Human Benchmark's](https://humanbenchmark.com/tests/chimp) Chimpanzee Test +rebuilt from scratch using jQuery. + +## Installation + +Clone this repository and open the `index.html` file in the resulting folder. + +## Acknowledgements +Favicons generated using +[John Sorrentino's](https://twitter.com/johnsorrentino) [favicon.io](https://favicon.io/favicon-generator/) + +## License +[MIT](https://choosealicense.com/licenses/mit/) \ No newline at end of file diff --git a/assets/favicon-16x16.png b/assets/favicon-16x16.png new file mode 100644 index 0000000..3cee8d2 Binary files /dev/null and b/assets/favicon-16x16.png differ diff --git a/assets/favicon-32x32.png b/assets/favicon-32x32.png new file mode 100644 index 0000000..931875a Binary files /dev/null and b/assets/favicon-32x32.png differ diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000..dcbc6af Binary files /dev/null and b/assets/favicon.ico differ diff --git a/index.html b/index.html new file mode 100755 index 0000000..98cecfd --- /dev/null +++ b/index.html @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + Chimp Test + + + +
+
+

Chimpanzee Test

+

By Andy Wu

+

+ Check out some of my other work on + GitHub +

+
+ +
+
+
+
+
+

Test Your Working Memory

+

Idea taken from + Chimpanzee Test and rebuilt from scratch +

+

Click the squares in order according to their numbers. +
+ The test will get progressively harder. +

+
+
+
+
+ +
+ +
+ +
+

Click the button above to start the test

+
+
+ + diff --git a/scripts/hide_section.js b/scripts/hide_section.js new file mode 100755 index 0000000..8ed66d9 --- /dev/null +++ b/scripts/hide_section.js @@ -0,0 +1,38 @@ + +let listIsHidden = false; +let headIsHidden = false; + +$(document).ready(function() { + let hideHeadButton = $("#hide-head-button"); + let headContainer = $("#header-text"); + + let hideDescButton = $("#hide-description-button"); + let descriptionContainer = $("#description-text"); + + hideHeadButton.click(function() { + if(!headIsHidden) { + headContainer.hide(); + hideHeadButton.html("Show Heading"); + headIsHidden = true; + } + else { + headContainer.show(); + hideHeadButton.html("Hide Heading"); + headIsHidden = false; + } + }); + + hideDescButton.click(function() { + if(!listIsHidden) { + descriptionContainer.hide(); + hideDescButton.html("Show Description"); + listIsHidden = true; + } + else { + descriptionContainer.show(); + hideDescButton.html("Hide Description"); + listIsHidden = false; + } + }); + +}); \ No newline at end of file diff --git a/scripts/mem_test.js b/scripts/mem_test.js new file mode 100755 index 0000000..47adcf5 --- /dev/null +++ b/scripts/mem_test.js @@ -0,0 +1,142 @@ + +const numNodes = 25; // Equal to # of levels +const defaultBoard = []; +for(let i = 1; i <= numNodes; i++) { + defaultBoard.push(i); + } + +let nodeOrder = []; +let currentOrder = 0; +let level = 2; +let gameOver = false; +let firstNodeClicked = false; + +$(document).ready(function() { + let startButton = $("#start-button"); + let startButtonContainer = $("#start-button-container"); + + // Hide "Start" button when pressed + startButtonContainer.on("click", "#start-button", function() { + startButton.hide(); + startGame(); + }); + /* + Handle when a valid node is clicked. Delegate event to gameBoard div since + templated elements don't have event handlers. + */ + $('#game-board').on("click", ".node-t", function() { + let id = $(this).attr("id"); + let node = document.getElementById(id); + let nodeNum = parseInt(node.id); + + /* Check if number clicked in correct order */ + if(nodeNum !== nodeOrder[currentOrder]) { + endGame(level); + startButton.show(); + gameOver = true; + } + /* Clicking final node in level with no errors */ + else if(nodeNum === nodeOrder[nodeOrder.length - 1]) { + level = level + 1; + firstNodeClicked = false; + // End game if max score beat + if(level > numNodes) { + endGame(level); + startButton.show(); + return; + } + playLevel(defaultBoard.slice()) + } + /* Clicked in correct order but not last in level */ + else { + /* Hide all node numbers after the first in a level is clicked */ + if(!firstNodeClicked) { + firstNodeClicked = true; + hideNodeNumbers(nodeOrder); + } + nodeOrder.splice(0, 1); + } + node.className = "node node-f"; + node.innerText = (0).toString(); + }); +}); + +function startGame() { + resetAll(); + let roll = defaultBoard.slice(); + // Template the blank nodes before starting game loop + emptyBoard(defaultBoard); + playLevel(roll); +} + +/* Main game loop */ +function playLevel(nodeNums) { + let rollCopy = nodeNums.slice(); + let nextNodeOrder = generateNextLevel(level, rollCopy); + nodeOrder = nextNodeOrder; + renderLevelBoard(nextNodeOrder); +} + +/* Game helper functions */ +function generateNextLevel(levelNum, nodeNums) { + emptyBoard(defaultBoard); + let nodesToRender = []; + // Randomly determine which nodes will be part of the level + for (let i = 0; i < levelNum; i++) { + let index = Math.floor(Math.random() * nodeNums.length); + nodesToRender.push(nodeNums[index]); + // Remove already added nodes from being rolled again + nodeNums.splice(index, 1); + } + return nodesToRender; +} + +function renderLevelBoard(boardNodes) { + for(let i = 0; i < boardNodes.length; i++) { + let boardNode = document.getElementById(boardNodes[i].toString()); + boardNode.className = "node node-t"; + boardNode.innerText = (i+1).toString(); + } +} + +function emptyBoard(board) { + let templateString = ""; + let gameBoard = document.getElementById("game-board"); + let gameMessage = document.getElementById("game-message"); + + for(let i = 0; i < board.length; i++) { + templateString += ""; + } + gameBoard.innerHTML = templateString; + gameMessage.innerHTML = ""; +} + +function endGame(score) { + let gameBoard = document.getElementById("game-board"); + let gameMessage = document.getElementById("game-message"); + + gameBoard.innerHTML = ""; + if(score > 25) { + gameMessage.innerHTML = + "

You have reached the maximum score of " + (score-1).toString() + "

"; + } + else { + gameMessage.innerHTML = + "

Your score is " + (score-1).toString() + ". Try again to beat your score!

"; + } +} + +function resetAll() { + nodeOrder = []; + currentOrder = 0; + level = 2; + gameOver = false; + firstNodeClicked = false; +} + +function hideNodeNumbers(nodesOnBoard) { + for(let i = 0; i < nodesOnBoard.length; i++) { + let node = document.getElementById(nodesOnBoard[i]); + node.innerHTML = ""; + } +} \ No newline at end of file diff --git a/styles/layout.css b/styles/layout.css new file mode 100755 index 0000000..8ae8e00 --- /dev/null +++ b/styles/layout.css @@ -0,0 +1,25 @@ +@charset "utf-8"; + +#game-board { + justify-content: center; + text-align: center; + display: grid; + grid-template-columns: 80px 80px 80px 80px 80px; + grid-template-rows: 80px 80px 80px 80px 80px; +} + +.node { + height: 80px; + width: 80px; +} + +.node-t { + height: 80px; + width: 80px; + visibility: visible; + font-size: 30pt; +} + +.node-f { + visibility: hidden; +} diff --git a/styles/styles.css b/styles/styles.css new file mode 100755 index 0000000..23d0895 --- /dev/null +++ b/styles/styles.css @@ -0,0 +1,90 @@ +@charset "utf-8"; + +:root { + --page-background-color: #0d1117; + --text-color: #d9d9d9; + --link-color: #67b2e8; + --link-hover-color: #60bec9; + --body-font-size: clamp(11pt, 15pt, 17pt); +} + +html { + padding-bottom: 20px; +} + +h1 { + font-size: 3rem; +} + +h2 { + font-size: 1.75rem; +} + +/* Body */ +body { + /* Dark mode */ + color: var(--text-color); + background-color: var(--page-background-color); +} + +p { + font-size: 1.5rem; +} + +/* Hyperlinks */ +a:link { + color: var(--link-color); + padding: 2px; + text-decoration: none; + display: inline-block; +} + +a:visited { + color: hsla(255, 32%, 58%, 0.79); + border-color: black; + text-decoration: none; +} + +a:hover { + /*text-decoration: underline;*/ + color: var(--link-hover-color); +} + +.section-txt { + text-align: center; +} + +.hide-button { + border-style: outset; + border-color: white; + border-radius: 20px; + background-color: steelblue; + color: white; + min-width: 20px; + min-height: 30px; +} + +#game-board > .node { + background-color: steelblue; + border-color: white; + color: white; +} + +#start-button-container { + text-align: center; +} + +#start-button { + text-align: center; + background-color: chartreuse; + border-color: white; + font-size: 20pt; + color: black; + min-height: 20px; + min-width: 40px; +} + +#game-description { + text-align: center; + font-size: 13pt; +}