Skip to content

Commit

Permalink
Merge branch 'main' into fix/button
Browse files Browse the repository at this point in the history
  • Loading branch information
Sa24miksha authored Oct 13, 2023
2 parents 55d0f58 + 7a216fe commit 955bbe0
Show file tree
Hide file tree
Showing 15 changed files with 683 additions and 2 deletions.
9 changes: 9 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,15 @@
"contributions": [
"code"
]
},
{
"login": "freemrl",
"name": "Jannik Schmidtke",
"avatar_url": "https://avatars.githubusercontent.com/u/66525499?v=4",
"profile": "https://github.com/FreemRL",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"redux-persist": "^6.0.0",
"remarkable": "^2.0.1",
"reselect": "^4.1.5",
"styled-components": "^6.0.8",
"swiper": "^9.3.2",
"url": "^0.11.0",
"web-vitals": "^2.1.0",
Expand Down Expand Up @@ -125,6 +126,7 @@
]
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@types/dompurify": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.41.0",
Expand Down
4 changes: 3 additions & 1 deletion src/common/activities/ActivityBanner.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { UMAMI_EVENTS } from 'constants';

function ActivityBanner({ currentActivity }) {
const { data } = useFetch(`${process.env.REACT_APP_PLAY_API_URL}/react-play`);
const formatter = Intl.NumberFormat('en', { notation: 'compact' });
const activity = activities.filter((a) => a.id === currentActivity);
const { name, subtitle, description, logo, heroImage } = activity[0];

Expand Down Expand Up @@ -50,7 +51,8 @@ function ActivityBanner({ currentActivity }) {
<span className="btn-label">
GitHub{' '}
<div className="label-info-more">
<FiStar /> <div className="more-label">{data.stargazers_count}</div>
<FiStar />{' '}
<div className="more-label">{formatter.format(data.stargazers_count)}</div>
</div>{' '}
</span>
</a>
Expand Down
3 changes: 2 additions & 1 deletion src/common/defaultBanner/DefaultBanner.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { UMAMI_EVENTS } from 'constants';

const DefaultBanner = () => {
const { data } = useFetch(`${process.env.REACT_APP_PLAY_API_URL}/react-play`);
const formatter = Intl.NumberFormat('en', { notation: 'compact' });

return (
<div>
Expand Down Expand Up @@ -36,7 +37,7 @@ const DefaultBanner = () => {
<span className="btn-label">
GitHub{' '}
<div className="label-info-more">
<FiStar /> <div className="more-label">{data.stargazers_count}</div>
<FiStar /> <div className="more-label">{formatter.format(data.stargazers_count)}</div>
</div>{' '}
</span>
</a>
Expand Down
22 changes: 22 additions & 0 deletions src/plays/hangman-game/HangmanGame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import PlayHeader from 'common/playlists/PlayHeader';
import Main from './components/Main';
import './styles.css';

function HangmanGame(props: any) {
// Your Code Start below.
return (
<>
<div className="play-details">
<PlayHeader play={props} />
<div className="play-details-body">
{/* Your Code Starts Here */}
<Main />
{/* Your Code Ends Here */}
</div>
</div>
</>
);
}

export default HangmanGame;
44 changes: 44 additions & 0 deletions src/plays/hangman-game/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Hangman Game

Hangman is an old school favorite, a word game where the goal is simply to find the missing word or words. You will be presented with a number of blank spaces representing the missing letters you need to find. Use the keyboard to guess a letter.

## Play Demographic

- Language: ts
- Level: Intermediate

## Creator Information

- User: ANKITy102
- Gihub Link: https://github.com/ANKITy102
- Blog:
- Video:

## Implementation Details

The Hangman game is structured around four major components, each designed for enhanced aesthetics and responsiveness using the Styled Components library:

1. Drawing.tsx
The Drawing.tsx component plays a crucial role in rendering the visual representation of the Hangman figure as the game progresses. It provides a visual cue to the player regarding their current progress and incorrect guesses.

2. Word.tsx
The Word.tsx component is responsible for managing the user's input and displaying the correct answer. It ensures a seamless interaction between the player's guesses and the hidden word, providing real-time feedback on the correctness of their choices.

3. Keyboard.tsx
The Keyboard.tsx component is designed to facilitate user input. It presents an interactive keyboard to players, allowing them to select letters as guesses. This component enhances the user experience by making it intuitive and straightforward to make guesses.

4. Main.tsx
The Main.tsx component serves as the central hub where all other components are integrated, resulting in the complete Hangman game experience. It orchestrates the flow of the game, including initializing the game state, tracking guessed letters, and determining whether the player has won or lost.

In addition to these core components, the game relies on a wordList.json file, which contains a collection of hints and words used throughout the gameplay. These hints provide context to players and make the game more engaging and challenging.

This modular and organized structure ensures that the Hangman game is not only enjoyable but also maintainable and extensible, making it an excellent showcase of best practices in React development.


## Consideration

Update all considerations(if any)

## Resources

Update external resources(if any)
34 changes: 34 additions & 0 deletions src/plays/hangman-game/components/Drawing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import styled from 'styled-components';
import {
Head,
Body,
RightArm,
LeftArm,
RightLeg,
LeftLeg,
Element4,
Element3,
Element2,
Element1
} from '../styled-components';

const BodyParts = [Head, Body, RightArm, LeftArm, RightLeg, LeftLeg];
const Gallows = [Element4, Element3, Element2, Element1];

interface DrawingProps {
numberOfGuesses: number;
}

export default function Drawing({ numberOfGuesses }: DrawingProps) {
return (
<div style={{ position: 'relative' }}>
{BodyParts.slice(0, numberOfGuesses).map((Component, id) => (
<Component key={id} />
))}
{Gallows.map((Component, id) => (
<Component key={id} />
))}
</div>
);
}
62 changes: 62 additions & 0 deletions src/plays/hangman-game/components/Keyboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useEffect } from 'react';
import React from 'react';
import styled from 'styled-components';
import { KEYS } from '../constants/constants';
import { Key, KeyboardGrid, KeyContainer } from '../styled-components';

interface KeyboardProps {
correctLetters: string[];
incorrectLetters: string[];
addGuessedLetter: (letter: string) => void;
disabled?: boolean;
}

export default function Keyboard({
correctLetters,
incorrectLetters,
addGuessedLetter,
disabled = false
}: KeyboardProps) {
useEffect(() => {
const handleKeyPress = (event: KeyboardEvent) => {
const key = event.key.toLowerCase();
if (
!disabled &&
KEYS.includes(key) &&
!correctLetters.includes(key) &&
!incorrectLetters.includes(key)
) {
addGuessedLetter(key);
}
};

window.addEventListener('keydown', handleKeyPress);

return () => {
window.removeEventListener('keydown', handleKeyPress);
};
}, [correctLetters, incorrectLetters, addGuessedLetter, disabled]);

return (
<KeyContainer>
<KeyboardGrid>
{KEYS.map((key) => {
const active = correctLetters.includes(key);
const inActive = incorrectLetters.includes(key);

return (
<Key
active={active}
disabled={active || inActive || disabled}
inActive={inActive}
key={key}
onClick={() => addGuessedLetter(key)}
>
{key}
</Key>
);
})}
</KeyboardGrid>
</KeyContainer>
);
}
88 changes: 88 additions & 0 deletions src/plays/hangman-game/components/Main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, { useEffect, useState } from 'react';
import Drawing from './Drawing';
import words from '../constants/wordList.json';
import Keyboard from './Keyboard';
import Word from './Word';
import {
BigContainer,
Container,
EndGame,
P,
Span,
Title,
TryAgainButton
} from '../styled-components';
import { VscDebugRestart } from 'react-icons/vsc';

function getRandomWord(arr: { [key: string]: string }[]) {
const obj = arr[Math.floor(Math.random() * arr.length)];
const word = Object.values(obj)[0] as string;

return { question: Object.keys(obj)[0], word };
}

export default function App() {
const [wordToGuess, setWordToGuess] = useState<string>('');
const [hintToGuess, setHintToGuess] = useState<string>('');
const [guessedLetters, setGuessedLetters] = useState<string[]>([]);

const incorrectLetters = guessedLetters.filter((letter) => !wordToGuess.includes(letter));

const isLoser = incorrectLetters.length >= 6;
const isWinner = wordToGuess.split('').every((letter) => guessedLetters.includes(letter));
const isGameCompleted = isWinner || isLoser;

const addGuessedLetter = (letter: string) => {
if (!guessedLetters.includes(letter)) {
setGuessedLetters((currentLetters) => [...currentLetters, letter]);
}
};

const restartGame = () => {
const { word, question } = getRandomWord(words);
setHintToGuess(question);
setWordToGuess(word);
setGuessedLetters([]);
};

useEffect(() => {
restartGame();
// eslint-disable-next-line
}, []);

return (
<BigContainer>
<Container>
<Title>Hangman</Title>

{!isGameCompleted ? (
<Drawing numberOfGuesses={incorrectLetters.length} />
) : (
<EndGame isWinner={isWinner}>
{isWinner && 'You are a winner!'}
{isLoser && 'Nice try...'}
</EndGame>
)}
{!isGameCompleted && (
<P>
<Span>Question: {hintToGuess} </Span>
</P>
)}
<Word guessedLetters={guessedLetters} reveal={isLoser} wordToGuess={wordToGuess} />

{isGameCompleted && (
<TryAgainButton onClick={restartGame}>
<VscDebugRestart />
</TryAgainButton>
)}

<Keyboard
addGuessedLetter={addGuessedLetter}
correctLetters={guessedLetters.filter((letter) => wordToGuess.includes(letter))}
disabled={isWinner || isLoser}
incorrectLetters={incorrectLetters}
/>
</Container>
</BigContainer>
);
}
23 changes: 23 additions & 0 deletions src/plays/hangman-game/components/Word.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import styled from 'styled-components';
import { Border, LetterComponent, WordContainer } from '../styled-components';

interface WordProps {
guessedLetters: string[];
wordToGuess: string;
reveal?: boolean;
}

export default function Word({ guessedLetters, wordToGuess, reveal = false }: WordProps) {
return (
<WordContainer>
{wordToGuess.split('').map((letter, id) => (
<Border key={id}>
<LetterComponent guessedLetters={guessedLetters} letter={letter} reveal={reveal}>
{letter}
</LetterComponent>
</Border>
))}
</WordContainer>
);
}
30 changes: 30 additions & 0 deletions src/plays/hangman-game/constants/constants.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';

export const KEYS = [
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z'
];
Loading

0 comments on commit 955bbe0

Please sign in to comment.