Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/memory challenge #86

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions client/src/components/MemoryChallenge/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React, { useState, useEffect, useRef } from 'react';
import './main.css';

function MemoryChallenge() {
const initialGridSize = 2;
const maxGridSize = 6;
const [gridSize, setGridSize] = useState<number>(initialGridSize);
const [cards, setCards] = useState<number[]>(Array(initialGridSize * initialGridSize).fill(0));
const [sequence, setSequence] = useState<number[]>([]);
const [userSequence, setUserSequence] = useState<number[]>([]);
const [isShowing, setIsShowing] = useState<boolean>(true);
const [message, setMessage] = useState<string>('');
const [sequenceLength, setSequenceLength] = useState<number>(2);
const timeoutsRef = useRef<NodeJS.Timeout[]>([]);

const colors = ['#f5c242', '#e4a101'];

useEffect(() => {
startNewGame();
return () => {
timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
};
}, [gridSize]);

const startNewGame = () => {
timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
timeoutsRef.current = [];

const newSequence = Array.from({ length: sequenceLength }, () => Math.floor(Math.random() * (gridSize * gridSize)));
setSequence(newSequence);
setUserSequence([]);
setMessage('');
setCards(Array(gridSize * gridSize).fill(0));
showSequence(newSequence);
};

const showSequence = (sequence: number[]) => {
setIsShowing(true);
let delay = 0;

sequence.forEach((index, i) => {
const showTimeout = setTimeout(() => {
setCards(prev => prev.map((card, idx) => (idx === index ? 1 : card)));

const hideTimeout = setTimeout(() => {
setCards(prev => prev.map((card, idx) => (idx === index ? 0 : card)));
if (i === sequence.length - 1) setIsShowing(false);
}, 500);

timeoutsRef.current.push(hideTimeout);
}, delay);

timeoutsRef.current.push(showTimeout);
delay += 1000;
});
};

const handleCardClick = (index: number) => {
if (isShowing || userSequence.length >= sequence.length) return;

setUserSequence([...userSequence, index]);

if (sequence[userSequence.length] !== index) {
setMessage('Incorrect! Try again.');
setUserSequence([]);
} else if (userSequence.length + 1 === sequence.length) {
setUserSequence([]);
setMessage('Next level');
setSequenceLength(prev => prev + 1);
if (gridSize < maxGridSize) {
setGridSize(prev => prev + 1);
}
startNewGame();
}
};

return (
<div className="container" style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', height: '100vh' }}>
<h1>Memory Challenge</h1>
{message && <div className="message">{message}</div>}
<div className="card-grid" style={{ gridTemplateColumns: `repeat(${gridSize}, 1fr)`, gap: '10px' }}>
{cards.map((card, index) => (
<div
key={index}
className={`card ${card ? 'active' : ''}`}
style={{
width: '60px',
height: '60px',
backgroundColor: card ? colors[index % colors.length] : undefined,
backgroundImage: card ? undefined : 'url(src/assets/img/logo.jpeg)',
backgroundSize: 'cover',
backgroundPosition: 'center'
}}
onClick={() => handleCardClick(index)}
/>
))}
</div>
{message === 'Incorrect! Try again.' && (
<button onClick={startNewGame} className="restart-button">Restart Game</button>
)}
</div>
);
}

export default MemoryChallenge;
59 changes: 59 additions & 0 deletions client/src/components/MemoryChallenge/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
body {
color: #fff;
}

.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}

h1 {
font-size: 3rem;
margin: 20px 0
}

.card-grid {
display: grid;
gap: 10px;
margin-top: 20px;
}

.card {
width: 60px;
height: 60px;
border-radius: 8px;
cursor: pointer;
transition: transform 0.2s;
}

.card.active {
transform: scale(1.1);
}

.message {
margin: 10px 0;
padding: 10px;
background-color: 2c0001;
color: #e4a101;
border-radius: 5px;
text-align: center;
}

.restart-button {
margin-top: 20px;
padding: 10px 20px;
background-color: #e4a101;
color: #2c0001;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}

.restart-button:hover {
background-color: #2c0001;
color: #e4a101;
}
14 changes: 5 additions & 9 deletions client/src/main.tsx
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ import Chat from "./components/Chat/index.tsx";
import AppLayout from "./components/Layouts/AppLayout.tsx";

import "./index.css";
import MemoryChallenge from "./components/MemoryChallenge/index.tsx";

function provider() {
return new RpcProvider({
@@ -62,15 +63,10 @@ async function main() {
>
<Router>
<Routes>
{/* Cover route without header*/}
<Route path="/" element={<NewCover />} />

{/* Internal routes using layout for header */}
<Route element={<AppLayout />}>
<Route path="/bag" element={<Bag sdk={sdk} />} />
<Route path="/play/:beastId" element={<Tamagotchi sdk={sdk} />} />
<Route path="/chat" element={<Chat />} />
</Route>
<Route path='/' element={<Cover />}/>
<Route path='/bag' element={<Bag sdk={sdk} />} />
<Route path='/play' element={<Tamagotchi sdk={sdk} />} />
<Route path='/chat' element={<Chat />} />
</Routes>
</Router>
</StarknetConfig>