├── docs ├── html.ico ├── js.png ├── logo.png ├── safe.png ├── css-3.png ├── gmail.png ├── html5.png └── step1-1.png ├── exampleSSL.pfx ├── public ├── img │ ├── Emo.png │ ├── bg.png │ ├── Mario.png │ ├── furdu.png │ ├── Georgi.png │ ├── Iliyan.png │ ├── Ivelin.jpg │ ├── Stoyan.png │ ├── Zargan_1.jpg │ ├── bgZargan.png │ ├── bgaboutTeam.png │ ├── britishWinImg.png │ ├── germanLoseImg.png │ ├── germanWinImg.png │ └── britishLoseImg.png ├── js │ ├── background.png │ ├── index.js │ ├── singleplayerClient.js │ ├── multiplayerClient.js │ └── translate.js ├── Rules of the game.pdf ├── css │ └── style.css ├── error404.html ├── index.html ├── contact.html ├── aboutTeam.html ├── rules.html ├── singleplayer.html └── multiplayer.html ├── out ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ └── OpenSans-LightItalic-webfont.woff ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── lang-css.js │ │ ├── Apache-License-2.0.txt │ │ └── prettify.js ├── index.html ├── styles │ ├── prettify-jsdoc.css │ ├── prettify-tomorrow.css │ └── jsdoc-default.css ├── utils_game.js.html ├── public_js_singleplayerClient.js.html ├── public_js_multiplayerClient.js.html ├── public_js_translate.js.html └── app.js.html ├── .editorconfig ├── .github └── ISSUE_TEMPLATE │ ├── task.md │ └── bug_report.md ├── package.json ├── README.md ├── .gitignore ├── utils └── game.js └── app.js /docs/html.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/docs/html.ico -------------------------------------------------------------------------------- /docs/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/docs/js.png -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/docs/logo.png -------------------------------------------------------------------------------- /docs/safe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/docs/safe.png -------------------------------------------------------------------------------- /docs/css-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/docs/css-3.png -------------------------------------------------------------------------------- /docs/gmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/docs/gmail.png -------------------------------------------------------------------------------- /docs/html5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/docs/html5.png -------------------------------------------------------------------------------- /exampleSSL.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/exampleSSL.pfx -------------------------------------------------------------------------------- /docs/step1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/docs/step1-1.png -------------------------------------------------------------------------------- /public/img/Emo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/Emo.png -------------------------------------------------------------------------------- /public/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/bg.png -------------------------------------------------------------------------------- /public/img/Mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/Mario.png -------------------------------------------------------------------------------- /public/img/furdu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/furdu.png -------------------------------------------------------------------------------- /public/img/Georgi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/Georgi.png -------------------------------------------------------------------------------- /public/img/Iliyan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/Iliyan.png -------------------------------------------------------------------------------- /public/img/Ivelin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/Ivelin.jpg -------------------------------------------------------------------------------- /public/img/Stoyan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/Stoyan.png -------------------------------------------------------------------------------- /public/img/Zargan_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/Zargan_1.jpg -------------------------------------------------------------------------------- /public/img/bgZargan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/bgZargan.png -------------------------------------------------------------------------------- /public/js/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/js/background.png -------------------------------------------------------------------------------- /public/Rules of the game.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/Rules of the game.pdf -------------------------------------------------------------------------------- /public/img/bgaboutTeam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/bgaboutTeam.png -------------------------------------------------------------------------------- /public/img/britishWinImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/britishWinImg.png -------------------------------------------------------------------------------- /public/img/germanLoseImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/germanLoseImg.png -------------------------------------------------------------------------------- /public/img/germanWinImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/germanWinImg.png -------------------------------------------------------------------------------- /public/img/britishLoseImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/public/img/britishLoseImg.png -------------------------------------------------------------------------------- /out/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /out/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /out/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IPBachvarov18/CryptoZargan/HEAD/out/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | indent_style = tab 8 | indent_size = 4 9 | -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | height: 100%; 3 | display: none; 4 | background-image: url('../img/bg.png'); 5 | background-size: cover; 6 | } 7 | 8 | nav { 9 | font-size: 24px; 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Task 3 | about: Issue template connected with tasks for the project 4 | title: "[Task Name]" 5 | labels: task 6 | assignees: "" 7 | --- 8 | 9 | ### Description 10 | 11 | A short description of the task. 12 | 13 | ### Due Date 14 | 15 | Due date in format ISO 8601 (yyyy-mm-dd) 16 | 17 | Crypto Zargan Logo 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG TITLE]" 5 | labels: bug 6 | assignees: IDIliev18, snkolev18, eiribarev18 7 | 8 | --- 9 | 10 | ## Bug description ## 11 | Short description of the bug. 12 | ## In which page the bug appears ## 13 | Page title: 14 |
15 | Tab image example 16 | ## Show us the bug ## 17 | Take a photo of the bug and paste it here. 18 | 19 | 20 | 21 |
22 |
23 |
24 | Crypto Zargan Logo 25 | -------------------------------------------------------------------------------- /out/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (() => { 3 | const source = document.getElementsByClassName('prettyprint source linenums'); 4 | let i = 0; 5 | let lineNumber = 0; 6 | let lineId; 7 | let lines; 8 | let totalLines; 9 | let anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = `line${lineNumber}`; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /out/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /public/js/index.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | $("body").css("display", "none"); 3 | $("body").fadeIn(500); 4 | 5 | if (Cookies.get("language") == null) { 6 | Cookies.set("language", "en", { expires: 1 }); 7 | } 8 | 9 | $(".translate-button").on("click", function () { 10 | Cookies.set("language", $(this).data("lng"), { expires: 1 }); 11 | console.log("keks"); 12 | translateLabel(Cookies.get("language")); 13 | }); 14 | 15 | let lang = Cookies.get("language"); 16 | translateLabel(lang); 17 | }); 18 | 19 | $(() => { 20 | $("#singleButton").on("click", () => { 21 | $("#multi").hide(); 22 | $("#single").fadeIn(500); 23 | $("#single").show(); 24 | }); 25 | 26 | $("#multiButton").on("click", () => { 27 | $("#single").hide(); 28 | $("#multi").fadeIn(500); 29 | $("#multi").show(); 30 | }); 31 | 32 | $("#contactSubmit").on("submit", () => { 33 | $("#invalidName").show(); 34 | 35 | }); 36 | }) 37 | 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cryptozargan", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "genDoc": "jsdoc ./app.js ./utils/game.js ./public/js/index.js ./public/js/multiplayerClient.js ./public/js/singleplayerClient.js ./public/js/translate.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/IPBachvarov18/CryptoZargan.git" 13 | }, 14 | "author": "CryptoZargan", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/IPBachvarov18/CryptoZargan/issues" 18 | }, 19 | "homepage": "https://github.com/IPBachvarov18/CryptoZargan#readme", 20 | "dependencies": { 21 | "body-parser": "^1.19.0", 22 | "bootstrap": "^4.5.3", 23 | "clipboard-copy": "^4.0.1", 24 | "dotenv": "^8.2.0", 25 | "ejs": "^3.1.5", 26 | "express": "^4.17.1", 27 | "html": "^1.0.0", 28 | "nodemailer": "^6.4.17", 29 | "path": "^0.12.7", 30 | "request": "^2.88.2", 31 | "socket.io": "^3.0.3", 32 | "uuid": "^8.3.1" 33 | }, 34 | "devDependencies": { 35 | "jsdoc-to-markdown": "^6.0.1", 36 | "nodemon": "^2.0.6" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /public/error404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Crypto Zargan 8 | 9 | 10 | 11 | 13 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | Logo 31 |

32 | Zargans not found 33 |

34 |
35 | 36 |
37 | 40 |
41 | 42 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Phantasma Logo 3 |

4 |

ScaleFocus Project - Team Crypto Zargan

5 | 6 | ## Website 7 | 8 | https://cryptozargan.studio 9 | 10 | --- 11 | 12 | We have implemented the Bletchley game with HTML / CSS / JS. Our project consists of singleplayer module and multiplayer module. The singleplayer includes three difficulties - Easy, Medium and Hard. The multiplayer allows one player to play as the Germans and create the code which the other player has to guess. 13 | 14 | ## Technologies 15 | 16 | - HTML 17 | - CSS 18 | - JavaScript 19 | 20 | ## Features 21 | 22 | - [x] 3 singleplayer difficulties 23 | - [x] Multiplayer mode 24 | - [x] Bulgarian and English localisation 25 | 26 | ## Documentation and presentation 27 | 28 | - [Presentation](https://codingburgas.sharepoint.com/:p:/s/2018-TeamCryptoZargan/Efc3eaGtsNpChyVfUh6oKyQB4Pt3P_-_LlC7auQdkQvotw?e=uMszYZ) 29 | - [Documentation](https://codingburgas.sharepoint.com/:w:/s/2018-TeamCryptoZargan/EQMQyv_Uw71FprXKo335sP4BMzeDGbMo90Jm-DofDUViMw?e=fCGZ47) 30 | - [QA](https://codingburgas-my.sharepoint.com/:f:/g/personal/ipbachvarov18_codingburgas_bg/EvT1oDBiABJLqxDSOYGJQTkBpGVIXyZzqg34RPERicJSNQ?e=mbpwNr) 31 | --- 32 | 33 | ## How to run the project on your machine 34 | 35 | ### Step 1: Clone the repository 36 | 37 | Open your terminal and clone the repository. 38 | 39 | ``` 40 | git clone https://github.com/IPBachvarov18/CryptoZargan.git 41 | cd CryptoZargan 42 | npm install 43 | ``` 44 | 45 | ### Step 2: Rename `.env.example` to `.env` 46 | 47 | ### Step 3: Enter your gmail account 48 | 49 | Step 3 50 | 51 | ### Step 4: Run the project 52 | 53 | ``` 54 | node . 55 | ``` 56 | 57 | ### Step 5: Go to `https:/localhost:8888` 58 | 59 | Step 3 60 | -------------------------------------------------------------------------------- /out/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Home 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Home

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 55 | 56 |
57 | 58 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /out/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | *.env 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | # SSL certificate 108 | certPK.pfx 109 | 110 | fikret/ 111 | -------------------------------------------------------------------------------- /out/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /utils/game.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let gamesInProgress; 4 | 5 | const uuid = require("uuid"); 6 | 7 | /** 8 | * Generates an unique random number. 9 | * 10 | * @param {object} blacklister An array with blacklisted digits. 11 | * @return {number} randNumber An unique random number. 12 | */ 13 | function getTrulyRandomNumber(blacklister = []) { 14 | let randNumber; 15 | 16 | do { 17 | randNumber = Math.floor(Math.random() * 8); 18 | } while (blacklister.indexOf(randNumber) != -1); 19 | 20 | return randNumber; 21 | } 22 | 23 | /** 24 | * Calculates guessed digits. 25 | * 26 | * @param {string} inputDigits The input of the user. 27 | * @param {string} digits The digits of the correct code. 28 | * @return {number} guessed The number of guessed digits. 29 | */ 30 | function calculatesGuessedDigits(inputDigits, digits) { 31 | let guessed = 0; 32 | if (!inputDigits || !digits) { 33 | return {}; 34 | } 35 | 36 | for (let i = 0; i < 4; i++) { 37 | if ( 38 | inputDigits[i] < "0" || 39 | inputDigits[i] > "7" || 40 | digits[i] < "0" || 41 | digits[i] > "7" 42 | ) { 43 | return 0; 44 | } 45 | } 46 | 47 | for (let i = 0; i < digits.length; i++) { 48 | if (inputDigits.indexOf(digits[i]) != -1 && inputDigits[i]!=digits[i]) { 49 | guessed++; 50 | } 51 | } 52 | 53 | return guessed; 54 | } 55 | 56 | /** 57 | * Calculates exact positions. 58 | * 59 | * @param {string} inputDigits The input of the user. 60 | * @param {string} digits The digits of the correct code. 61 | * @return {number} guessedPosition The number of digits on exact positions. 62 | */ 63 | function calculateExactPositions(inputDigits, digits) { 64 | let guessedPosition = 0; 65 | //let allowedNumbers = "/^[0-7]+$/" 66 | for (let i = 0; i < 4; i++) { 67 | if ( 68 | inputDigits[i] < "0" || 69 | inputDigits[i] > "7" || 70 | digits[i] < "0" || 71 | digits[i] > "7" 72 | ) { 73 | return 0; 74 | } 75 | } 76 | 77 | for (let i = 0; i < inputDigits.length; i++) { 78 | if (inputDigits[i] == digits[i]) { 79 | guessedPosition++; 80 | } 81 | } 82 | 83 | return guessedPosition; 84 | } 85 | 86 | /** 87 | * Generates a code for task 1. 88 | * 89 | * @param {number} length The length of the code that has to be generated. 90 | * @return {number} code Returns the code that has been converted as a string. 91 | */ 92 | function generateCode(length) { 93 | let digits = []; 94 | 95 | for (let i = 0; i < length; i++) { 96 | digits.push(getTrulyRandomNumber(digits)); 97 | } 98 | let code = ""; 99 | 100 | for (let i = 0; i < length; i++) { 101 | code += String(digits[i]); 102 | } 103 | 104 | return code; 105 | } 106 | 107 | /** 108 | * Generates a code for task 2. 109 | * 110 | * @param {number} length The length of the code that has to be generated. 111 | * @return {number} code Returns the code that has been converted as a string. 112 | */ 113 | function generateRepetitiveCode(length) { 114 | let digits = []; 115 | 116 | for (let i = 0; i < length; i++) { 117 | digits.push(Math.floor(Math.random() * 8)); 118 | } 119 | 120 | let code = ""; 121 | 122 | for (let i = 0; i < length; i++) { 123 | code += String(digits[i]); 124 | } 125 | 126 | return code; 127 | } 128 | 129 | /** 130 | * Checks if the user's input is valid. 131 | * 132 | * @param {string} input The input of the user. 133 | * @return {boolean} Returns true or false. 134 | */ 135 | function checkInput(input) { 136 | if (input.length != 4) { 137 | return false; 138 | } 139 | 140 | let usedDigits = ""; 141 | 142 | for (let i = 0; i < input.length; i++) { 143 | if (input[i] < "0" || input[i] > "7") { 144 | return false; 145 | } 146 | 147 | if (usedDigits.indexOf(input[i]) != -1) { 148 | return false; 149 | } 150 | 151 | usedDigits += input[i]; 152 | } 153 | 154 | return true; 155 | } 156 | 157 | function checkInputTaskTwo(input) { 158 | if (input.length != 4) { 159 | return false; 160 | } 161 | 162 | for (let i = 0; i < input.length; i++) { 163 | if (input[i] < "0" || input[i] > "7") { 164 | return false; 165 | } 166 | } 167 | 168 | return true; 169 | } 170 | 171 | exports.generateCode = generateCode; 172 | exports.calculateExactPositions = calculateExactPositions; 173 | exports.calculatesGuessedDigits = calculatesGuessedDigits; 174 | exports.generateRepetitiveCode = generateRepetitiveCode; 175 | exports.checkInput = checkInput; 176 | exports.checkInputTaskTwo = checkInputTaskTwo; 177 | -------------------------------------------------------------------------------- /public/js/singleplayerClient.js: -------------------------------------------------------------------------------- 1 | const socket = io(); 2 | 3 | const inputUsername = document.getElementById("inputUsername"); 4 | const guessedDigits = document.getElementById("guessedDigits"); 5 | const levelActions = document.getElementById("levelActions"); 6 | const won = document.getElementById("won"); 7 | const lose = document.getElementById("lose"); 8 | const triesTableBody = document 9 | .getElementById("triesTable") 10 | .getElementsByTagName("tbody")[0]; 11 | const triesTable = document.getElementById("triesTable"); 12 | const difficulty = document.getElementById("difficulty"); 13 | 14 | $(() => { 15 | $("#digit1").on("input", () => { 16 | $("#digit2").focus(); 17 | }); 18 | 19 | $("#digit2").on("input", () => { 20 | $("#digit3").focus(); 21 | }); 22 | 23 | $("#digit3").on("input", () => { 24 | $("#digit4").focus(); 25 | }); 26 | 27 | $("#digit4").on("input", () => { 28 | $("#digit5").focus(); 29 | }); 30 | 31 | $("#digit5").on("input", () => { 32 | $("#submit").focus(); 33 | }); 34 | 35 | setTimeout(() => { 36 | $("#singlePlayerUsername").focus(); 37 | }, 100); 38 | }); 39 | 40 | if (inputUsername) { 41 | inputUsername.addEventListener("submit", function (e) { 42 | e.preventDefault(); 43 | 44 | inputUsername.style.display = "none"; 45 | 46 | difficulty.style.display = "block"; 47 | const username = e.target.elements.username.value; 48 | 49 | $("#easy").on("click", () => { 50 | difficulty.style.display = "none"; 51 | socket.emit("startSingleplayer", username, "easy"); 52 | guessedDigits.style.display = "block"; 53 | triesTable.style.display = "block"; 54 | $("#digit4").hide(); 55 | $("#digit5").hide(); 56 | }); 57 | 58 | $("#medium").on("click", () => { 59 | difficulty.style.display = "none"; 60 | socket.emit("startSingleplayer", username, "medium"); 61 | guessedDigits.style.display = "block"; 62 | $("#digit5").hide(); 63 | triesTable.style.display = "block"; 64 | }); 65 | 66 | $("#hard").on("click", () => { 67 | difficulty.style.display = "none"; 68 | socket.emit("startSingleplayer", username, "hard"); 69 | guessedDigits.style.display = "block"; 70 | triesTable.style.display = "block"; 71 | $("#digit5").show(); 72 | }); 73 | 74 | console.log(username); 75 | $("#digit1").focus(); 76 | }); 77 | } 78 | 79 | if (levelActions) { 80 | levelActions.addEventListener("submit", function (e) { 81 | e.preventDefault(); 82 | 83 | socket.emit("nextLevel"); 84 | 85 | guessedDigits.style.display = "block"; 86 | levelResult.style.display = "none"; 87 | triesTableBody.innerHTML = ""; 88 | }); 89 | } 90 | 91 | let number; 92 | 93 | if (guessedDigits) { 94 | guessedDigits.addEventListener("submit", function (e) { 95 | e.preventDefault(); 96 | 97 | const digit1 = e.target.elements.digit1.value; 98 | const digit2 = e.target.elements.digit2.value; 99 | const digit3 = e.target.elements.digit3.value; 100 | const digit4 = e.target.elements.digit4.value; 101 | const digit5 = e.target.elements.digit5.value; 102 | 103 | number = 104 | String(digit1) + 105 | String(digit2) + 106 | String(digit3) + 107 | String(digit4) + 108 | String(digit5); 109 | 110 | console.log(number); 111 | 112 | socket.emit("crackCodeSinglePlayer", number); 113 | 114 | e.target.elements.digit1.value = ""; 115 | e.target.elements.digit2.value = ""; 116 | e.target.elements.digit3.value = ""; 117 | e.target.elements.digit4.value = ""; 118 | e.target.elements.digit5.value = ""; 119 | 120 | e.target.elements.digit1.focus(); 121 | }); 122 | } 123 | 124 | socket.on("singleplayerMediumAnswer", function (obj) { 125 | console.log(obj); 126 | 127 | if (obj.hasWon) { 128 | if (obj.level == 1) { 129 | guessedDigits.style.display = "none"; 130 | levelResult.style.display = "block"; 131 | } else { 132 | guessedDigits.style.display = "none"; 133 | won.style.display = "block"; 134 | } 135 | } 136 | 137 | if (!obj.hasTries) { 138 | lose.style.display = "block"; 139 | guessedDigits.style.display = "none"; 140 | triesTable.style.display = "none"; 141 | } 142 | 143 | displayTries(obj); 144 | }); 145 | 146 | /** 147 | * Adds rows with information about the guessed digits and exact positions to the table. 148 | * 149 | * @param {object} obj An object with information about the game. 150 | */ 151 | function displayTries(obj) { 152 | let newRow = triesTableBody.insertRow(); 153 | let cell1 = newRow.insertCell(0); 154 | let cell2 = newRow.insertCell(1); 155 | let cell3 = newRow.insertCell(2); 156 | 157 | cell1.innerHTML = obj.guessedDigits; 158 | cell2.innerHTML = obj.guessedPosition; 159 | cell3.innerHTML = number; 160 | } 161 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Crypto Zargan 7 | 8 | 9 | 10 | 11 | 12 | 18 | 23 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 142 | 143 |
144 |
145 |

146 | Welcome to Bletchley Game 147 |

148 |
149 |
150 | By Team Crypto Zargan 151 |
152 |
153 |
154 | 155 |
156 | 164 | 172 |
173 | 174 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /out/utils_game.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: utils/game.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: utils/game.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
"use strict";
 30 | 
 31 | let gamesInProgress;
 32 | 
 33 | const uuid = require("uuid");
 34 | 
 35 | /**
 36 |  * Generates an unique random number.
 37 |  *
 38 |  * @param {object} blacklister An array with blacklisted digits.
 39 |  * @return {number} randNumber An unique random number.
 40 |  */
 41 | function getTrulyRandomNumber(blacklister = []) {
 42 | 	let randNumber;
 43 | 
 44 | 	do {
 45 | 		randNumber = Math.floor(Math.random() * 8);
 46 | 	} while (blacklister.indexOf(randNumber) != -1);
 47 | 
 48 | 	return randNumber;
 49 | }
 50 | 
 51 | /**
 52 |  * Calculates guessed digits.
 53 |  *
 54 |  * @param {string} inputDigits The input of the user.
 55 |  * @param {string} digits The digits of the correct code.
 56 |  * @return {number} guessed The number of guessed digits.
 57 |  */
 58 | function calculatesGuessedDigits(inputDigits, digits) {
 59 | 	let guessed = 0;
 60 | 	if (!inputDigits || !digits) {
 61 | 		return {};
 62 | 	}
 63 | 
 64 | 	for (let i = 0; i < 4; i++) {
 65 | 		if (
 66 | 			inputDigits[i] < "0" ||
 67 | 			inputDigits[i] > "7" ||
 68 | 			digits[i] < "0" ||
 69 | 			digits[i] > "7"
 70 | 		) {
 71 | 			return 0;
 72 | 		}
 73 | 	}
 74 | 
 75 | 	for (let i = 0; i < inputDigits.length; i++) {
 76 | 		if (digits.indexOf(inputDigits[i]) != -1) {
 77 | 			guessed++;
 78 | 		}
 79 | 	}
 80 | 
 81 | 	return guessed;
 82 | }
 83 | 
 84 | /**
 85 |  * Calculates exact positions.
 86 |  *
 87 |  * @param {string} inputDigits The input of the user.
 88 |  * @param {string} digits The digits of the correct code.
 89 |  * @return {number} guessedPosition The number of digits on exact positions.
 90 |  */
 91 | function calculateExactPositions(inputDigits, digits) {
 92 | 	let guessedPosition = 0;
 93 | 	//let allowedNumbers = "/^[0-7]+$/"
 94 | 	for (let i = 0; i < 4; i++) {
 95 | 		if (
 96 | 			inputDigits[i] < "0" ||
 97 | 			inputDigits[i] > "7" ||
 98 | 			digits[i] < "0" ||
 99 | 			digits[i] > "7"
100 | 		) {
101 | 			return 0;
102 | 		}
103 | 	}
104 | 
105 | 	for (let i = 0; i < inputDigits.length; i++) {
106 | 		if (inputDigits[i] == digits[i]) {
107 | 			guessedPosition++;
108 | 		}
109 | 	}
110 | 
111 | 	return guessedPosition;
112 | }
113 | 
114 | /**
115 |  * Generates a code for task 1.
116 |  *
117 |  * @param {number} length The length of the code that has to be generated.
118 |  * @return {number} code Returns the code that has been converted as a string.
119 |  */
120 | function generateCode(length) {
121 | 	let digits = [];
122 | 
123 | 	for (let i = 0; i < length; i++) {
124 | 		digits.push(getTrulyRandomNumber(digits));
125 | 	}
126 | 	let code = "";
127 | 
128 | 	for (let i = 0; i < length; i++) {
129 | 		code += String(digits[i]);
130 | 	}
131 | 
132 | 	return code;
133 | }
134 | 
135 | /**
136 |  * Generates a code for task 2.
137 |  *
138 |  * @param {number} length The length of the code that has to be generated.
139 |  * @return {number} code Returns the code that has been converted as a string.
140 |  */
141 | function generateRepetitiveCode(length) {
142 | 	let digits = [];
143 | 
144 | 	for (let i = 0; i < length; i++) {
145 | 		digits.push(Math.floor(Math.random() * 8));
146 | 	}
147 | 
148 | 	let code = "";
149 | 
150 | 	for (let i = 0; i < length; i++) {
151 | 		code += String(digits[i]);
152 | 	}
153 | 
154 | 	return code;
155 | }
156 | 
157 | /**
158 |  * Checks if the user's input is valid.
159 |  *
160 |  * @param {string} input The input of the user.
161 |  * @return {boolean} Returns true or false.
162 |  */
163 | function checkInput(input) {
164 | 	if (input.length != 4) {
165 | 		return false;
166 | 	}
167 | 
168 | 	let usedDigits = "";
169 | 
170 | 	for (let i = 0; i < input.length; i++) {
171 | 		if (input[i] < "0" || input[i] > "7") {
172 | 			return false;
173 | 		}
174 | 
175 | 		if (usedDigits.indexOf(input[i]) != -1) {
176 | 			return false;
177 | 		}
178 | 
179 | 		usedDigits += input[i];
180 | 	}
181 | 
182 | 	return true;
183 | }
184 | 
185 | function checkInputTaskTwo(input) {
186 | 	if (input.length != 4) {
187 | 		return false;
188 | 	}
189 | 
190 | 	for (let i = 0; i < input.length; i++) {
191 | 		if (input[i] < "0" || input[i] > "7") {
192 | 			return false;
193 | 		}
194 | 	}
195 | 
196 | 	return true;
197 | }
198 | 
199 | exports.generateCode = generateCode;
200 | exports.calculateExactPositions = calculateExactPositions;
201 | exports.calculatesGuessedDigits = calculatesGuessedDigits;
202 | exports.generateRepetitiveCode = generateRepetitiveCode;
203 | exports.checkInput = checkInput;
204 | exports.checkInputTaskTwo = checkInputTaskTwo;
205 | 
206 |
207 |
208 | 209 | 210 | 211 | 212 |
213 | 214 | 217 | 218 |
219 | 220 | 223 | 224 | 225 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /public/contact.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | About Us 7 | 8 | 9 | 10 | 16 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 143 | 144 |
145 |
149 |

150 | This is contact 151 |

152 | 153 |
154 |
160 | 166 |
167 | 168 | 169 | 177 | 178 |
179 |
180 | 181 |
182 | 183 | 184 | 192 | 193 |
194 |
195 | 196 |
197 | 198 | 199 | 207 | 208 |
209 |
210 | 211 |
212 | 213 | 214 | 222 | 223 |
224 | 225 |
226 | 227 |
221 |
222 |
223 |
224 | © 2021 Copyright: 225 | Crypto Zargan 230 |
231 |
232 |
233 | 234 | 235 | -------------------------------------------------------------------------------- /public/rules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | About Us 8 | 9 | 10 | 11 | 13 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 79 | 80 | 81 | 82 |
83 | 86 | 90 |
91 | 92 | 93 | 94 | 126 |
127 | 128 | 164 |
165 | 166 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /public/js/multiplayerClient.js: -------------------------------------------------------------------------------- 1 | const socket = io(); 2 | 3 | const createGameForm = document.getElementById("createGameForm"); 4 | const createJoin = document.getElementById("createOrJoin"); 5 | const createButton = document.getElementById("create"); 6 | const joinButton = document.getElementById("join"); 7 | const joinGameForm = document.getElementById("joinGameForm"); 8 | const waitingForPlayer = document.getElementById("waitingForPlayer"); 9 | const guessedDigits = document.getElementById("guessedDigits"); 10 | const triesTableBody = document 11 | .getElementById("triesTable") 12 | .getElementsByTagName("tbody")[0]; 13 | const triesTable = document.getElementById("triesTable"); 14 | const levelActions = document.getElementById("levelActions"); 15 | 16 | $(() => { 17 | $("#digit1").on("input", () => { 18 | $("#digit2").focus(); 19 | }); 20 | 21 | $("#digit2").on("input", () => { 22 | $("#digit3").focus(); 23 | }); 24 | 25 | $("#digit3").on("input", () => { 26 | $("#digit4").focus(); 27 | }); 28 | 29 | $("#digit4").on("input", () => { 30 | $("#gsSubmit").focus(); 31 | }); 32 | 33 | $("#create1").on("input", () => { 34 | $("#create2").focus(); 35 | }); 36 | 37 | $("#create2").on("input", () => { 38 | $("#create3").focus(); 39 | }); 40 | 41 | $("#create3").on("input", () => { 42 | $("#create4").focus(); 43 | }); 44 | 45 | $("#create4").on("input", () => { 46 | $("#crSubmit").focus(); 47 | }); 48 | }); 49 | 50 | if (joinGameForm) { 51 | joinGameForm.addEventListener("submit", function (e) { 52 | e.preventDefault(); 53 | 54 | const nickname = e.target.nickname.value; 55 | const roomId = e.target.gameId.value; 56 | const waitingForStart = document.getElementById("waitForStart"); 57 | socket.emit("playerTwoJoin", nickname, roomId); 58 | 59 | joinGameForm.style.display = "none"; 60 | waitingForStart.style.display = "block"; 61 | $("#errorMessage").hide(); 62 | }); 63 | } 64 | 65 | const startButton = document.getElementById("startButton"); 66 | 67 | socket.on("playerJoined", function (message, obj) { 68 | const startGame = document.getElementById("startGame"); 69 | const joinMessage = document.getElementById("joinMessage"); 70 | 71 | waitingForPlayer.style.display = "none"; 72 | startGame.style.display = "block"; 73 | 74 | joinMessage.innerText = message; 75 | }); 76 | 77 | if (startButton) { 78 | startButton.addEventListener("click", function (e) { 79 | e.preventDefault(); 80 | socket.emit("startGame"); 81 | }); 82 | } 83 | 84 | if (createGameForm) { 85 | createGameForm.addEventListener("submit", function (e) { 86 | e.preventDefault(); 87 | 88 | const nickname = e.target.nickname.value; 89 | const role = e.target.role.value; 90 | 91 | console.log(nickname, role); 92 | 93 | socket.emit("playerOneJoin", nickname, role); 94 | createGameForm.style.display = "none"; 95 | }); 96 | } 97 | 98 | socket.on("generateId", function (code) { 99 | waitingForPlayer.style.display = "block"; 100 | roomId.innerText = code; 101 | $("#errorMessage").hide(); 102 | }); 103 | 104 | $("#codeInitialSetup").on("submit", function (e) { 105 | e.preventDefault(); 106 | 107 | let digit1 = e.target.create1.value; 108 | let digit2 = e.target.create2.value; 109 | let digit3 = e.target.create3.value; 110 | let digit4 = e.target.create4.value; 111 | 112 | let code = 113 | String(digit1) + String(digit2) + String(digit3) + String(digit4); 114 | 115 | socket.emit("setupCode", code); 116 | 117 | clearInitialSetupDigits(e); 118 | $("#errorMessage").hide(); 119 | }); 120 | 121 | $("#guessedDigits").on("submit", function (e) { 122 | e.preventDefault(); 123 | 124 | let digit1 = e.target.digit1.value; 125 | let digit2 = e.target.digit2.value; 126 | let digit3 = e.target.digit3.value; 127 | let digit4 = e.target.digit4.value; 128 | 129 | let britishCode = 130 | String(digit1) + String(digit2) + String(digit3) + String(digit4); 131 | 132 | socket.emit("inputCode", britishCode); 133 | 134 | clearGuessedDigits(e); 135 | $("#errorMessage").hide(); 136 | }); 137 | 138 | socket.on("gameStatusBritish", function () { 139 | console.log("GameStatusBritish"); 140 | $("#startGame").hide(); 141 | $("#waitForStart").hide(); 142 | $("#waitForCode").show(); 143 | }); 144 | 145 | socket.on("gameStatusGerman", function () { 146 | console.log("GameStatusGerman"); 147 | $("#startGame").hide(); 148 | $("#codeInitialSetup").show(); 149 | $("#waitForStart").hide(); 150 | }); 151 | 152 | socket.on("displayBritish", function () { 153 | $("#waitForCode").hide(); 154 | $("#guessedDigits").show(); 155 | $("#triesTable").show(); 156 | }); 157 | 158 | socket.on("displayGerman", function (code) { 159 | $("#codeInitialSetup").hide(); 160 | $("#triesTable").show(); 161 | $("#code").show(); 162 | $("#code").text(`Code: ${code}`); 163 | }); 164 | 165 | socket.on("codeGenerated", function () { 166 | socket.emit("gameStarted"); 167 | }); 168 | 169 | socket.on("cheaterDetected", function (message) { 170 | alert(message); 171 | }); 172 | 173 | socket.on( 174 | "resultGerman", 175 | function ( 176 | britishCode, 177 | guessedDigits, 178 | exactPositions, 179 | hasTries, 180 | hasWon, 181 | level 182 | ) { 183 | if (hasWon) { 184 | console.log(level); 185 | if (level == 2) { 186 | $("#levelResult").show(); 187 | $("#nextLevelMultiplayer").on("click", function (e) { 188 | e.preventDefault(); 189 | $("#tries").empty(); 190 | $("#code").hide(); 191 | socket.emit("nextLevelMultiplayer", hasWon); 192 | console.log(level); 193 | $("#levelResult").hide(); 194 | $("#codeInitialSetup").show(); 195 | }); 196 | } else { 197 | $("#loseImg").attr("src", "img/germanLoseImg.png"); 198 | $("#lose").show(); 199 | $("#multiMain").hide(); 200 | $("#multiLose").show(); 201 | $("#homeButton").show(); 202 | } 203 | } 204 | if (!hasTries) { 205 | $("#winImg").attr("src", "img/germanWinImg.png"); 206 | $("#win").show(); 207 | $("#multiMain").hide(); 208 | $("#multiWin").show(); 209 | $("#homeButton").show(); 210 | } 211 | 212 | addRowsToTable(guessedDigits, exactPositions, britishCode); 213 | } 214 | ); 215 | 216 | socket.on( 217 | "guessBritish", 218 | function ( 219 | britishCode, 220 | guessedDigits, 221 | exactPositions, 222 | hasTries, 223 | hasWon, 224 | level 225 | ) { 226 | if (hasWon) { 227 | console.log(level); 228 | 229 | if (level == 2) { 230 | $("#guessedDigits").hide(); 231 | $("#congratulationsLevel").show(); 232 | $("#waitForNextLevel").show(); 233 | socket.on("nextLevelBritish", function () { 234 | $("#tries").empty(); 235 | $("#congratulationsLevel").hide(); 236 | $("#waitForNextLevel").hide(); 237 | $("#guessedDigits").show(); 238 | }); 239 | } else { 240 | $("#winImg").attr("src", "img/britishWinImg.png"); 241 | $("#win").show(); 242 | $("#guessedDigits").hide(); 243 | $("#multiMain").hide(); 244 | $("#multiWin").show(); 245 | $("#homeButton").show(); 246 | } 247 | } 248 | 249 | if (!hasTries) { 250 | $("#guessedDigits").hide(); 251 | $("#loseImg").attr("src", "img/britishLoseImg.png"); 252 | $("#lose").show(); 253 | $("#multiMain").hide(); 254 | $("#multiLose").show(); 255 | $("#homeButton").show(); 256 | } 257 | 258 | addRowsToTable(guessedDigits, exactPositions, britishCode); 259 | } 260 | ); 261 | 262 | socket.on("error", function (errorCode) { 263 | switch (errorCode) { 264 | case 0: 265 | $("#errorMessage").show(); 266 | $("#errorMessage").text("Please enter name and role"); 267 | $("#createGameForm").show(); 268 | break; 269 | case 1: 270 | $("#errorMessage").show(); 271 | $("#errorMessage").text("Please enter name"); 272 | $("#joinGameForm").show(); 273 | $("#waitForStart").hide(); 274 | break; 275 | case 2: 276 | $("#errorMessage").show(); 277 | $("#errorMessage").text("Invalid code"); 278 | clearInitialSetupDigits(); 279 | break; 280 | case 3: 281 | $("#errorMessage").show(); 282 | $("#errorMessage").text("Invalid code"); 283 | clearGuessedDigits(); 284 | break; 285 | case 4: 286 | $("#errorMessage").show(); 287 | $("#errorMessage").text("The Game Has Started"); 288 | $("#joinGameForm").show(); 289 | $("#waitForStart").hide(); 290 | case 5: 291 | $("#errorMessage").show(); 292 | $("#errorMessage").text("Invalid ID"); 293 | $("#joinGameForm").show(); 294 | $("#waitForStart").hide(); 295 | } 296 | }); 297 | 298 | socket.on("gameCrash", function () { 299 | $("#guessedDigits").hide(); 300 | $("#triesTable").hide(); 301 | $("#code").hide(); 302 | $("#createJoin").hide(); 303 | $("#codeInitialSetup").hide(); 304 | $("#createGameForm").hide(); 305 | $("#joinGameForm").hide(); 306 | $("#waitForStart").hide(); 307 | $("#startGame").hide(); 308 | $("#congratulationsLevel").hide(); 309 | $("#waitForNextLevel").hide(); 310 | $("#levelActions").hide(); 311 | $("#homeButton").hide(); 312 | $("#winImg").hide(); 313 | $("#loseImg").hide(); 314 | $("#leaveMessage").show(); 315 | }); 316 | 317 | socket.on("levelTwoCode", function (code) { 318 | $("#codeInitialSetup").hide(); 319 | $("#code").text(`Code: ${code}`); 320 | $("#code").show(); 321 | }); 322 | 323 | $("#createGameButton").on("click", function (e) { 324 | e.preventDefault(); 325 | 326 | $("#createJoin").hide(); 327 | $("#createGameForm").show(); 328 | }); 329 | 330 | $("#joinGameButton").on("click", function (e) { 331 | e.preventDefault(); 332 | 333 | $("#createJoin").hide(); 334 | $("#joinGameForm").show(); 335 | }); 336 | 337 | /** 338 | * Adds rows with information about the guessed digits and exact positions to the table. 339 | * 340 | * @param {number} guessedDigits The number of digits that are guessed. 341 | * @param {number} exactPositions The number of exact positions that are guessed. 342 | * @param {number} britishCode The code that was guessed from the player. 343 | */ 344 | function addRowsToTable(guessedDigits, exactPositions, britishCode) { 345 | let newRow = triesTableBody.insertRow(); 346 | let cell1 = newRow.insertCell(0); 347 | let cell2 = newRow.insertCell(1); 348 | let cell3 = newRow.insertCell(2); 349 | 350 | cell1.innerHTML = guessedDigits; 351 | cell2.innerHTML = exactPositions; 352 | cell3.innerHTML = britishCode; 353 | } 354 | 355 | function copyToClipboard() { 356 | const str = $("#roomId").text(); 357 | const el = document.createElement("textarea"); 358 | el.value = str; 359 | el.setAttribute("readonly", ""); 360 | el.style.position = "absolute"; 361 | el.style.left = "-9999px"; 362 | document.body.appendChild(el); 363 | el.select(); 364 | document.execCommand("copy"); 365 | document.body.removeChild(el); 366 | } 367 | 368 | function clearGuessedDigits() { 369 | $("#guessedDigits")[0].reset(); 370 | } 371 | 372 | function clearInitialSetupDigits() { 373 | $("#codeInitialSetup")[0].reset(); 374 | } 375 | -------------------------------------------------------------------------------- /public/singleplayer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 16 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 139 | 140 |
141 |
145 |

146 | Singleplayer Mode 147 |

148 | 149 |
150 | 151 | 157 |
158 | 159 | 160 | 168 |
169 |
170 |
171 |
172 | 180 | 181 | 188 | Rules 189 | 190 |
191 | 192 |
193 | 194 | 217 | 218 | 283 | 284 | 319 | 320 | 344 | 345 | 369 | 370 |
371 | 372 | 373 | 374 | 375 | 378 | 379 | 380 | 381 | 382 | 383 |
384 |
385 |
386 | 387 | 392 | 393 | 394 | 395 | 396 | 406 | 407 | 408 | -------------------------------------------------------------------------------- /out/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /out/public_js_multiplayerClient.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: public/js/multiplayerClient.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: public/js/multiplayerClient.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
const socket = io();
 30 | 
 31 | const createGameForm = document.getElementById("createGameForm");
 32 | const createJoin = document.getElementById("createOrJoin");
 33 | const createButton = document.getElementById("create");
 34 | const joinButton = document.getElementById("join");
 35 | const joinGameForm = document.getElementById("joinGameForm");
 36 | const waitingForPlayer = document.getElementById("waitingForPlayer");
 37 | const guessedDigits = document.getElementById("guessedDigits");
 38 | const triesTableBody = document
 39 | 	.getElementById("triesTable")
 40 | 	.getElementsByTagName("tbody")[0];
 41 | const triesTable = document.getElementById("triesTable");
 42 | const levelActions = document.getElementById("levelActions");
 43 | 
 44 | $(() => {
 45 | 	$("#digit1").on("input", () => {
 46 | 		$("#digit2").focus();
 47 | 	});
 48 | 
 49 | 	$("#digit2").on("input", () => {
 50 | 		$("#digit3").focus();
 51 | 	});
 52 | 
 53 | 	$("#digit3").on("input", () => {
 54 | 		$("#digit4").focus();
 55 | 	});
 56 | 
 57 | 	$("#digit4").on("input", () => {
 58 | 		$("#gsSubmit").focus();
 59 | 	});
 60 | 
 61 | 	$("#create1").on("input", () => {
 62 | 		$("#create2").focus();
 63 | 	});
 64 | 
 65 | 	$("#create2").on("input", () => {
 66 | 		$("#create3").focus();
 67 | 	});
 68 | 
 69 | 	$("#create3").on("input", () => {
 70 | 		$("#create4").focus();
 71 | 	});
 72 | 
 73 | 	$("#create4").on("input", () => {
 74 | 		$("#crSubmit").focus();
 75 | 	});
 76 | });
 77 | 
 78 | if (joinGameForm) {
 79 | 	joinGameForm.addEventListener("submit", function (e) {
 80 | 		e.preventDefault();
 81 | 
 82 | 		const nickname = e.target.nickname.value;
 83 | 		const roomId = e.target.gameId.value;
 84 | 		const waitingForStart = document.getElementById("waitForStart");
 85 | 		socket.emit("playerTwoJoin", nickname, roomId);
 86 | 
 87 | 		joinGameForm.style.display = "none";
 88 | 		waitingForStart.style.display = "block";
 89 | 		$("#errorMessage").hide();
 90 | 	});
 91 | }
 92 | 
 93 | const startButton = document.getElementById("startButton");
 94 | 
 95 | socket.on("playerJoined", function (message, obj) {
 96 | 	const startGame = document.getElementById("startGame");
 97 | 	const joinMessage = document.getElementById("joinMessage");
 98 | 
 99 | 	waitingForPlayer.style.display = "none";
100 | 	startGame.style.display = "block";
101 | 
102 | 	joinMessage.innerText = message;
103 | });
104 | 
105 | if (startButton) {
106 | 	startButton.addEventListener("click", function (e) {
107 | 		e.preventDefault();
108 | 		socket.emit("startGame");
109 | 	});
110 | }
111 | 
112 | if (createGameForm) {
113 | 	createGameForm.addEventListener("submit", function (e) {
114 | 		e.preventDefault();
115 | 
116 | 		const nickname = e.target.nickname.value;
117 | 		const role = e.target.role.value;
118 | 
119 | 		console.log(nickname, role);
120 | 
121 | 		socket.emit("playerOneJoin", nickname, role);
122 | 		createGameForm.style.display = "none";
123 | 	});
124 | }
125 | 
126 | socket.on("generateId", function (code) {
127 | 	waitingForPlayer.style.display = "block";
128 | 	roomId.innerText = code;
129 | 	$("#errorMessage").hide();
130 | });
131 | 
132 | $("#codeInitialSetup").on("submit", function (e) {
133 | 	e.preventDefault();
134 | 
135 | 	let digit1 = e.target.create1.value;
136 | 	let digit2 = e.target.create2.value;
137 | 	let digit3 = e.target.create3.value;
138 | 	let digit4 = e.target.create4.value;
139 | 
140 | 	let code =
141 | 		String(digit1) + String(digit2) + String(digit3) + String(digit4);
142 | 
143 | 	socket.emit("setupCode", code);
144 | 
145 | 	clearInitialSetupDigits(e);
146 | 	$("#errorMessage").hide();
147 | });
148 | 
149 | $("#guessedDigits").on("submit", function (e) {
150 | 	e.preventDefault();
151 | 
152 | 	let digit1 = e.target.digit1.value;
153 | 	let digit2 = e.target.digit2.value;
154 | 	let digit3 = e.target.digit3.value;
155 | 	let digit4 = e.target.digit4.value;
156 | 
157 | 	let britishCode =
158 | 		String(digit1) + String(digit2) + String(digit3) + String(digit4);
159 | 
160 | 	socket.emit("inputCode", britishCode);
161 | 
162 | 	clearGuessedDigits(e);
163 | 	$("#errorMessage").hide();
164 | });
165 | 
166 | socket.on("gameStatusBritish", function () {
167 | 	console.log("GameStatusBritish");
168 | 	$("#startGame").hide();
169 | 	$("#waitForStart").hide();
170 | 	$("#waitForCode").show();
171 | });
172 | 
173 | socket.on("gameStatusGerman", function () {
174 | 	console.log("GameStatusGerman");
175 | 	$("#startGame").hide();
176 | 	$("#codeInitialSetup").show();
177 | 	$("#waitForStart").hide();
178 | });
179 | 
180 | socket.on("displayBritish", function () {
181 | 	$("#waitForCode").hide();
182 | 	$("#guessedDigits").show();
183 | 	$("#triesTable").show();
184 | });
185 | 
186 | socket.on("displayGerman", function (code) {
187 | 	$("#codeInitialSetup").hide();
188 | 	$("#triesTable").show();
189 | 	$("#code").show();
190 | 	$("#code").text(`Code: ${code}`);
191 | });
192 | 
193 | socket.on("codeGenerated", function () {
194 | 	socket.emit("gameStarted");
195 | });
196 | 
197 | socket.on("cheaterDetected", function (message) {
198 | 	alert(message);
199 | });
200 | 
201 | socket.on(
202 | 	"resultGerman",
203 | 	function (
204 | 		britishCode,
205 | 		guessedDigits,
206 | 		exactPositions,
207 | 		hasTries,
208 | 		hasWon,
209 | 		level
210 | 	) {
211 | 		if (hasWon) {
212 | 			console.log(level);
213 | 			if (level == 2) {
214 | 				$("#levelResult").show();
215 | 				$("#nextLevelMultiplayer").on("click", function (e) {
216 | 					e.preventDefault();
217 | 					$("#tries").empty();
218 | 					$("#code").hide();
219 | 					socket.emit("nextLevelMultiplayer", hasWon);
220 | 					console.log(level);
221 | 					$("#levelResult").hide();
222 | 					$("#codeInitialSetup").show();
223 | 				});
224 | 			} else {
225 | 				$("#loseImg").attr("src", "img/germanLoseImg.png");
226 | 				$("#lose").show();
227 | 				$("#multiMain").hide();
228 | 				$("#multiLose").show();
229 | 				$("#homeButton").show();
230 | 			}
231 | 		}
232 | 		if (!hasTries) {
233 | 			$("#winImg").attr("src", "img/germanWinImg.png");
234 | 			$("#win").show();
235 | 			$("#multiMain").hide();
236 | 			$("#multiWin").show();
237 | 			$("#homeButton").show();
238 | 		}
239 | 
240 | 		addRowsToTable(guessedDigits, exactPositions, britishCode);
241 | 	}
242 | );
243 | 
244 | socket.on(
245 | 	"guessBritish",
246 | 	function (
247 | 		britishCode,
248 | 		guessedDigits,
249 | 		exactPositions,
250 | 		hasTries,
251 | 		hasWon,
252 | 		level
253 | 	) {
254 | 		if (hasWon) {
255 | 			console.log(level);
256 | 
257 | 			if (level == 2) {
258 | 				$("#guessedDigits").hide();
259 | 				$("#congratulationsLevel").show();
260 | 				$("#waitForNextLevel").show();
261 | 				socket.on("nextLevelBritish", function () {
262 | 					$("#tries").empty();
263 | 					$("#congratulationsLevel").hide();
264 | 					$("#waitForNextLevel").hide();
265 | 					$("#guessedDigits").show();
266 | 				});
267 | 			} else {
268 | 				$("#winImg").attr("src", "img/britishWinImg.png");
269 | 				$("#win").show();
270 | 				$("#guessedDigits").hide();
271 | 				$("#multiMain").hide();
272 | 				$("#multiWin").show();
273 | 				$("#homeButton").show();
274 | 			}
275 | 		}
276 | 
277 | 		if (!hasTries) {
278 | 			$("#guessedDigits").hide();
279 | 			$("#loseImg").attr("src", "img/britishLoseImg.png");
280 | 			$("#lose").show();
281 | 			$("#multiMain").hide();
282 | 			$("#multiLose").show();
283 | 			$("#homeButton").show();
284 | 		}
285 | 
286 | 		addRowsToTable(guessedDigits, exactPositions, britishCode);
287 | 	}
288 | );
289 | 
290 | socket.on("error", function (errorCode) {
291 | 	switch (errorCode) {
292 | 		case 0:
293 | 			$("#errorMessage").show();
294 | 			$("#errorMessage").text("Please enter name and role");
295 | 			$("#createGameForm").show();
296 | 			break;
297 | 		case 1:
298 | 			$("#errorMessage").show();
299 | 			$("#errorMessage").text("Please enter name");
300 | 			$("#joinGameForm").show();
301 | 			$("#waitForStart").hide();
302 | 			break;
303 | 		case 2:
304 | 			$("#errorMessage").show();
305 | 			$("#errorMessage").text("Invalid code");
306 | 			clearInitialSetupDigits();
307 | 			break;
308 | 		case 3:
309 | 			$("#errorMessage").show();
310 | 			$("#errorMessage").text("Invalid code");
311 | 			clearGuessedDigits();
312 | 			break;
313 | 		case 4:
314 | 			$("#errorMessage").show();
315 | 			$("#errorMessage").text("The Game Has Started");
316 | 			$("#joinGameForm").show();
317 | 			$("#waitForStart").hide();
318 | 	}
319 | });
320 | 
321 | socket.on("gameCrash", function () {
322 | 	$("#guessedDigits").hide();
323 | 	$("#triesTable").hide();
324 | 	$("#code").hide();
325 | 	$("#createJoin").hide();
326 | 	$("#codeInitialSetup").hide();
327 | 	$("#createGameForm").hide();
328 | 	$("#joinGameForm").hide();
329 | 	$("#waitForStart").hide();
330 | 	$("#startGame").hide();
331 | 	$("#congratulationsLevel").hide();
332 | 	$("#waitForNextLevel").hide();
333 | 	$("#levelActions").hide();
334 | 	$("#homeButton").hide();
335 | 	$("#winImg").hide();
336 | 	$("#loseImg").hide();
337 | 	$("#leaveMessage").show();
338 | });
339 | 
340 | socket.on("levelTwoCode", function (code) {
341 | 	$("#codeInitialSetup").hide();
342 | 	$("#code").text(`Code: ${code}`);
343 | 	$("#code").show();
344 | });
345 | 
346 | $("#createGameButton").on("click", function (e) {
347 | 	e.preventDefault();
348 | 
349 | 	$("#createJoin").hide();
350 | 	$("#createGameForm").show();
351 | });
352 | 
353 | $("#joinGameButton").on("click", function (e) {
354 | 	e.preventDefault();
355 | 
356 | 	$("#createJoin").hide();
357 | 	$("#joinGameForm").show();
358 | });
359 | 
360 | /**
361 |  * Adds rows with information about the guessed digits and exact positions to the table.
362 |  *
363 |  * @param {number} guessedDigits The number of digits that are guessed.
364 |  * @param {number} exactPositions The number of exact positions that are guessed.
365 |  * @param {number} britishCode The code that was guessed from the player.
366 |  */
367 | function addRowsToTable(guessedDigits, exactPositions, britishCode) {
368 | 	let newRow = triesTableBody.insertRow();
369 | 	let cell1 = newRow.insertCell(0);
370 | 	let cell2 = newRow.insertCell(1);
371 | 	let cell3 = newRow.insertCell(2);
372 | 
373 | 	cell1.innerHTML = guessedDigits;
374 | 	cell2.innerHTML = exactPositions;
375 | 	cell3.innerHTML = britishCode;
376 | }
377 | 
378 | function copyToClipboard() {
379 | 	const str = $("#roomId").text();
380 | 	const el = document.createElement("textarea");
381 | 	el.value = str;
382 | 	el.setAttribute("readonly", "");
383 | 	el.style.position = "absolute";
384 | 	el.style.left = "-9999px";
385 | 	document.body.appendChild(el);
386 | 	el.select();
387 | 	document.execCommand("copy");
388 | 	document.body.removeChild(el);
389 | }
390 | 
391 | function clearGuessedDigits() {
392 | 	$("#guessedDigits")[0].reset();
393 | }
394 | 
395 | function clearInitialSetupDigits() {
396 | 	$("#codeInitialSetup")[0].reset();
397 | }
398 | 
399 |
400 |
401 | 402 | 403 | 404 | 405 |
406 | 407 | 410 | 411 |
412 | 413 | 416 | 417 | 418 | 419 | 420 | 421 | -------------------------------------------------------------------------------- /out/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p 2 | 3 | 4 | 5 | JSDoc: Source: public/js/translate.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: public/js/translate.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
var textTranslation = {
 30 | 	"nav-game": {
 31 | 		en: `Game`,
 32 | 
 33 | 		bg: `Игра`,
 34 | 	},
 35 | 
 36 | 	"nav-singleplayer": {
 37 | 		en: `Single Player`,
 38 | 		bg: `Самостоятелна игра`,
 39 | 	},
 40 | 
 41 | 	"nav-multiplayer": {
 42 | 		en: `Multiplayer`,
 43 | 
 44 | 		bg: `Игра с приятел`,
 45 | 	},
 46 | 
 47 | 	"nav-rules": {
 48 | 		en: `Rules`,
 49 | 
 50 | 		bg: `Правила`,
 51 | 	},
 52 | 
 53 | 	"nav-about": {
 54 | 		en: `About`,
 55 | 
 56 | 		bg: `Информация`,
 57 | 	},
 58 | 
 59 | 	"nav-about-team": {
 60 | 		en: `About Team`,
 61 | 
 62 | 		bg: `За отбора`,
 63 | 	},
 64 | 
 65 | 	"nav-about-project": {
 66 | 		en: `About Project`,
 67 | 
 68 | 		bg: `За проекта`,
 69 | 	},
 70 | 
 71 | 	"nav-documentation": {
 72 | 		en: `Documentation`,
 73 | 
 74 | 		bg: `Документация`,
 75 | 	},
 76 | 
 77 | 	"nav-language": {
 78 | 		en: `Language`,
 79 | 
 80 | 		bg: `Език`,
 81 | 	},
 82 | 
 83 | 	"btn-en": {
 84 | 		en: `English`,
 85 | 
 86 | 		bg: `Английски`,
 87 | 	},
 88 | 
 89 | 	"btn-bg": {
 90 | 		en: `Bulgarian`,
 91 | 
 92 | 		bg: `Български`,
 93 | 	},
 94 | 
 95 | 	"nav-contact": {
 96 | 		en: `Contact`,
 97 | 
 98 | 		bg: `Контакт`,
 99 | 	},
100 | 
101 | 	"welcome-text": {
102 | 		en: `Welcome to Bletchley Game`,
103 | 
104 | 		bg: `Добре дошли в Bletchley Game`,
105 | 	},
106 | 
107 | 	"team-text": {
108 | 		en: `By Team Crypto Zargan`,
109 | 
110 | 		bg: `От отбор Крипто Зарган`,
111 | 	},
112 | 
113 | 	"index-singleplayer": {
114 | 		en: `Single Player`,
115 | 
116 | 		bg: `Самостоятелна игра`,
117 | 	},
118 | 
119 | 	"index-multiplayer": {
120 | 		en: `Multiplayer`,
121 | 
122 | 		bg: `Игра с приятел`,
123 | 	},
124 | 
125 | 	"index-story": {
126 | 		en: `Some Magic`,
127 | 
128 | 		bg: `Магия`,
129 | 	},
130 | 
131 | 	contact: {
132 | 		en: `Contact Page`,
133 | 
134 | 		bg: `Страница за контакт`,
135 | 	},
136 | 
137 | 	aboutTeam: {
138 | 		en: `About Team Page`,
139 | 
140 | 		bg: `Страница за отбора`,
141 | 	},
142 | 
143 | 	aboutProject: {
144 | 		en: `About Project Page`,
145 | 
146 | 		bg: `Страница за проекта`,
147 | 	},
148 | 
149 | 	singleplayer: {
150 | 		en: `Single Player Mode`,
151 | 
152 | 		bg: `Самостоятелна игра`,
153 | 	},
154 | 
155 | 	play: {
156 | 		en: `Play`,
157 | 
158 | 		bg: `Играй`,
159 | 	},
160 | 
161 | 	"diff-easy": {
162 | 		en: `Easy`,
163 | 
164 | 		bg: `Лесно`,
165 | 	},
166 | 
167 | 	"diff-med": {
168 | 		en: `Medium`,
169 | 
170 | 		bg: `Нормално`,
171 | 	},
172 | 
173 | 	"diff-hard": {
174 | 		en: `Hard`,
175 | 
176 | 		bg: `Трудно`,
177 | 	},
178 | 
179 | 	level1: {
180 | 		en: `You completed level 1. Are you ready to continue?`,
181 | 
182 | 		bg: `Ти мина първото ниво. Готов ли си да продължиш?`,
183 | 	},
184 | 
185 | 	"next-level": {
186 | 		en: `Next Task`,
187 | 
188 | 		bg: `Следваща мисия`,
189 | 	},
190 | 
191 | 	ff: {
192 | 		en: `Surrender`,
193 | 
194 | 		bg: `Предаване`,
195 | 	},
196 | 
197 | 	home: {
198 | 		en: `Home`,
199 | 
200 | 		bg: `Начална страница`,
201 | 	},
202 | 
203 | 	"play-again": {
204 | 		en: `Play Again`,
205 | 
206 | 		bg: `Играй отново`,
207 | 	},
208 | 
209 | 	win: {
210 | 		en: `You win!`,
211 | 
212 | 		bg: `Ти печелиш!`,
213 | 	},
214 | 
215 | 	lose: {
216 | 		en: `You lose!`,
217 | 
218 | 		bg: `Ти загуби!`,
219 | 	},
220 | 
221 | 	"guessed-digi": {
222 | 		en: `Guessed Digits`,
223 | 
224 | 		bg: `Познати числа`,
225 | 	},
226 | 
227 | 	"guessed-pos": {
228 | 		en: `Guessed Positions`,
229 | 
230 | 		bg: `Познати позиции`,
231 | 	},
232 | 
233 | 	"guessed-num": {
234 | 		en: `Number`,
235 | 
236 | 		bg: `Число`,
237 | 	},
238 | 
239 | 	opening: {
240 | 		en: `Multiplayer Mode`,
241 | 
242 | 		bg: `Игра с приятел`,
243 | 	},
244 | 
245 | 	winner: {
246 | 		en: `British wins!`,
247 | 
248 | 		bg: `Британеца печели!`,
249 | 	},
250 | 
251 | 	create: {
252 | 		en: `Create Game`,
253 | 
254 | 		bg: `Създай игра`,
255 | 	},
256 | 
257 | 	join: {
258 | 		en: `Join Game`,
259 | 
260 | 		bg: `Присъедини се в игра`,
261 | 	},
262 | 
263 | 	"send-code": {
264 | 		en: `Send this code to your friend and play together`,
265 | 
266 | 		bg: `Прати кода на твоя приятел и играйте заедно`,
267 | 	},
268 | 
269 | 	username: {
270 | 		en: `Username:`,
271 | 
272 | 		bg: `Потребителско име:`,
273 | 	},
274 | 
275 | 	role: {
276 | 		en: `Role:`,
277 | 
278 | 		bg: `Роля:`,
279 | 	},
280 | 
281 | 	german: {
282 | 		en: `German`,
283 | 
284 | 		bg: `Германец`,
285 | 	},
286 | 
287 | 	british: {
288 | 		en: `British`,
289 | 
290 | 		bg: `Британец`,
291 | 	},
292 | 
293 | 	ID: {
294 | 		en: `Game ID:`,
295 | 
296 | 		bg: `Идентификатор на играта:`,
297 | 	},
298 | 
299 | 	"guess-code": {
300 | 		en: `Guess Code`,
301 | 
302 | 		bg: `Познай кода`,
303 | 	},
304 | 
305 | 	"create-code": {
306 | 		en: `Create code`,
307 | 
308 | 		bg: `Създай кода`,
309 | 	},
310 | 
311 | 	code: {
312 | 		en: `Code: `,
313 | 
314 | 		bg: `Код: `,
315 | 	},
316 | 
317 | 	table1: {
318 | 		en: `Guessed Digits`,
319 | 
320 | 		bg: `Познати цифри`,
321 | 	},
322 | 
323 | 	table2: {
324 | 		en: `Guessed Positions`,
325 | 
326 | 		bg: `Познати позиции`,
327 | 	},
328 | 
329 | 	table3: {
330 | 		en: `Number`,
331 | 
332 | 		bg: `Число`,
333 | 	},
334 | 
335 | 	"level1-win": {
336 | 		en: `Congratulations you completed level 1`,
337 | 
338 | 		bg: `Поздравления ти завърши първо ниво`,
339 | 	},
340 | 
341 | 	"wait-level2": {
342 | 		en: `Waiting for your friend to start level 2`,
343 | 
344 | 		bg: `Изчакай приятеля си да стартира второ ниво`,
345 | 	},
346 | 
347 | 	"wait-create-code": {
348 | 		en: `Waiting for your friend to create the code`,
349 | 
350 | 		bg: `Изчакай приятеля си да напише кода`,
351 | 	},
352 | 
353 | 	"wait-start-game": {
354 | 		en: `Waiting for your friend to start the game`,
355 | 
356 | 		bg: `Изчакай приятеля си да стартира игра`,
357 | 	},
358 | 
359 | 	download: {
360 | 		en: `Download the full rules here`,
361 | 
362 | 		bg: `Изтегли правилата от тук`,
363 | 	},
364 | 
365 | 	"single-rules": {
366 | 		en: `In the single player mode of the game you play against the computer. To find out the coordinates of the enemy battleships
367 | 		you have to crack 2 codes - generated by a computer. <b>The numbers must be with the numbers form 0 to 7 including.</b>
368 | 		There are 3 difficulties:
369 | 		<ul>
370 | 			<li class="text-primary">Easy - You have to crack a 3-number code</li>
371 | 			<li style="color:#db7e32";>Medium - You have to crack a 4-number code </li>
372 | 			<li class="text-danger">Hard - You have to crack a 5-number code</li>
373 | 		</ul>
374 | 		There are also 2 tasks:
375 | 		<ul>
376 | 			<li> First task – On the first task the numbers cannot be repeated</li>
377 | 			<li>Second task – On the second task the numbers can be repeated. </li>
378 | 		</ul>
379 | 		<strong>You have 13 attempts</strong> to guess the number, otherwise you lose.`,
380 | 
381 | 		bg: `Във самостоятелния режим на играта вие играете срещу компютър. За да разберете
382 | 		координатите на вражеския кораб трябва да разбиете 2 кода, които са генерирани от компютър.
383 | 		<b>Цифрите на кода са между 0 и 7 включително.</b>
384 | 		Играта има 3 нива на трудност:
385 | 		<ul>
386 | 			<li class="text-primary">Лесно - Трябва да се разбие 3-цифрен код</li>
387 | 			<li style="color:#db7e32";>Средно - Трябва да се разбие 4-цифрен код</li>
388 | 			<li class="text-danger">Трудно - Трябва да се разбие 5-цифрен код</li>
389 | 		</ul>
390 | 		Във 2-те задачи кодовете ще бъдат генерирани по различен начин.
391 | 		<ul>
392 | 			<li>Първа задача - Кодът <b>не може</b> да има повтарящи се чифри.</li>
393 | 			<li>Втора задача - Кодът <b>може</b> да има повтарящи се чифри.</li>
394 | 		</ul>
395 | 		<strong>Имате 13 опита</strong>, за да познаете координатите на вражеския кораб, в противен случай ще загубите.`,
396 | 	},
397 | 
398 | 	"multi-rules": {
399 | 		en: ` In the multiplayer mode of the game 2 people can play against each other.<br> One person creates a room and
400 | 		gives the code that was given to him so that the other one can join it. <b>The numbers must be with the numbers form 0 to 7 including.</b>  <br>The person who creates the
401 | 		room can
402 | 	  choose his role. There are 2 different roles:
403 | 		<ul>
404 | 			<li  class="text-danger">German – If you choose to be German you create the code. Your task is the code
405 | 				to be hard so that the British cannot defeat you easy.</li>
406 | 				<li class="text-primary">British – Or if you choose to be the British you are guessing the code that was
407 | 				created by the German.<strong> You have 13 attempts</strong> to guess the code.</li> 
408 | 		</ul>
409 | 		There are also 2 tasks:
410 | 		<ul>
411 | 			<li> First task – On the first task the numbers<b> cannot</b> be repeated</li>
412 | 			<li> Second task – On the second task the numbers<b> can</b> be repeated. </li>
413 | 		</ul>`,
414 | 
415 | 		bg: `В груповия режима на играта 2-ма човека вие може ад играете един срещу друг. Единия от двамата прави стая и дава 
416 | 		кода за нея на другия, койото го въвжеда
417 | 		Този който прави стаята може да си избере каква роля да е, а другият ще е другата.
418 | 	  Двете различни роли на играта са:
419 | 		<ul>
420 | 			<li  class="text-danger">Германец - Ако изберете да сте германец, ролята ви е да създадете кода, който трябва да
421 | 			 бъде възможно най-труден, за да може вашият кораб да не бъде разбит</li>
422 | 				<li class="text-primary">Британец - Ако изберете да сте британец, ролята ви е да разбиете кода създаден от
423 | 				 германеца. Така вие ще унищожите неговият кораб</li> 
424 | 		</ul>
425 | 		Кода който създава германеца <b>трябва да е с цифрите от 0 до 7 включително.</b> Има и 2 различни задачи, които имат следните условия:
426 | 		<ul>
427 | 		<li>Първа задача - Кодът <b>не може</b> да има повтарящи се чифри.</li>
428 | 		<li>Втора задача - Кодът <b>може</b> да има повтарящи се чифри.</li>
429 | 		</ul>`,
430 | 	},
431 | 
432 | 	rules: {
433 | 		en: `Rules`,
434 | 
435 | 		bg: `Правила`,
436 | 	},
437 | 
438 | 	"start-game": {
439 | 		en: `Start Game`,
440 | 
441 | 		bg: `Стартирай играта`,
442 | 	},
443 | };
444 | 
445 | var currentLanguage = "en";
446 | 
447 | /**
448 |  * Replaces the text on the page with the chosen language.
449 |  *
450 |  * @param {string} item The item that has to be replaced.
451 |  * @param {string} text The text that the item is going to be replaced with.
452 |  */
453 | function replaceElementText(item, text) {
454 | 	if (!item.is("button")) {
455 | 		item.html(text);
456 | 	} else {
457 | 		item.text(text);
458 | 	}
459 | }
460 | 
461 | /**
462 |  * Translates the elements with the data-lang attribute.
463 |  *
464 |  * @param {string} langId The identificator of the language (bg/en).
465 |  */
466 | function translateLabel(langId) {
467 | 	console.log(langId);
468 | 	currentLanguage = langId;
469 | 
470 | 	// Gets all tags that have 'data-lang' attribute present
471 | 	$("[data-lang]").each(function () {
472 | 		let item = $(this);
473 | 		if (
474 | 			textTranslation.hasOwnProperty(item.data("lang")) &&
475 | 			textTranslation[item.data("lang")].hasOwnProperty(langId)
476 | 		) {
477 | 			let text = textTranslation[item.data("lang")][langId];
478 | 			replaceElementText(item, text);
479 | 		} else {
480 | 			replaceElementText(
481 | 				item,
482 | 				"<font color='red'>" + item.data("lang") + "</font>"
483 | 			);
484 | 		}
485 | 	});
486 | }
487 | 
488 | /**
489 |  * Gets the translated elements.
490 |  *
491 |  * @param {string} elementId The element's Id.
492 |  * @return {string} textTranslation The translated text.
493 |  */
494 | function getTranslatedText(elementId) {
495 | 	return textTranslation[elementId][currentLanguage];
496 | }
497 | 
498 |
499 |
500 | 501 | 502 | 503 | 504 |
505 | 506 | 509 | 510 |
511 | 512 |
513 | Documentation generated by JSDoc 3.6.6 on Tue Jan 12 2021 22:48:58 GMT+0200 (Eastern European Standard Time) 514 |
515 | 516 | 517 | 518 | 519 | 520 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const express = require("express"); 3 | const bodyParser = require("body-parser"); 4 | const { isObject } = require("util"); 5 | const socketio = require("socket.io"); 6 | const game = require("./utils/game"); 7 | const uuid = require("uuid"); 8 | const mailer = require("nodemailer"); 9 | 10 | const http = require("http"); 11 | const app = express(); 12 | const https = require("https"); 13 | const fs = require("fs"); 14 | const { listeners } = require("cluster"); 15 | require("dotenv").config(); 16 | 17 | const httpApp = express(http); 18 | 19 | app.disable("x-powered-by"); 20 | 21 | httpApp.listen(process.env.httpPort, () => { 22 | console.log(`HTTP server started on port ${process.env.httpPort}`); 23 | }); 24 | 25 | httpApp.get("*", function (req, res) { 26 | res.redirect("https://" + req.headers.host); 27 | }); 28 | 29 | const server = https.createServer( 30 | { 31 | hostname: process.env.hostname, 32 | path: process.env.path, 33 | method: process.env.method, 34 | pfx: fs.readFileSync(process.env.pfxPath), 35 | passphrase: process.env.passphrase, 36 | agent: process.env.agent, 37 | rejectUnauthorized: process.env.rejectUnauthorized, 38 | }, 39 | app 40 | ); 41 | 42 | const smtpConfig = { 43 | host: process.env.gmailHost, 44 | port: process.env.gmailPORT, 45 | secure: true, 46 | auth: { 47 | user: process.env.gmailID, 48 | pass: process.env.gmailPass, 49 | }, 50 | }; 51 | 52 | const transporter = mailer.createTransport(smtpConfig); 53 | 54 | server.listen(process.env.httpsPort, () => { 55 | console.log(`HTTPS Server running on port ${process.env.httpsPort}`); 56 | }); 57 | 58 | const io = socketio(server); 59 | app.use(bodyParser.urlencoded({ extended: true })); 60 | 61 | app.use(express.static("./public")); 62 | app.use(express.static("./out")); 63 | app.use(express.static("./docs")); 64 | 65 | app.get("/", function (req, res) { 66 | res.sendFile(__dirname + "/public/index.html"); 67 | }); 68 | 69 | app.get("/singleplayer", function (req, res) { 70 | res.sendFile(__dirname + "/public/singleplayer.html"); 71 | }); 72 | 73 | app.get("/multiplayer", function (req, res) { 74 | res.sendFile(__dirname + "/public/multiplayer.html"); 75 | }); 76 | 77 | app.get("/team", function (req, res) { 78 | res.sendFile(__dirname + "/public/aboutTeam.html"); 79 | }); 80 | 81 | app.get("/contact", function (req, res) { 82 | res.sendFile(__dirname + "/public/contact.html"); 83 | }); 84 | 85 | app.get(process.env.er1, function (req, res) { 86 | res.sendFile(__dirname + process.env.ee1); 87 | }); 88 | 89 | app.get("/rules", function (req, res) { 90 | res.sendFile(__dirname + "/public/rules.html"); 91 | }); 92 | 93 | app.get("/documentation", function (req, res) { 94 | res.sendFile(__dirname + "/out/global.html"); 95 | }); 96 | 97 | app.get("*", function (req, res) { 98 | res.sendFile(__dirname + "/public/error404.html"); 99 | }); 100 | 101 | app.post("/processContact", function (req, res) { 102 | let data = req.body; 103 | 104 | let mailOptions = { 105 | from: data.email, 106 | to: process.env.gmailID, 107 | subject: data.subject, 108 | html: ` 109 |

${data.username} send you a message

110 | 111 |

Message:

${data.message}

112 | `, 113 | }; 114 | console.log(mailOptions); 115 | 116 | transporter.sendMail(mailOptions, (error, info) => { 117 | if (error) { 118 | console.log(error); 119 | } 120 | }); 121 | 122 | res.redirect("/contact"); 123 | }); 124 | 125 | let multiGameState = { 126 | getRoomIdBySocketId(socketId) { 127 | console.log(`Getting roomId for ${socketId}`); 128 | console.log(this); 129 | for (let key in this) { 130 | if ( 131 | this[key].firstPlayerId == socketId || 132 | this[key].secondPlayerId == socketId 133 | ) { 134 | console.log(`roomId for ${key}`); 135 | return key; 136 | } 137 | } 138 | 139 | return null; 140 | }, 141 | 142 | getUserIdByRole(role, roomId) { 143 | console.log(`getUserIdByRole: ${role}`); 144 | 145 | if (this[roomId].firstPlayerRole == role) { 146 | console.log(`Returning ${this[roomId].firstPlayerId}`); 147 | return this[roomId].firstPlayerId; 148 | } 149 | 150 | if (this[roomId].secondPlayerRole == role) { 151 | console.log(`Returning ${this[roomId].secondPlayerId}`); 152 | return this[roomId].secondPlayerId; 153 | } 154 | 155 | return null; 156 | }, 157 | 158 | getUsersByRoles(roomId) { 159 | return { 160 | britishPlayerId: this.getUserIdByRole(ROLES.BRITISH, roomId), 161 | germanPlayerId: this.getUserIdByRole(ROLES.GERMAN, roomId), 162 | }; 163 | }, 164 | }; 165 | 166 | /** 167 | * Enum for game roles. 168 | * @enum {string} 169 | */ 170 | let ROLES = { 171 | /** The role is German.*/ 172 | GERMAN: "German", 173 | /** The role is British.*/ 174 | BRITISH: "British", 175 | }; 176 | 177 | /** 178 | * Enum for different game states. 179 | * @enum {number} 180 | */ 181 | let GAME_PROGRESS = { 182 | /** The game is in the preparing state.*/ 183 | PREPARE: 0, 184 | /** The game is in the starting state.*/ 185 | STARTED: 1, 186 | /** The game is in the level 1 state.*/ 187 | LEVEL_1: 2, 188 | /** The game is in the level 2 state.*/ 189 | LEVEL_2: 3, 190 | /** The game is in the finishing state.*/ 191 | FINISH: 4, 192 | }; 193 | 194 | let ERROR = { 195 | NO_NAME_P1: 0, 196 | NO_NAME_P2: 1, 197 | INVALID_CODE_GERMAN: 2, 198 | INVALID_CODE_BRITISH: 3, 199 | FULL_ROOM: 4, 200 | INVALID_ID: 5, 201 | }; 202 | 203 | io.on("connection", function (socket) { 204 | console.log(`New Connection: ${socket.id}`); 205 | 206 | socket.on("startSingleplayer", function (username, difficulty) { 207 | console.log(username, difficulty); 208 | 209 | if (username != undefined && difficulty != undefined) { 210 | let gameCount = 1; 211 | let hasWon = false; 212 | let level = 1; 213 | let hasTries = true; 214 | let guessedDigits = 0; 215 | let guessedPosition = 0; 216 | let code; 217 | let length; 218 | 219 | let code2; 220 | 221 | if (difficulty == "easy") { 222 | length = 3; 223 | code = game.generateCode(length); 224 | code2 = game.generateRepetitiveCode(length); 225 | } else if (difficulty == "medium") { 226 | length = 4; 227 | code = game.generateCode(length); 228 | code2 = game.generateRepetitiveCode(length); 229 | } else if (difficulty == "hard") { 230 | length = 5; 231 | code = game.generateCode(length); 232 | code2 = game.generateRepetitiveCode(length); 233 | } 234 | 235 | console.log(code); 236 | 237 | socket.on("nextLevel", function () { 238 | if (hasWon) { 239 | level = 2; 240 | guessedDigits = 0; 241 | guessedPosition = 0; 242 | gameCount = 1; 243 | code = code2; // LEVEL 2 244 | console.log(code); 245 | hasWon = false; 246 | hasTries = true; 247 | } 248 | }); 249 | 250 | socket.on("crackCodeSinglePlayer", function (guessedCode) { 251 | if (!guessedCode || guessedCode.length != length) { 252 | console.log(`Invalid request: !${guessedCode}!`); 253 | return {}; 254 | } 255 | 256 | hasTries = gameCount <= 13; 257 | if (hasTries) { 258 | gameCount++; 259 | guessedDigits = game.calculatesGuessedDigits( 260 | guessedCode, 261 | code 262 | ); 263 | guessedPosition = game.calculateExactPositions( 264 | guessedCode, 265 | code 266 | ); 267 | hasWon = guessedPosition == length; 268 | if (hasWon && level == 2) { 269 | gameCount = 420; 270 | } 271 | console.log( 272 | "Digs: " + guessedDigits, 273 | "Pos: " + guessedPosition 274 | ); 275 | } 276 | socket.emit("singleplayerMediumAnswer", { 277 | guessedDigits, 278 | guessedPosition, 279 | hasTries, 280 | hasWon, 281 | level, 282 | }); 283 | }); 284 | } 285 | }); 286 | 287 | socket.on("playerOneJoin", function (nickname, role) { 288 | const roomId = uuid.v4().substr(0, 8); 289 | socket.join(roomId); 290 | 291 | if (nickname == "" || role == "") { 292 | console.log("User tried to join with no name or role"); 293 | io.to(socket.id).emit("error", ERROR.NO_NAME_P1); 294 | return {}; 295 | } 296 | 297 | multiGameState[roomId] = { 298 | firstPlayer: nickname, 299 | firstPlayerRole: role, 300 | secondPlayer: null, 301 | secondPlayerRole: null, 302 | firstPlayerId: socket.id, 303 | code: null, 304 | progress: GAME_PROGRESS.PREPARE, 305 | }; 306 | 307 | console.log( 308 | `${nickname} who is ${role} has joined in room with id ${roomId}` 309 | ); 310 | console.log(multiGameState); 311 | socket.emit("generateId", roomId); 312 | }); 313 | 314 | socket.on("playerTwoJoin", function (nickname, roomId) { 315 | if (nickname == "") { 316 | socket.emit("error", ERROR.NO_NAME_P2); 317 | return {}; 318 | } 319 | if (roomId != undefined) { 320 | console.log(multiGameState[roomId]); 321 | if (multiGameState.hasOwnProperty(roomId)) { 322 | let players = multiGameState.getUsersByRoles(roomId); 323 | if (multiGameState[roomId].secondPlayer == null) { 324 | socket.join(roomId); 325 | if ( 326 | multiGameState[roomId].firstPlayer != undefined && 327 | multiGameState[roomId].firstPlayerRole != undefined 328 | ) { 329 | multiGameState[roomId].secondPlayer = nickname; 330 | if ( 331 | multiGameState[roomId].firstPlayerRole == "German" 332 | ) { 333 | multiGameState[roomId].secondPlayerRole = "British"; 334 | } else { 335 | multiGameState[roomId].secondPlayerRole = "German"; 336 | } 337 | multiGameState[roomId].secondPlayerId = socket.id; 338 | 339 | console.log(multiGameState); 340 | 341 | console.log( 342 | `${nickname} who is ${multiGameState[roomId].secondPlayerRole} has joind in room with id ${roomId}` 343 | ); 344 | 345 | socket.broadcast 346 | .to(roomId) 347 | .emit( 348 | "playerJoined", 349 | `${nickname} has joined`, 350 | multiGameState[roomId] 351 | ); 352 | } 353 | } else { 354 | socket.emit("error", ERROR.FULL_ROOM); 355 | } 356 | } else { 357 | socket.emit("error", ERROR.INVALID_ID); 358 | console.log(`!Room with ID of ${roomId} doesn't exist!`); 359 | } 360 | } 361 | }); 362 | 363 | socket.on("startGame", function () { 364 | let roomId = multiGameState.getRoomIdBySocketId(socket.id); 365 | console.log(`startGame: ${roomId}`); 366 | if (roomId == null) { 367 | console.log(`gameId is null!`); 368 | return {}; 369 | } 370 | 371 | let players = multiGameState.getUsersByRoles(roomId); 372 | console.log(`Dumping players object`); 373 | console.log(players); 374 | 375 | multiGameState[roomId].progress = GAME_PROGRESS.STARTED; 376 | console.log(`Dumping multiGameState object`); 377 | console.log(multiGameState); 378 | 379 | console.log(`Emitting gameStatusGerman to ${players.germanPlayerId}`); 380 | io.to(players.germanPlayerId).emit(`gameStatusGerman`); 381 | console.log(`Emitting gameStatusBritish to ${players.britishPlayerId}`); 382 | io.to(players.britishPlayerId).emit(`gameStatusBritish`); 383 | }); 384 | 385 | socket.on("gameStarted", function () { 386 | let roomId = multiGameState.getRoomIdBySocketId(socket.id); 387 | if (roomId == null) { 388 | return {}; 389 | } 390 | 391 | let players = multiGameState.getUsersByRoles(roomId); 392 | 393 | multiGameState[roomId].progress = GAME_PROGRESS.LEVEL_1; 394 | 395 | io.to(players.germanPlayerId).emit( 396 | `displayGerman`, 397 | multiGameState[roomId].code 398 | ); 399 | io.to(players.britishPlayerId).emit(`displayBritish`); 400 | }); 401 | 402 | let gameCountMultiplayer = 1; 403 | let hasWonMultiplayer = false; 404 | let hasTriesMultiplayer = true; 405 | let guessedDigitsMultiplayer; 406 | let exactPositionsMultiplayer; 407 | 408 | socket.on("nextLevelMultiplayer", function (hasWon1) { 409 | let roomId = multiGameState.getRoomIdBySocketId(socket.id); 410 | if (hasWon1) { 411 | multiGameState[roomId].progress = GAME_PROGRESS.LEVEL_2; 412 | guessedDigitsMultiplayer = 0; 413 | exactPositionsMultiplayer = 0; 414 | gameCountMultiplayer = 1; 415 | hasWonMultiplayer = false; 416 | hasTriesMultiplayer = true; 417 | } 418 | console.log(multiGameState[roomId].code); 419 | }); 420 | 421 | socket.on("setupCode", function (code) { 422 | let roomId = multiGameState.getRoomIdBySocketId(socket.id); 423 | 424 | let players = multiGameState.getUsersByRoles(roomId); 425 | 426 | if (roomId == null) { 427 | return {}; 428 | } 429 | 430 | if (socket.id == players.britishPlayerId) { 431 | return {}; 432 | } 433 | 434 | console.log(multiGameState[roomId].progress); 435 | 436 | if (multiGameState[roomId].progress + 1 == 2) { 437 | if (game.checkInput(code)) { 438 | multiGameState[roomId].code = code; 439 | socket.emit("codeGenerated"); 440 | } else { 441 | socket.emit("error", ERROR.INVALID_CODE_GERMAN); 442 | } 443 | } else if (multiGameState[roomId].progress == 3) { 444 | if (game.checkInputTaskTwo(code)) { 445 | multiGameState[roomId].code = code; 446 | io.to(players.britishPlayerId).emit(`nextLevelBritish`); 447 | io.to(players.germanPlayerId).emit( 448 | `levelTwoCode`, 449 | multiGameState[roomId].code 450 | ); 451 | } else { 452 | io.to(players.germanPlayerId).emit( 453 | "error", 454 | ERROR.INVALID_CODE_GERMAN 455 | ); 456 | } 457 | } 458 | }); 459 | 460 | socket.on("inputCode", function (britishCode) { 461 | let roomId = multiGameState.getRoomIdBySocketId(socket.id); 462 | if (roomId == null) { 463 | return {}; 464 | } 465 | 466 | let players = multiGameState.getUsersByRoles(roomId); 467 | 468 | if (socket.id != players.britishPlayerId) { 469 | return {}; 470 | } 471 | 472 | if (!britishCode || britishCode.length != 4) { 473 | console.log(`Invalid request: !${britishCode}!`); 474 | socket.emit("error", ERROR.INVALID_CODE_BRITISH); 475 | return {}; 476 | } 477 | 478 | guessedDigitsMultiplayer = game.calculatesGuessedDigits( 479 | britishCode, 480 | multiGameState[roomId].code 481 | ); 482 | 483 | exactPositionsMultiplayer = game.calculateExactPositions( 484 | britishCode, 485 | multiGameState[roomId].code 486 | ); 487 | 488 | hasTriesMultiplayer = gameCountMultiplayer <= 13; 489 | if (hasTriesMultiplayer) { 490 | gameCountMultiplayer++; 491 | hasWonMultiplayer = exactPositionsMultiplayer == 4; 492 | if (hasWonMultiplayer && multiGameState[roomId].progress == 3) { 493 | gameCountMultiplayer = 420; 494 | } 495 | console.log( 496 | "Digs: " + guessedDigitsMultiplayer, 497 | "Pos: " + exactPositionsMultiplayer + " " + hasWonMultiplayer 498 | ); 499 | } 500 | console.log(multiGameState[roomId].progress); 501 | io.to(players.germanPlayerId).emit( 502 | `resultGerman`, 503 | britishCode, 504 | guessedDigitsMultiplayer, 505 | exactPositionsMultiplayer, 506 | hasTriesMultiplayer, 507 | hasWonMultiplayer, 508 | multiGameState[roomId].progress 509 | ); 510 | 511 | io.to(players.britishPlayerId).emit( 512 | `guessBritish`, 513 | britishCode, 514 | guessedDigitsMultiplayer, 515 | exactPositionsMultiplayer, 516 | hasTriesMultiplayer, 517 | hasWonMultiplayer, 518 | multiGameState[roomId].progress 519 | ); 520 | }); 521 | 522 | socket.on("disconnect", function () { 523 | let roomId = multiGameState.getRoomIdBySocketId(socket.id); 524 | delete multiGameState[roomId]; 525 | console.log(multiGameState); 526 | 527 | io.to(roomId).emit("gameCrash"); 528 | }); 529 | }); 530 | -------------------------------------------------------------------------------- /out/app.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: app.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: app.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
"use strict";
 30 | const express = require("express");
 31 | const bodyParser = require("body-parser");
 32 | const { isObject } = require("util");
 33 | const socketio = require("socket.io");
 34 | const game = require("./utils/game");
 35 | const uuid = require("uuid");
 36 | const mailer = require("nodemailer");
 37 | 
 38 | const http = require("http");
 39 | const app = express();
 40 | const https = require("https");
 41 | const fs = require("fs");
 42 | const { listeners } = require("cluster");
 43 | require("dotenv").config();
 44 | 
 45 | const httpApp = express(http);
 46 | 
 47 | app.disable("x-powered-by");
 48 | 
 49 | httpApp.listen(process.env.httpPort, () => {
 50 | 	console.log(`HTTP server started on port ${process.env.httpPort}`);
 51 | });
 52 | 
 53 | httpApp.get("*", function (req, res) {
 54 | 	res.redirect("https://" + req.headers.host);
 55 | });
 56 | 
 57 | const server = https.createServer(
 58 | 	{
 59 | 		hostname: process.env.hostname,
 60 | 		path: process.env.path,
 61 | 		method: process.env.method,
 62 | 		pfx: fs.readFileSync(process.env.pfxPath),
 63 | 		passphrase: process.env.passphrase,
 64 | 		agent: process.env.agent,
 65 | 		rejectUnauthorized: process.env.rejectUnauthorized,
 66 | 	},
 67 | 	app
 68 | );
 69 | 
 70 | const smtpConfig = {
 71 | 	host: process.env.gmailHost,
 72 | 	port: process.env.gmailPORT,
 73 | 	secure: true,
 74 | 	auth: {
 75 | 		user: process.env.gmailID,
 76 | 		pass: process.env.gmailPass,
 77 | 	},
 78 | };
 79 | 
 80 | const transporter = mailer.createTransport(smtpConfig);
 81 | 
 82 | server.listen(process.env.httpsPort, () => {
 83 | 	console.log(`HTTPS Server running on port ${process.env.httpsPort}`);
 84 | });
 85 | 
 86 | const io = socketio(server);
 87 | app.use(bodyParser.urlencoded({ extended: true }));
 88 | 
 89 | app.use(express.static("./public"));
 90 | app.use(express.static("./out"));
 91 | app.use(express.static("./docs"));
 92 | 
 93 | app.get("/", function (req, res) {
 94 | 	res.sendFile(__dirname + "/public/index.html");
 95 | });
 96 | 
 97 | app.get("/singleplayer", function (req, res) {
 98 | 	res.sendFile(__dirname + "/public/singleplayer.html");
 99 | });
100 | 
101 | app.get("/multiplayer", function (req, res) {
102 | 	res.sendFile(__dirname + "/public/multiplayer.html");
103 | });
104 | 
105 | app.get("/team", function (req, res) {
106 | 	res.sendFile(__dirname + "/public/aboutTeam.html");
107 | });
108 | 
109 | app.get("/contact", function (req, res) {
110 | 	res.sendFile(__dirname + "/public/contact.html");
111 | });
112 | 
113 | app.get(process.env.er1, function (req, res) {
114 | 	res.sendFile(__dirname + process.env.ee1);
115 | });
116 | 
117 | app.get("/rules", function (req, res) {
118 | 	res.sendFile(__dirname + "/public/rules.html");
119 | });
120 | 
121 | app.get("/documentation", function (req, res) {
122 | 	res.sendFile(__dirname + "/out/global.html");
123 | });
124 | 
125 | app.get("*", function (req, res) {
126 | 	res.sendFile(__dirname + "/public/error404.html");
127 | });
128 | 
129 | app.post("/processContact", function (req, res) {
130 | 	let data = req.body;
131 | 
132 | 	let mailOptions = {
133 | 		from: data.email,
134 | 		to: process.env.gmailID,
135 | 		subject: data.subject,
136 | 		html: `
137 | 		 <h1> ${data.username} send you a message </h1>
138 | 
139 | 		<h2> Message: </h2> <p> ${data.message} </p>
140 | 		`,
141 | 	};
142 | 	console.log(mailOptions);
143 | 
144 | 	transporter.sendMail(mailOptions, (error, info) => {
145 | 		if (error) {
146 | 			console.log(error);
147 | 		}
148 | 	});
149 | 
150 | 	res.redirect("/contact");
151 | });
152 | 
153 | let multiGameState = {
154 | 	getRoomIdBySocketId(socketId) {
155 | 		console.log(`Getting roomId for ${socketId}`);
156 | 		console.log(this);
157 | 		for (let key in this) {
158 | 			if (
159 | 				this[key].firstPlayerId == socketId ||
160 | 				this[key].secondPlayerId == socketId
161 | 			) {
162 | 				console.log(`roomId for ${key}`);
163 | 				return key;
164 | 			}
165 | 		}
166 | 
167 | 		return null;
168 | 	},
169 | 
170 | 	getUserIdByRole(role, roomId) {
171 | 		console.log(`getUserIdByRole: ${role}`);
172 | 
173 | 		// console.log(
174 | 		// 	`getUserIdByRole[${roomId}].firstPlayerRole ${this[roomId].firstPlayerRole}`
175 | 		// );
176 | 		if (this[roomId].firstPlayerRole == role) {
177 | 			console.log(`Returning ${this[roomId].firstPlayerId}`);
178 | 			return this[roomId].firstPlayerId;
179 | 		}
180 | 
181 | 		// console.log(
182 | 		// 	`getUserIdByRole[${roomId}].secondPlayerRole ${this[roomId].secondPlayerRole}`
183 | 		// );
184 | 		if (this[roomId].secondPlayerRole == role) {
185 | 			console.log(`Returning ${this[roomId].secondPlayerId}`);
186 | 			return this[roomId].secondPlayerId;
187 | 		}
188 | 
189 | 		return null;
190 | 	},
191 | 
192 | 	getUsersByRoles(roomId) {
193 | 		// console.log(`getUsersByRoles: ${roomId}`);
194 | 		return {
195 | 			britishPlayerId: this.getUserIdByRole(ROLES.BRITISH, roomId),
196 | 			germanPlayerId: this.getUserIdByRole(ROLES.GERMAN, roomId),
197 | 		};
198 | 	},
199 | };
200 | 
201 | /**
202 |  * Enum for game roles.
203 |  * @enum {string}
204 |  */
205 | let ROLES = {
206 | 	/** The role is German.*/
207 | 	GERMAN: "German",
208 | 	/** The role is British.*/
209 | 	BRITISH: "British",
210 | };
211 | 
212 | /**
213 |  * Enum for different game states.
214 |  * @enum {number}
215 |  */
216 | let GAME_PROGRESS = {
217 | 	/** The game is in the preparing state.*/
218 | 	PREPARE: 0,
219 | 	/** The game is in the starting state.*/
220 | 	STARTED: 1,
221 | 	/** The game is in the level 1 state.*/
222 | 	LEVEL_1: 2,
223 | 	/** The game is in the level 2 state.*/
224 | 	LEVEL_2: 3,
225 | 	/** The game is in the finishing state.*/
226 | 	FINISH: 4,
227 | };
228 | 
229 | let ERROR = {
230 | 	NO_NAME_P1: 0,
231 | 	NO_NAME_P2: 1,
232 | 	INVALID_CODE_GERMAN: 2,
233 | 	INVALID_CODE_BRITISH: 3,
234 | 	FULL_ROOM: 4,
235 | };
236 | 
237 | io.on("connection", function (socket) {
238 | 	console.log(`New Connection: ${socket.id}`);
239 | 
240 | 	socket.on("startSingleplayer", function (username, difficulty) {
241 | 		console.log(username, difficulty);
242 | 
243 | 		if (username != undefined && difficulty != undefined) {
244 | 			let gameCount = 1;
245 | 			let hasWon = false;
246 | 			let level = 1;
247 | 			let hasTries = true;
248 | 			let guessedDigits = 0;
249 | 			let guessedPosition = 0;
250 | 			let code;
251 | 			let length;
252 | 
253 | 			let code2;
254 | 
255 | 			if (difficulty == "easy") {
256 | 				length = 3;
257 | 				code = game.generateCode(length);
258 | 				code2 = game.generateRepetitiveCode(length);
259 | 			} else if (difficulty == "medium") {
260 | 				length = 4;
261 | 				code = game.generateCode(length);
262 | 				code2 = game.generateRepetitiveCode(length);
263 | 			} else if (difficulty == "hard") {
264 | 				length = 5;
265 | 				code = game.generateCode(length);
266 | 				code2 = game.generateRepetitiveCode(length);
267 | 			}
268 | 
269 | 			console.log(code);
270 | 
271 | 			socket.on("nextLevel", function () {
272 | 				if (hasWon) {
273 | 					level = 2;
274 | 					guessedDigits = 0;
275 | 					guessedPosition = 0;
276 | 					gameCount = 1;
277 | 					code = code2; // LEVEL 2
278 | 					console.log(code);
279 | 					hasWon = false;
280 | 					hasTries = true;
281 | 				}
282 | 			});
283 | 
284 | 			socket.on("crackCodeSinglePlayer", function (guessedCode) {
285 | 				if (!guessedCode || guessedCode.length != length) {
286 | 					console.log(`Invalid request: !${guessedCode}!`);
287 | 					return {};
288 | 				}
289 | 
290 | 				hasTries = gameCount <= 13;
291 | 				if (hasTries) {
292 | 					gameCount++;
293 | 					guessedDigits = game.calculatesGuessedDigits(
294 | 						guessedCode,
295 | 						code
296 | 					);
297 | 					guessedPosition = game.calculateExactPositions(
298 | 						guessedCode,
299 | 						code
300 | 					);
301 | 					hasWon = guessedPosition == length;
302 | 					if (hasWon && level == 2) {
303 | 						gameCount = 420;
304 | 					}
305 | 					console.log(
306 | 						"Digs: " + guessedDigits,
307 | 						"Pos: " + guessedPosition
308 | 					);
309 | 				}
310 | 				socket.emit("singleplayerMediumAnswer", {
311 | 					guessedDigits,
312 | 					guessedPosition,
313 | 					hasTries,
314 | 					hasWon,
315 | 					level,
316 | 				});
317 | 			});
318 | 		}
319 | 	});
320 | 
321 | 	socket.on("playerOneJoin", function (nickname, role) {
322 | 		const roomId = uuid.v4().substr(0, 8);
323 | 		socket.join(roomId);
324 | 
325 | 		if (nickname == "" || role == "") {
326 | 			console.log("User tried to join with no name or role");
327 | 			io.to(socket.id).emit("error", ERROR.NO_NAME_P1);
328 | 			return {};
329 | 		}
330 | 
331 | 		multiGameState[roomId] = {
332 | 			firstPlayer: nickname,
333 | 			firstPlayerRole: role,
334 | 			secondPlayer: null,
335 | 			secondPlayerRole: null,
336 | 			firstPlayerId: socket.id,
337 | 			code: null,
338 | 			progress: GAME_PROGRESS.PREPARE,
339 | 		};
340 | 
341 | 		console.log(
342 | 			`${nickname} who is ${role} has joined in room with id ${roomId}`
343 | 		);
344 | 		console.log(multiGameState);
345 | 		socket.emit("generateId", roomId);
346 | 	});
347 | 
348 | 	socket.on("playerTwoJoin", function (nickname, roomId) {
349 | 		if (nickname == "") {
350 | 			socket.emit("error", ERROR.NO_NAME_P2);
351 | 			return {};
352 | 		}
353 | 		if (roomId != undefined) {
354 | 			console.log(multiGameState[roomId]);
355 | 			if (multiGameState.hasOwnProperty(roomId)) {
356 | 				let players = multiGameState.getUsersByRoles(roomId);
357 | 				if (multiGameState[roomId].secondPlayer == null) {
358 | 					socket.join(roomId);
359 | 					if (
360 | 						multiGameState[roomId].firstPlayer != undefined &&
361 | 						multiGameState[roomId].firstPlayerRole != undefined
362 | 					) {
363 | 						multiGameState[roomId].secondPlayer = nickname;
364 | 						if (
365 | 							multiGameState[roomId].firstPlayerRole == "German"
366 | 						) {
367 | 							multiGameState[roomId].secondPlayerRole = "British";
368 | 						} else {
369 | 							multiGameState[roomId].secondPlayerRole = "German";
370 | 						}
371 | 						multiGameState[roomId].secondPlayerId = socket.id;
372 | 
373 | 						console.log(multiGameState);
374 | 
375 | 						console.log(
376 | 							`${nickname} who is ${multiGameState[roomId].secondPlayerRole} has joind in room with id ${roomId}`
377 | 						);
378 | 
379 | 						socket.broadcast
380 | 							.to(roomId)
381 | 							.emit(
382 | 								"playerJoined",
383 | 								`${nickname} has joined`,
384 | 								multiGameState[roomId]
385 | 							);
386 | 					}
387 | 				} else {
388 | 					socket.emit("error", ERROR.FULL_ROOM);
389 | 				}
390 | 			} else {
391 | 				console.log(`!Room with ID of ${roomId} doesn't exist!`);
392 | 			}
393 | 		}
394 | 	});
395 | 
396 | 	socket.on("startGame", function () {
397 | 		// !Check if id is null
398 | 		let roomId = multiGameState.getRoomIdBySocketId(socket.id);
399 | 		console.log(`startGame: ${roomId}`);
400 | 		if (roomId == null) {
401 | 			console.log(`gameId is null!`);
402 | 			return {};
403 | 		}
404 | 		// !Check if id is null
405 | 		let players = multiGameState.getUsersByRoles(roomId);
406 | 		console.log(`Dumping players object`);
407 | 		console.log(players);
408 | 
409 | 		multiGameState[roomId].progress = GAME_PROGRESS.STARTED;
410 | 		console.log(`Dumping multiGameState object`);
411 | 		console.log(multiGameState);
412 | 
413 | 		console.log(`Emitting gameStatusGerman to ${players.germanPlayerId}`);
414 | 		io.to(players.germanPlayerId).emit(`gameStatusGerman`);
415 | 		console.log(`Emitting gameStatusBritish to ${players.britishPlayerId}`);
416 | 		io.to(players.britishPlayerId).emit(`gameStatusBritish`);
417 | 	});
418 | 
419 | 	socket.on("gameStarted", function () {
420 | 		// !Check if id is null
421 | 		let roomId = multiGameState.getRoomIdBySocketId(socket.id);
422 | 		if (roomId == null) {
423 | 			return {};
424 | 		}
425 | 		// !Check if id is null
426 | 		let players = multiGameState.getUsersByRoles(roomId);
427 | 
428 | 		multiGameState[roomId].progress = GAME_PROGRESS.LEVEL_1;
429 | 
430 | 		io.to(players.germanPlayerId).emit(
431 | 			`displayGerman`,
432 | 			multiGameState[roomId].code
433 | 		);
434 | 		io.to(players.britishPlayerId).emit(`displayBritish`);
435 | 	});
436 | 
437 | 	let gameCountMultiplayer = 1;
438 | 	let hasWonMultiplayer = false;
439 | 	let hasTriesMultiplayer = true;
440 | 	let code2;
441 | 	let guessedDigitsMultiplayer;
442 | 	let exactPositionsMultiplayer;
443 | 
444 | 	socket.on("nextLevelMultiplayer", function (hasWon1) {
445 | 		let roomId = multiGameState.getRoomIdBySocketId(socket.id);
446 | 		if (hasWon1) {
447 | 			multiGameState[roomId].progress = GAME_PROGRESS.LEVEL_2;
448 | 			guessedDigitsMultiplayer = 0;
449 | 			exactPositionsMultiplayer = 0;
450 | 			gameCountMultiplayer = 1;
451 | 			hasWonMultiplayer = false;
452 | 			hasTriesMultiplayer = true;
453 | 		}
454 | 		console.log(multiGameState[roomId].code);
455 | 	});
456 | 
457 | 	let cntCodeSetup = 0;
458 | 
459 | 	socket.on("setupCode", function (code) {
460 | 		// !Check if id is null
461 | 		let roomId = multiGameState.getRoomIdBySocketId(socket.id);
462 | 
463 | 		let players = multiGameState.getUsersByRoles(roomId);
464 | 
465 | 		if (roomId == null) {
466 | 			return {};
467 | 		}
468 | 
469 | 		if (socket.id == players.britishPlayerId) {
470 | 			return {};
471 | 		}
472 | 
473 | 		console.log(multiGameState[roomId].progress);
474 | 
475 | 		if (multiGameState[roomId].progress + 1 == 2) {
476 | 			if (game.checkInput(code)) {
477 | 				multiGameState[roomId].code = code;
478 | 				socket.emit("codeGenerated");
479 | 			} else {
480 | 				socket.emit("error", ERROR.INVALID_CODE_GERMAN);
481 | 			}
482 | 		} else if (multiGameState[roomId].progress == 3) {
483 | 			if (game.checkInputTaskTwo(code)) {
484 | 				multiGameState[roomId].code = code;
485 | 				io.to(players.britishPlayerId).emit(`nextLevelBritish`);
486 | 				io.to(players.germanPlayerId).emit(
487 | 					`levelTwoCode`,
488 | 					multiGameState[roomId].code
489 | 				);
490 | 			} else {
491 | 				io.to(players.germanPlayerId).emit(
492 | 					"error",
493 | 					ERROR.INVALID_CODE_GERMAN
494 | 				);
495 | 			}
496 | 		}
497 | 	});
498 | 
499 | 	socket.on("inputCode", function (britishCode) {
500 | 		let roomId = multiGameState.getRoomIdBySocketId(socket.id);
501 | 		if (roomId == null) {
502 | 			return {};
503 | 		}
504 | 
505 | 		let players = multiGameState.getUsersByRoles(roomId);
506 | 
507 | 		if (socket.id != players.britishPlayerId) {
508 | 			return {};
509 | 		}
510 | 
511 | 		if (!britishCode || britishCode.length != 4) {
512 | 			console.log(`Invalid request: !${britishCode}!`);
513 | 			socket.emit("error", ERROR.INVALID_CODE_BRITISH);
514 | 			return {};
515 | 		}
516 | 
517 | 		guessedDigitsMultiplayer = game.calculatesGuessedDigits(
518 | 			britishCode,
519 | 			multiGameState[roomId].code
520 | 		);
521 | 
522 | 		exactPositionsMultiplayer = game.calculateExactPositions(
523 | 			britishCode,
524 | 			multiGameState[roomId].code
525 | 		);
526 | 
527 | 		hasTriesMultiplayer = gameCountMultiplayer <= 13;
528 | 		if (hasTriesMultiplayer) {
529 | 			gameCountMultiplayer++;
530 | 			hasWonMultiplayer = exactPositionsMultiplayer == 4;
531 | 			if (hasWonMultiplayer && multiGameState[roomId].progress == 3) {
532 | 				gameCountMultiplayer = 420;
533 | 			}
534 | 			console.log(
535 | 				"Digs: " + guessedDigitsMultiplayer,
536 | 				"Pos: " + exactPositionsMultiplayer + " " + hasWonMultiplayer
537 | 			);
538 | 		}
539 | 		console.log(multiGameState[roomId].progress);
540 | 		io.to(players.germanPlayerId).emit(
541 | 			`resultGerman`,
542 | 			britishCode,
543 | 			guessedDigitsMultiplayer,
544 | 			exactPositionsMultiplayer,
545 | 			hasTriesMultiplayer,
546 | 			hasWonMultiplayer,
547 | 			multiGameState[roomId].progress
548 | 		);
549 | 
550 | 		io.to(players.britishPlayerId).emit(
551 | 			`guessBritish`,
552 | 			britishCode,
553 | 			guessedDigitsMultiplayer,
554 | 			exactPositionsMultiplayer,
555 | 			hasTriesMultiplayer,
556 | 			hasWonMultiplayer,
557 | 			multiGameState[roomId].progress
558 | 		);
559 | 	});
560 | 
561 | 	socket.on("disconnect", function () {
562 | 		let roomId = multiGameState.getRoomIdBySocketId(socket.id);
563 | 		delete multiGameState[roomId];
564 | 		console.log(multiGameState);
565 | 
566 | 		io.to(roomId).emit("gameCrash");
567 | 	});
568 | });
569 | 
570 |
571 |
572 | 573 | 574 | 575 | 576 |
577 | 578 | 581 | 582 |
583 | 584 |
585 | Documentation generated by JSDoc 3.6.6 on Tue Jan 12 2021 22:48:58 GMT+0200 (Eastern European Standard Time) 586 |
587 | 588 | 589 | 590 | 591 | 592 | -------------------------------------------------------------------------------- /public/js/translate.js: -------------------------------------------------------------------------------- 1 | var textTranslation = { 2 | "navGame": { 3 | en: `Game`, 4 | 5 | bg: `Игра`, 6 | }, 7 | 8 | "navSingleplayer": { 9 | en: `Single Player`, 10 | bg: `Самостоятелна игра`, 11 | }, 12 | 13 | "navMultiplayer": { 14 | en: `Multiplayer`, 15 | 16 | bg: `Игра с приятел`, 17 | }, 18 | 19 | "navRules": { 20 | en: `Rules`, 21 | 22 | bg: `Правила`, 23 | }, 24 | 25 | "navAbout": { 26 | en: `About`, 27 | 28 | bg: `Информация`, 29 | }, 30 | 31 | "navAboutTeam": { 32 | en: `About Team`, 33 | 34 | bg: `За отбора`, 35 | }, 36 | 37 | "navDocumentation": { 38 | en: `Documentation`, 39 | 40 | bg: `Документация`, 41 | }, 42 | 43 | "navLanguage": { 44 | en: `Language`, 45 | 46 | bg: `Език`, 47 | }, 48 | 49 | "btnEn": { 50 | en: `English`, 51 | 52 | bg: `Английски`, 53 | }, 54 | 55 | "btnBg": { 56 | en: `Bulgarian`, 57 | 58 | bg: `Български`, 59 | }, 60 | 61 | "navContact": { 62 | en: `Contact`, 63 | 64 | bg: `Контакт`, 65 | }, 66 | 67 | "welcomeText": { 68 | en: `Welcome to Bletchley Game`, 69 | 70 | bg: `Добре дошли в Bletchley Game`, 71 | }, 72 | 73 | "teamText": { 74 | en: `By Team Crypto Zargan`, 75 | 76 | bg: `От отбор Крипто Зарган`, 77 | }, 78 | 79 | "indexSingleplayer": { 80 | en: `Single Player`, 81 | 82 | bg: `Самостоятелна игра`, 83 | }, 84 | 85 | "indexMultiplayer": { 86 | en: `Multiplayer`, 87 | 88 | bg: `Игра с приятел`, 89 | }, 90 | 91 | "contact": { 92 | en: `Contact Page`, 93 | 94 | bg: `Страница за контакт`, 95 | }, 96 | 97 | "aboutTeam": { 98 | en: `About Team Page`, 99 | 100 | bg: `Страница за отбора`, 101 | }, 102 | 103 | "aboutProject": { 104 | en: `About Project Page`, 105 | 106 | bg: `Страница за проекта`, 107 | }, 108 | 109 | "singleplayer": { 110 | en: `Single Player Mode`, 111 | 112 | bg: `Самостоятелна игра`, 113 | }, 114 | 115 | "play": { 116 | en: `Play`, 117 | 118 | bg: `Играй`, 119 | }, 120 | 121 | "difficultyEasy": { 122 | en: `Easy`, 123 | 124 | bg: `Лесно`, 125 | }, 126 | 127 | "difficultyMedium": { 128 | en: `Medium`, 129 | 130 | bg: `Нормално`, 131 | }, 132 | 133 | "difficultyHard": { 134 | en: `Hard`, 135 | 136 | bg: `Трудно`, 137 | }, 138 | 139 | "levelOne": { 140 | en: `You completed level 1. Are you ready to continue?`, 141 | 142 | bg: `Ти мина първото ниво. Готов ли си да продължиш?`, 143 | }, 144 | 145 | "nextLevel": { 146 | en: `Next Task`, 147 | 148 | bg: `Следваща мисия`, 149 | }, 150 | 151 | "surrender": { 152 | en: `Surrender`, 153 | 154 | bg: `Предаване`, 155 | }, 156 | 157 | "home": { 158 | en: `Home`, 159 | 160 | bg: `Начална страница`, 161 | }, 162 | 163 | "playAgain": { 164 | en: `Play Again`, 165 | 166 | bg: `Играй отново`, 167 | }, 168 | 169 | "win": { 170 | en: `You win!`, 171 | 172 | bg: `Ти печелиш!`, 173 | }, 174 | 175 | "lose": { 176 | en: `You lose!`, 177 | 178 | bg: `Ти загуби!`, 179 | }, 180 | 181 | "guessedDigigits": { 182 | en: `Guessed Digits`, 183 | 184 | bg: `Познати числа`, 185 | }, 186 | 187 | "guessedPos": { 188 | en: `Guessed Positions`, 189 | 190 | bg: `Познати позиции`, 191 | }, 192 | 193 | "guessedNum": { 194 | en: `Number`, 195 | 196 | bg: `Число`, 197 | }, 198 | 199 | "opening": { 200 | en: `Multiplayer Mode`, 201 | 202 | bg: `Игра с приятел`, 203 | }, 204 | 205 | "winner": { 206 | en: `British wins!`, 207 | 208 | bg: `Британеца печели!`, 209 | }, 210 | 211 | "create": { 212 | en: `Create Game`, 213 | 214 | bg: `Създай игра`, 215 | }, 216 | 217 | "join": { 218 | en: `Join Game`, 219 | 220 | bg: `Присъедини се в игра`, 221 | }, 222 | 223 | "sendCode": { 224 | en: `Send this code to your friend and play together`, 225 | 226 | bg: `Прати кода на твоя приятел и играйте заедно`, 227 | }, 228 | 229 | "username": { 230 | en: `Username:`, 231 | 232 | bg: `Потребителско име:`, 233 | }, 234 | 235 | "role": { 236 | en: `Role:`, 237 | 238 | bg: `Роля:`, 239 | }, 240 | 241 | "german": { 242 | en: `German`, 243 | 244 | bg: `Германец`, 245 | }, 246 | 247 | "british": { 248 | en: `British`, 249 | 250 | bg: `Британец`, 251 | }, 252 | 253 | "guessCode": { 254 | en: `Guess Code`, 255 | 256 | bg: `Познай кода`, 257 | }, 258 | 259 | "createCode": { 260 | en: `Create code`, 261 | 262 | bg: `Създай кода`, 263 | }, 264 | 265 | "code": { 266 | en: `Code: `, 267 | 268 | bg: `Код: `, 269 | }, 270 | 271 | "guessedDigits": { 272 | en: `Guessed Digits`, 273 | 274 | bg: `Познати цифри`, 275 | }, 276 | 277 | "guessedPositions": { 278 | en: `Guessed Positions`, 279 | 280 | bg: `Познати позиции`, 281 | }, 282 | 283 | "britishCode": { 284 | en: `Number`, 285 | 286 | bg: `Число`, 287 | }, 288 | 289 | "levelOneWin": { 290 | en: `Congratulations you completed level 1`, 291 | 292 | bg: `Поздравления ти завърши първо ниво`, 293 | }, 294 | 295 | "waitForLevelTwo": { 296 | en: `Waiting for your friend to start level 2`, 297 | 298 | bg: `Изчакай приятеля си да стартира второ ниво`, 299 | }, 300 | 301 | "waitCreateCode": { 302 | en: `Waiting for your friend to create the code`, 303 | 304 | bg: `Изчакай приятеля си да напише кода`, 305 | }, 306 | 307 | "waitStartGame": { 308 | en: `Waiting for your friend to start the game`, 309 | 310 | bg: `Изчакай приятеля си да стартира игра`, 311 | }, 312 | 313 | "download": { 314 | en: `Download the full rules here`, 315 | 316 | bg: `Изтегли правилата от тук`, 317 | }, 318 | 319 | "crackButton": { 320 | en: `Crack`, 321 | 322 | bg: `Разбий`, 323 | }, 324 | 325 | "singleplayerRules": { 326 | en: `In the single player mode of the game you play against the computer. To find out the coordinates of the enemy battleships 327 | you have to crack 2 codes - generated by a computer. The numbers must be with the numbers form 0 to 7 including. 328 | There are 3 difficulties: 329 |
    330 |
  • Easy - You have to crack a 3-number code
  • 331 |
  • Medium - You have to crack a 4-number code
  • 332 |
  • Hard - You have to crack a 5-number code
  • 333 |
334 | There are also 2 tasks: 335 |
    336 |
  • First task – On the first task the numbers cannot be repeated
  • 337 |
  • Second task – On the second task the numbers can be repeated.
  • 338 |
339 | You have 13 attempts to guess the number, otherwise you lose.`, 340 | 341 | bg: `Във самостоятелния режим на играта вие играете срещу компютър. За да разберете 342 | координатите на вражеския кораб трябва да разбиете 2 кода, които са генерирани от компютър. 343 | Цифрите на кода са между 0 и 7 включително. 344 | Играта има 3 нива на трудност: 345 |
    346 |
  • Лесно - Трябва да се разбие 3-цифрен код
  • 347 |
  • Средно - Трябва да се разбие 4-цифрен код
  • 348 |
  • Трудно - Трябва да се разбие 5-цифрен код
  • 349 |
350 | Във 2-те задачи кодовете ще бъдат генерирани по различен начин. 351 |
    352 |
  • Първа задача - Кодът не може да има повтарящи се чифри.
  • 353 |
  • Втора задача - Кодът може да има повтарящи се чифри.
  • 354 |
355 | Имате 13 опита, за да познаете координатите на вражеския кораб, в противен случай ще загубите.`, 356 | }, 357 | 358 | "multiplayerRules": { 359 | en: ` In the multiplayer mode of the game 2 people can play against each other.
One person creates a room and 360 | gives the code that was given to him so that the other one can join it. The numbers must be with the numbers form 0 to 7 including.
The person who creates the 361 | room can 362 | choose his role. There are 2 different roles: 363 |
    364 |
  • German – If you choose to be German you create the code. Your task is the code 365 | to be hard so that the British cannot defeat you easy.
  • 366 |
  • British – Or if you choose to be the British you are guessing the code that was 367 | created by the German. You have 13 attempts to guess the code.
  • 368 |
369 | There are also 2 tasks: 370 |
    371 |
  • First task – On the first task the numbers cannot be repeated
  • 372 |
  • Second task – On the second task the numbers can be repeated.
  • 373 |
`, 374 | 375 | bg: `В груповия режима на играта 2-ма човека вие може ад играете един срещу друг. Единия от двамата прави стая и дава 376 | кода за нея на другия, койото го въвжеда 377 | Този който прави стаята може да си избере каква роля да е, а другият ще е другата. 378 | Двете различни роли на играта са: 379 |
    380 |
  • Германец - Ако изберете да сте германец, ролята ви е да създадете кода, който трябва да 381 | бъде възможно най-труден, за да може вашият кораб да не бъде разбит
  • 382 |
  • Британец - Ако изберете да сте британец, ролята ви е да разбиете кода създаден от 383 | германеца. Така вие ще унищожите неговият кораб
  • 384 |
385 | Кода който създава германеца трябва да е с цифрите от 0 до 7 включително. Има и 2 различни задачи, които имат следните условия: 386 |
    387 |
  • Първа задача - Кодът не може да има повтарящи се чифри.
  • 388 |
  • Втора задача - Кодът може да има повтарящи се чифри.
  • 389 |
`, 390 | }, 391 | 392 | "name": { 393 | en: `Name`, 394 | 395 | bg: `Име`, 396 | }, 397 | 398 | "email": { 399 | en: `Email`, 400 | 401 | bg: `Имейл`, 402 | }, 403 | 404 | "subject": { 405 | en: `Subject`, 406 | 407 | bg: `Тема`, 408 | }, 409 | 410 | "message": { 411 | en: `Message`, 412 | 413 | bg: `Съобщение`, 414 | }, 415 | 416 | "contactSubmit": { 417 | en: `Submit`, 418 | 419 | bg: `Предай`, 420 | }, 421 | 422 | "meetTheTeam": { 423 | en: `Meet The Team`, 424 | 425 | bg: `Запознайте се с отбора ни`, 426 | }, 427 | 428 | "nameIvelin": { 429 | en: `Ivelin Bachvarov`, 430 | 431 | bg: `Ивелин Бъчваров`, 432 | }, 433 | 434 | "roleIvelin": { 435 | en: `SCRUM Master`, 436 | 437 | bg: `SCRUM Мастър`, 438 | }, 439 | 440 | "nameIliyan": { 441 | en: `Iliyan Iliev`, 442 | 443 | bg: `Илиян Илиев`, 444 | }, 445 | 446 | "roleIliyan": { 447 | en: `Back-end Developer`, 448 | 449 | bg: `Back-end разработчик`, 450 | }, 451 | 452 | "nameMario": { 453 | en: `Mario Slavov`, 454 | 455 | bg: `Марио Славов`, 456 | }, 457 | 458 | "roleMario": { 459 | en: `Documentary / Front-end Developer`, 460 | 461 | bg: `Документация / Front-end разработчик`, 462 | }, 463 | 464 | "nameStoyan": { 465 | en: `Stoyan Kolev`, 466 | 467 | bg: `Стоян Колев`, 468 | }, 469 | 470 | "roleStoyan": { 471 | en: `QA Engineer`, 472 | 473 | bg: `QA Инжинер`, 474 | }, 475 | 476 | "nameGeorgi": { 477 | en: `Georgi Georgiev`, 478 | 479 | bg: `Георги Георгиев`, 480 | }, 481 | 482 | "roleGeorgi": { 483 | en: `Code Checker / Front-end Developer`, 484 | 485 | bg: `Проверка на кода / Front-end разработчик`, 486 | }, 487 | 488 | "nameEmil": { 489 | en: `Emil Ribarev`, 490 | 491 | bg: `Емил Рибарев`, 492 | }, 493 | 494 | "roleEmil": { 495 | en: `Back-end Developer / GitHub Wizard`, 496 | 497 | bg: `Back-end разработчик / GitHub магьосник`, 498 | }, 499 | 500 | "contactUsernamePlaceholder": { 501 | en: ` 502 | `, 510 | 511 | bg: ` 512 | 520 | `, 521 | }, 522 | 523 | "contactEmaiPlaceholder": { 524 | en: ` `, 532 | 533 | bg: ``, 541 | }, 542 | 543 | "contactSubjectPlaceholder": { 544 | en: ` 545 | `, 553 | 554 | bg: ``, 562 | }, 563 | 564 | "contactMessagePlaceholder": { 565 | en: ``, 573 | 574 | bg: ``, 582 | }, 583 | 584 | 585 | 586 | "contactUsernamePlaceholderSing": { 587 | en: ` `, 595 | 596 | bg: ` `, 604 | }, 605 | 606 | "rules": { 607 | en: `Rules`, 608 | 609 | bg: `Правила`, 610 | }, 611 | 612 | "multiplayerWin": { 613 | en: `You Win!`, 614 | 615 | bg: `Ти спечели!`, 616 | }, 617 | 618 | "multiplayerLose": { 619 | en: `You Lose!`, 620 | 621 | bg: `Ти загуби!`, 622 | }, 623 | 624 | "multiplayerNickname": { 625 | en: `Nickname`, 626 | 627 | bg: `Име`, 628 | }, 629 | 630 | "multiplayerNicknamePlaceholder": { 631 | en: ``, 640 | 641 | bg: ``, 650 | }, 651 | 652 | "multiplayerRole": { 653 | en: `Role`, 654 | 655 | bg: `Роля`, 656 | }, 657 | 658 | "multiplayerPlayButton": { 659 | en: `Play`, 660 | 661 | bg: `Играй`, 662 | }, 663 | 664 | "multiplayerNicknameTwo": { 665 | en: `Nickname`, 666 | 667 | bg: `Име`, 668 | }, 669 | 670 | "multiplayerNicknameTwoPlaceholder": { 671 | en: ``, 679 | 680 | bg: ``, 688 | }, 689 | 690 | "gameIdMultiplayer": { 691 | en: `Game ID`, 692 | 693 | bg: `Код на играта`, 694 | }, 695 | 696 | "multiplayerIdPlaceholder": { 697 | en: ``, 705 | 706 | bg: ``, 714 | }, 715 | 716 | "copyButton": { 717 | en: `Copy`, 718 | 719 | bg: `Копирай`, 720 | }, 721 | 722 | "": { 723 | en: ``, 724 | 725 | bg: ``, 726 | }, 727 | 728 | "": { 729 | en: ``, 730 | 731 | bg: ``, 732 | }, 733 | 734 | "": { 735 | en: ``, 736 | 737 | bg: ``, 738 | }, 739 | 740 | "": { 741 | en: ``, 742 | 743 | bg: ``, 744 | }, 745 | 746 | "multiplayerGuessCodeButton": { 747 | en: `Guess Code`, 748 | 749 | bg: `Познай кода`, 750 | }, 751 | 752 | "multiplayerCreateCodeButton": { 753 | en: `Create Code`, 754 | 755 | bg: `Създай код`, 756 | }, 757 | 758 | "startGame": { 759 | en: `Start Game`, 760 | 761 | bg: `Започни игра`, 762 | }, 763 | 764 | "otherPlayerLeft": { 765 | en: `The other player left the game`, 766 | 767 | bg: `Другият играч е излязал от играта`, 768 | } 769 | 770 | }; 771 | 772 | var currentLanguage = "en"; 773 | 774 | /** 775 | * Replaces the text on the page with the chosen language. 776 | * 777 | * @param {string} item The item that has to be replaced. 778 | * @param {string} text The text that the item is going to be replaced with. 779 | */ 780 | function replaceElementText(item, text) { 781 | if (!item.is("button")) { 782 | item.html(text); 783 | } else { 784 | item.text(text); 785 | } 786 | } 787 | 788 | /** 789 | * Translates the elements with the data-lang attribute. 790 | * 791 | * @param {string} langId The identificator of the language (bg/en). 792 | */ 793 | function translateLabel(langId) { 794 | console.log(langId); 795 | currentLanguage = langId; 796 | 797 | // Gets all tags that have 'data-lang' attribute present 798 | $("[data-lang]").each(function () { 799 | let item = $(this); 800 | if ( 801 | textTranslation.hasOwnProperty(item.data("lang")) && 802 | textTranslation[item.data("lang")].hasOwnProperty(langId) 803 | ) { 804 | let text = textTranslation[item.data("lang")][langId]; 805 | replaceElementText(item, text); 806 | } else { 807 | replaceElementText( 808 | item, 809 | "" + item.data("lang") + "" 810 | ); 811 | } 812 | }); 813 | } 814 | 815 | /** 816 | * Gets the translated elements. 817 | * 818 | * @param {string} elementId The element's Id. 819 | * @return {string} textTranslation The translated text. 820 | */ 821 | function getTranslatedText(elementId) { 822 | return textTranslation[elementId][currentLanguage]; 823 | } 824 | -------------------------------------------------------------------------------- /public/multiplayer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Multiplayer 7 | 8 | 9 | 10 | 16 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 136 | 137 |
138 |
142 |

143 | Multiplayer Mode 144 |

145 | 146 |

147 | You Win 148 |

149 | 150 |

151 | You Lose 152 |

153 | 154 |
155 | 162 | 169 | 170 | 177 | Rules 178 | 179 |
180 | 181 | 196 | 197 |
198 | 248 |
249 | 250 |
251 | 303 |
304 | 305 |
306 | 364 | 365 |
366 | 424 |
425 | 426 |
427 | 486 | 487 | 501 | 502 | 510 | 511 | 523 | 524 | 536 | 537 | 542 | 543 | 555 | 556 | 595 | 596 | 609 | 610 | 615 | 616 | 619 | 620 | 623 | 624 | 631 | 632 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 |
647 |
648 |
649 | 650 | 655 | 656 | 657 | 658 | 659 | 669 | 670 | 671 | --------------------------------------------------------------------------------