├── src
├── images
│ ├── 0.png
│ ├── 1.png
│ ├── 2.png
│ ├── 3.png
│ ├── 4.png
│ ├── 5.png
│ └── 6.png
├── App.test.js
├── components
│ ├── streak.js
│ ├── Next.js
│ ├── Letter.js
│ ├── Output.js
│ ├── Answer.js
│ ├── Letters.js
│ ├── hangman-figure.js
│ └── words.js
├── index.js
├── registerServiceWorker.js
└── App.js
├── public
├── favicon.ico
├── manifest.json
├── index.html
└── style
│ └── style.css
├── .gitignore
├── package.json
└── README.md
/src/images/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djbarnwal/hangman/HEAD/src/images/0.png
--------------------------------------------------------------------------------
/src/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djbarnwal/hangman/HEAD/src/images/1.png
--------------------------------------------------------------------------------
/src/images/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djbarnwal/hangman/HEAD/src/images/2.png
--------------------------------------------------------------------------------
/src/images/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djbarnwal/hangman/HEAD/src/images/3.png
--------------------------------------------------------------------------------
/src/images/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djbarnwal/hangman/HEAD/src/images/4.png
--------------------------------------------------------------------------------
/src/images/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djbarnwal/hangman/HEAD/src/images/5.png
--------------------------------------------------------------------------------
/src/images/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djbarnwal/hangman/HEAD/src/images/6.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djbarnwal/hangman/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/streak.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | const Output = (props) => {
5 |
6 | return (
7 |
8 | Streak: {props.streak}
9 |
10 | );
11 | };
12 |
13 | export default Output;
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import registerServiceWorker from './registerServiceWorker';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 | registerServiceWorker();
8 |
--------------------------------------------------------------------------------
/src/components/Next.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Next = (props) => {
4 | if(props.gameStatus > 0 && props.answerList.length) {
5 | return (
6 | props.nextWord()} className='nextButton'>
7 | Next
8 |
9 | );
10 | }
11 | return ;
12 | }
13 |
14 | export default Next;
15 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Hangman",
3 | "name": "Play Hangman",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#fefefe",
14 | "background_color": "#232222"
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # See https://help.github.com/ignore-files/ for more about ignoring files.
3 |
4 | # dependencies
5 | /node_modules
6 |
7 | # testing
8 | /coverage
9 |
10 | # production
11 | /build
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 | *.db
24 |
25 |
--------------------------------------------------------------------------------
/src/components/Letter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Letter = (props) => {
4 | if ( props.pickedArray.indexOf(props.alpha) > -1 || props.gameStatus > 0 ) {
5 | return (
6 |
7 | {props.alpha}
8 |
9 | );
10 | }
11 | return (
12 | props.addAlphas(props.alpha)}>
13 | {props.alpha}
14 |
15 | );
16 | };
17 |
18 | export default Letter;
19 |
--------------------------------------------------------------------------------
/src/components/Output.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | let output;
4 | const Output = (props) => {
5 | if(!props.gameStatus) output = "The Game is on let's play";
6 | if(props.gameStatus === 1) output = "YOU WIN!!";
7 | if(props.gameStatus === 2) {
8 | output = `YOU LOSE! The word was ${props.answer}`;
9 | }
10 | return (
11 |
12 | {output}
13 |
14 | );
15 | };
16 |
17 | export default Output;
18 |
--------------------------------------------------------------------------------
/src/components/Answer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Answer = (props) => {
4 | let answer = props.answer.word;
5 | const hint = props.answer.hint;
6 | let pick = props.pickedArray;
7 |
8 | let guess = pick.join('');
9 | let regexp = new RegExp('[^' + guess + ']','g');
10 | let underscore = answer.replace(regexp, '_');
11 |
12 |
13 | return (
14 |
15 |
16 | {underscore}
17 |
18 |
19 | {hint}
20 |
21 |
22 | );
23 | };
24 |
25 | export default Answer;
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hangman",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "https://dhiraj161298.github.io/hangman",
6 | "dependencies": {
7 | "react": "^15.5.4",
8 | "react-dom": "^15.5.4"
9 | },
10 | "devDependencies": {
11 | "gh-pages": "^1.0.0",
12 | "react-scripts": "1.0.7"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test --env=jsdom",
18 | "eject": "react-scripts eject",
19 | "predeploy": "npm run build",
20 | "deploy": "gh-pages -d build"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/Letters.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Letter from './Letter';
3 |
4 | const Letters = (props) => {
5 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
6 | let chars = characters.split('');
7 |
8 | chars = chars.map((character, i) => {
9 | return (
10 |
16 | );
17 | });
18 |
19 | return (
20 |
25 | );
26 | };
27 |
28 | export default Letters;
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Play Hangman
2 | https://djbarnwal.github.io/hangman/
3 | The traditional hangman puzzle game developed using ReactJS.
4 |
5 | ## Requirements for Development
6 |
7 | - `React`
8 | - `npm`
9 |
10 | ## Setup for Development
11 |
12 | - `git clone https://github.com/djbarnwal/hangman.git`
13 | - `cd hangman`
14 | - `npm install`
15 | - `npm start`
16 |
17 | ## Git Flow
18 |
19 | To submit a PR:
20 | - Create a feature branch in this repo (or your own fork if you don't have appropriate permissions)
21 | - Once the feature is ready, open a pull request against the `master` branch
22 |
23 | ## Things to Do
24 | 1. Add more categories
25 | 2. Add a better hangman figure
26 | 3. Add leaderboard
27 | 4. Make Hangman creator
28 |
--------------------------------------------------------------------------------
/src/components/hangman-figure.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | //Import all images
4 | const images = importAll(require.context('../images', false, /\.(png|jpe?g|svg)$/));
5 |
6 | let imgArray = [];
7 |
8 | class Hangman extends Component {
9 |
10 | componentWillMount() {
11 | for(let i=0; i<=6; i++) {
12 | imgArray.push(
);
13 | }
14 | }
15 |
16 | showHangman() {
17 | let output = imgArray.slice(0, this.props.incorrectPicks+1);
18 | return output;
19 | }
20 |
21 | render() {
22 | return (
23 |
24 | {this.showHangman()}
25 |
26 | );
27 | }
28 | }
29 |
30 | export default Hangman;
31 |
32 | function importAll(r) {
33 | let images = {};
34 | r.keys().map((item, index) => {
35 | images[item.replace('./', '')] = r(item);
36 | return null;
37 | });
38 | return images;
39 | }
40 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Play Hangman
12 |
13 |
14 |
17 |
18 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/components/words.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {word: "Machaya", hint:"To do something great"},
3 | {word: "Makhaya", hint:"To do a task poorly"},
4 | {word: "Insti Top", hint:"Highest point of KGP"},
5 | {word: "Gol C", hint:"Here stands BC Roy"},
6 | {word: "Bhaat", hint:"A local meetup"},
7 | {word: "Maggu", hint:"A special kind of species with just one goal"},
8 | {word: "Rassa", hint:"They often conduct strikes in campus :P"},
9 | {word: "Matka", hint:"Not a UG, not a scholar"},
10 | {word: "Dassi", hint:"Academic gods"},
11 | {word: "Peace", hint:"The most famous one"},
12 | {word: "Illumination", hint:"Lights."},
13 | {word: "Happa", hint:"Hall president"},
14 | {word: "Tempo Shout", hint:"We don't scream we have ____"},
15 | {word: "Chaggi", hint:"Probably the most common CG"},
16 | {word: "Panji", hint:"He is a dude"},
17 | {word: "Faccha", hint:"The noobs of KGP"},
18 | {word: "Frustapa", hint:"Anxiety and annoyance for a KGPian"},
19 | {word: "Bhajan", hint:"60% of DC searches"},
20 | {word: "Funda", hint:"the basic principle behind something"},
21 | {word: "Geez", hint:"eating someone's stuff as of its own"},
22 | {word: "Load", hint:"To Have Tension"},
23 | {word: "Fakka", hint:"An F-grade in any subject"},
24 | {word: "Lodu", hint:"A person who takes lot of load"},
25 | {word: "Banda", hint:"Any Boy"},
26 | {word: "Bhaatu", hint:"A person who is very talkative"},
27 | {word: "Archi", hint:"The Architecture Department"},
28 | {word: "Taapna", hint:" Copying assignments or examination answer-scripts from any person"},
29 | {word: "Makhana", hint:"To spoil a job"},
30 | {word: "Stud", hint:"Any student who is good in academics as well as other fields like sports"},
31 | {word: "Bandi", hint:"Any girl"},
32 | {word: "Batti", hint:"The Electrical Engineering Department"},
33 | {word: "Hathora", hint:"The Mechanical Engineering Department"},
34 | {word: "Junta", hint:"The human population"},
35 | {word: "Chhedis", hint:"A dhaba just outside campus"},
36 | {word: "Atthi", hint:"A C.G.P.A. in between 8 and 9"},
37 | {word: "Nehli", hint:"A C.G.P.A. greater than 9"},
38 | {word: "Panji", hint:"A C.G.P.A. in between 5 and 6"},
39 | {word: "Bhaat", hint:"Bekar Chat"},
40 | {word: "Ghaasi", hint:"A student of Agriculture Engineering Department"},
41 | ];
42 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | export default function register() {
12 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
13 | window.addEventListener('load', () => {
14 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
15 | navigator.serviceWorker
16 | .register(swUrl)
17 | .then(registration => {
18 | registration.onupdatefound = () => {
19 | const installingWorker = registration.installing;
20 | installingWorker.onstatechange = () => {
21 | if (installingWorker.state === 'installed') {
22 | if (navigator.serviceWorker.controller) {
23 | // At this point, the old content will have been purged and
24 | // the fresh content will have been added to the cache.
25 | // It's the perfect time to display a "New content is
26 | // available; please refresh." message in your web app.
27 | console.log('New content is available; please refresh.');
28 | } else {
29 | // At this point, everything has been precached.
30 | // It's the perfect time to display a
31 | // "Content is cached for offline use." message.
32 | console.log('Content is cached for offline use.');
33 | }
34 | }
35 | };
36 | };
37 | })
38 | .catch(error => {
39 | console.error('Error during service worker registration:', error);
40 | });
41 | });
42 | }
43 | }
44 |
45 | export function unregister() {
46 | if ('serviceWorker' in navigator) {
47 | navigator.serviceWorker.ready.then(registration => {
48 | registration.unregister();
49 | });
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/public/style/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #232222 none repeat scroll 0 0;
3 | color: #fefefe;
4 | font-family: Verdana;
5 | -moz-user-select: none;
6 | -webkit-user-select: none;
7 | }
8 |
9 | .container {
10 | text-align: center;
11 | }
12 |
13 | .figureWrapper {
14 | display: inline-block;
15 | }
16 |
17 | .answerWrapper {
18 | display: inline-block;
19 | width: 60%;
20 | }
21 |
22 | .title {
23 | font-size: 30px;
24 | margin: 2em 0;
25 | }
26 |
27 | .info {
28 | margin-top: 10px;
29 | color: #555;
30 | }
31 |
32 | .hangman {
33 | height: 350px;
34 | margin-top: 20px;
35 | position: relative;
36 | width: 350px;
37 | }
38 |
39 | .hangman img {
40 | position: absolute;
41 | left: 0;
42 | height: 350px;
43 | }
44 |
45 | .output {
46 | background: #fefefe;
47 | color: #232222;
48 | display: inline-block;
49 | padding: 4px 10px;
50 | }
51 |
52 | .answer-box {
53 | font-size: 50px;
54 | letter-spacing: 20px;
55 | margin-top: 30px;
56 | }
57 |
58 | .letters ul {
59 | margin: 0 auto;
60 | width: 75%;
61 | margin-top: 25px;
62 | padding: 0;
63 | }
64 |
65 | .letters ul li {
66 | background: #fbf9f9;
67 | border-radius: 3px;
68 | color: #222;
69 | cursor: pointer;
70 | display: inline-block;
71 | height: 20px;
72 | margin:3px;
73 | padding: 8px;
74 | width: 30px;
75 | transition: background-color ease 0.2s;
76 | }
77 |
78 | .letters ul li:hover {
79 | background: #F7DE31;
80 | }
81 |
82 | .letters ul .picked {
83 | background: #423F40;
84 | color: #212121;
85 | cursor: default;
86 | }
87 |
88 | .letters ul .picked:hover {
89 | background: #423F40;
90 | }
91 |
92 | .nextButton {
93 | border: 1px solid #eee;
94 | border-radius: 5px;
95 | display: inline-block;
96 | margin-top: 25px;
97 | padding: 10px 40px;
98 | transition: all 0.3s ease 0s;
99 | cursor: pointer;
100 | }
101 |
102 | .nextButton:hover {
103 | background: #fefefe;
104 | color: #222;
105 | }
106 |
107 | .hint, .streak {
108 | margin-top: 15px;
109 | }
110 |
111 | @media only screen and (max-width: 890px) {
112 | .title {
113 | margin: 0.3em 0;
114 | }
115 | .answerWrapper {
116 | width: 100%;
117 | margin-top: 2em;
118 | }
119 | .answer-box {
120 | font-size: 22px;
121 | letter-spacing: 10px;
122 | margin-top: 30px;
123 | }
124 | .hangman img, .hangman {
125 | height: 250px;
126 | }
127 | .hangman {
128 | width: 225px;
129 | }
130 | .letters ul {
131 | width: 90%;
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Hangman from './components/hangman-figure';
3 | import Answer from './components/Answer';
4 | import Output from './components/Output';
5 | import Letters from './components/Letters';
6 | import Next from './components/Next';
7 | import Streak from './components/streak';
8 | import words from './components/words';
9 |
10 | class App extends Component {
11 | constructor(props) {
12 | super(props);
13 | let answerList = words;
14 | // Shuffle the array
15 | answerList.sort(function() { return 0.5 - Math.random() });
16 | const answer = answerList.pop();
17 | answer.word = answer.word.toUpperCase();
18 |
19 | this.state = {
20 | picked: [" "],
21 | incorrectPicks: 0,
22 | answerList,
23 | answer,
24 | gameStatus: 0, // 0 - play, 1 - won, 2 - lost
25 | streak: 0,
26 | };
27 |
28 | this.addAlphas = this.addAlphas.bind(this);
29 | this.nextWord = this.nextWord.bind(this);
30 | }
31 |
32 | addAlphas(alpha) {
33 | let alphaList = this.state.picked;
34 | alphaList.push(alpha);
35 | this.setState({picked: alphaList}, () => {
36 | let word = this.state.answer.word.replace(new RegExp('[^' + this.state.picked + ']','g'), '-');
37 | if(word.indexOf('-') === -1) {
38 | this.setState({
39 | gameStatus: 1,
40 | streak: this.state.streak + 1
41 | })
42 | }
43 | });
44 |
45 | // Adding if statement and the regex as the else part in the above callback
46 | // will make the process slow. In the current setup we add regex for every
47 | // alphabet added increasing the number of cases. Find optimal way.
48 |
49 | if(this.state.answer.word.indexOf(alpha) === -1) {
50 | this.setState({incorrectPicks: (this.state.incorrectPicks + 1)}, () => {
51 | if(this.state.incorrectPicks === 6) {
52 | this.setState({
53 | gameStatus: 2,
54 | streak: 0,
55 | })
56 | }
57 | });
58 | }
59 | }
60 |
61 | nextWord() {
62 | const answer = this.state.answerList.pop();
63 | answer.word = answer.word.toUpperCase();
64 | this.setState({
65 | picked: [" "],
66 | incorrectPicks: 0,
67 | answer,
68 | gameStatus: 0,
69 | });
70 | }
71 |
72 | render() {
73 | return (
74 |
75 |
Hangman Game
76 |
77 |
80 |
81 |
82 |
86 |
90 |
(All words are from KGP lingo)
91 |
96 |
99 |
104 |
105 |
106 | );
107 | }
108 | }
109 |
110 | export default App;
111 |
--------------------------------------------------------------------------------