From 21dc0450f01b180fa0cdd24601ebd4a0e58fbf24 Mon Sep 17 00:00:00 2001 From: Andy Wu Date: Sun, 31 Jul 2022 21:59:24 -0400 Subject: [PATCH] Release 1.0 --- .gitignore | 5 ++ LICENSE | 21 ++++++ README.md | 15 +++++ assets/favicon-16x16.png | Bin 0 -> 325 bytes assets/favicon-32x32.png | Bin 0 -> 801 bytes assets/favicon.ico | Bin 0 -> 15406 bytes index.html | 61 +++++++++++++++++ scripts/hide_section.js | 38 +++++++++++ scripts/mem_test.js | 142 +++++++++++++++++++++++++++++++++++++++ styles/layout.css | 25 +++++++ styles/styles.css | 90 +++++++++++++++++++++++++ 11 files changed, 397 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 assets/favicon-16x16.png create mode 100644 assets/favicon-32x32.png create mode 100644 assets/favicon.ico create mode 100755 index.html create mode 100755 scripts/hide_section.js create mode 100755 scripts/mem_test.js create mode 100755 styles/layout.css create mode 100755 styles/styles.css 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 0000000000000000000000000000000000000000..3cee8d276bffbd555d1ea713d3b10f462b95cb6a GIT binary patch literal 325 zcmV-L0lNN)P)&52PYUrm8*M~Hi4r3*U{12T z?%k1eDK2)IW?`7`H@h?YlU6*q7SxqsLrR22QY;gF ztqZ4-&*PUSdDomYJ#PDYKAP$poE-!_e;ayl(>xz2_%)Ev;PN=+u0Q3X9ngC%3fem! z_XEvtMR*w-qPpT?sA<*|jhe9G6uQZz5I8^dbExhMM-KD^o<;`c&aF@}N(~=BmTf1N z<&5iGakuIwX(6y^jg6|X8H#(FBNoJ}tnpu8c`qJL$~tk@Fmt4|Zk(Of5_Wb@1l#!o Xq4jQxrsT>R00000NkvXXu0mjf`9O-G literal 0 HcmV?d00001 diff --git a/assets/favicon-32x32.png b/assets/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..931875a262e97e7019c530df5ee1950340084591 GIT binary patch literal 801 zcmV++1K#|JP)F|9LK+JX8*anW~*st$*vWsm1%Vl3rocel8`z_hq4H>F3}|oOp6FSq-6({E*<(K zb|@(OL(rc?5oMv2W@%cfOS-wPuCsq;rr%5@t>9&B(Zde2hhg9Qz0dFSd-L8rhN>#g zzWitf7%Ky?lmT>y?~(!Kc0!UH`VYpPW%j1gQ;f0d@C`Y8WLZXq0^lTogn0pgJjfi) zE>bc-mr{#)1yItC07MK#3@khY%0{5)0KXKvI5`$^81P86g#X_~E5tx~rV+U-^w1MU z{aXRWDF&Q)=2b_m%QK^{T|lpU2H8J6sWuMBHkhy}L5KG)5jVR1xZfWLAx?;5aQS2e z|Ad(aP%>}Z6OEhHiP3}2#8eY^`vT|~5h*B-k7E*2Z9D>`p^FAkETt~y!BKmT+ICXA z7$ZaNRx|cLm_(9=Avv1EE2oJ3WF5Yd!RpOsG<67gG!Rt5rUBB3{(PRu`XgA>alS!1UGN{kli8^eg3_C|f^_NCKpWPyMtu!F7#f@!bFe{!%bEgjt1r}II z=Y=-{%E<2X!60@}ywZmg=o|m7U>YDjmP2Eq6-Bqkv3?1UD@D;LYIUP=yA^#jfTF%2 zS&!T^akJ)XY2)sGK|PsM%j_dcr(N47gMOoG2`j?fSQ?0kkH!WN9j5vT6zLF zl4Zn%AMp5P=%@r&KloHT9V0;uPts$MdA}lk`QQ9M2QOT@LklF3ZET fMPBMJwVnF~5-C8l-%Lq600000NkvXXu0mjfQLtr% literal 0 HcmV?d00001 diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..dcbc6af1760dfa7e77435d19962fbf8541b51e7f GIT binary patch literal 15406 zcmeHOXK++i6n?0`^oRJvah#D&Kt&W4#)54ekWm!TQHr3V(j3JyIy#7o6a~S8$S6gV z4WYNt3=oP)3n9`4LWcyYp(L;DzPJ0f<@lYmWJ3rWlE7ry@$Jl;x9{F_&pqwlJ@MB7N>Nm-LHwZ9n46%>SDF z`(}}U{~WS5k0fi$DDoFfzjuQytWD_KHU@kf3vX+~w`62@l(F7b9}{1`?c>S2 z@&hv04<^s@-nb7UV{te1eMBbcecOJG$)(MFg3R2{$ynG)+Kff7#QMbUlkS#&PtI!< z?U_w0zSlDLlF^s(WG;251mg8ws{Py=tke3Hb&K_T(M_Qijl9pK;%bA7_osNDAw!gF zO43~e)r^#r(7EhVx?OHR&w=Ztnw~O%NNJ$T+=8?~7rZOqC*MC~uh{(7#t{@ax*9pu7|FR*bJ(g0PRH)T6%Gaiw- zLZ$o2yP_`z&+L@kHLMlJiJ8U}Quo7t!-(@<-}Z5^ce>bAop3vB+Lg4aEyeDV&rZ6B z)XY1`nBRen1uuf`C1N^l+5?brmFU5CVOy#bnvmzuKJeYM6fE9|?{CNSJl_x2=AWcL zcxoGYmi2_M=EUgiL)oOyX&ZY!e_Z)@=5H6}P}n>rGI&?KTZNv_4lH;1n5uW={ujx? z^{h6cM^$=fKXYv2#DEh6$rl6Bv!LsAqI`$>Pek99CCGL-1IziF-`C+BS|8`Jb2cyL zGe4idCU=U3cTgKj z(i`;*q!9fVOceb|rDjKPoVo2#pM!qj2o`ET)^*>liM4jV0Y>Uhitu`Jlc>1=bOFPXNxrGDmEU zd<7GM!=wR=T90R)d|Q7Je5EX83;q*4Qvkf^I0cTZq_U8Ytc~A+W;F1iJ%Z7MjeiB3 ziP#2Y8AkS@g+gx^<_J#2dWXHoz_YbrD~#s^j;s>wCv>&|n9TuTWm&}S`uyi967W#q z*c$TfniL=B08Yd-fg>wm6JR00XBaPH{L7DV+Kfjj0{qL&`;r2{nL?#|NrzuJM$8Q( zp!@d}g4~RygtS9sE%ih5Wz}=*m?*GLo;z5)3GLZYj8U*JU|H;IV5(-`0GWreI@X*0@BOPU z*43*~TLL%puKi5rXWX*9X02Sd3-2EGIqb@KWJozyyr~x|9@?L_Mv&^iMv9Kf7TDwa8*~h%+#B5&UGjS7%4{PIa z^1((v)J^hUEEsBydDJAYh}K)i)fchBdwtygD=JG(ovIMgwk%kp6h3vk7I$$vA} + + + + + + + + + + + + + + + + + + + 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; +}