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

Handle matching pairs #7

Merged
merged 8 commits into from
Nov 5, 2024
Merged

Handle matching pairs #7

merged 8 commits into from
Nov 5, 2024

Conversation

pishposh
Copy link
Owner

@pishposh pishposh commented Nov 5, 2024

When two cards are flipped, checks if they’re a match, and if so, marks them as such and ignores them for the rest of the game; otherwise, flips them back over after a delay.

Also:

  • Changes “flipped” terminology to “face-down” and “face-up,” because I kept getting confused
  • Moves flipped state management out of PicketSign into App

handleCardClick could probably use a close look from someone who understands state management in React better than me.

@@ -2,36 +2,25 @@ import { useEffect, useMemo, useState } from 'react';
import { SignContent } from '../../types';
import './PicketSign.css';

export const PicketSign = ({ content }: { content: SignContent }) => {
const [flipped, setFlipped] = useState(true);
const [showContent, setShowContent] = useState(false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exists to prevent the card contents from flashing when the page loads. However I think you're on to something. I'll make a suggestion below that can prevent the image flash without extra JS

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggestions feature in github won't let me suggest the entire code change, so I made #8 instead.

Copy link
Collaborator

@mattgrunwald mattgrunwald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! I wound up having to request changes in the form of a PR into your PR for some silly reason, but it's just a fix for a minor vqa bug.

@@ -2,36 +2,25 @@ import { useEffect, useMemo, useState } from 'react';
import { SignContent } from '../../types';
import './PicketSign.css';

export const PicketSign = ({ content }: { content: SignContent }) => {
const [flipped, setFlipped] = useState(true);
const [showContent, setShowContent] = useState(false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggestions feature in github won't let me suggest the entire code change, so I made #8 instead.

@mattgrunwald mattgrunwald self-requested a review November 5, 2024 05:05
src/App.tsx Outdated
Comment on lines 17 to 57

const handleCardClick = (card: Card) => {
// do nothing if card is already face up or matched:
if (card.isFaceUp || card.isMatched) {
return;
}

// do nothing if there's already two actively face-up cards:
const faceUpCards = cards.filter(c => c.isFaceUp && !c.isMatched); // TODO: do we care about O(N) here? probably not
if (faceUpCards.length >= 2) {
return;
}

// flip the card face-up:
const newCards = cards.map(c =>
c.id === card.id ? { ...c, isFaceUp: true } : c
);
setCards(newCards);

// is this the second flip, and if so is it a match for the first?
const newFaceUpCards = newCards.filter(c => c.isFaceUp && !c.isMatched);
if (newFaceUpCards.length === 2) {
const [firstCard, secondCard] = newFaceUpCards;
if (firstCard.value === secondCard.value) {
// cards match, mark them as matched and keep them face up:
setCards(newCards.map(c =>
c.value === firstCard.value ? { ...c, isMatched: true } : c
));
} else {
// cards don't match, flip them back face-down after a delay:
setTimeout(() => {
setCards(cards => cards.map(c =>
c.id === firstCard.id || c.id === secondCard.id
? { ...c, isFaceUp: false }
: c
));
}, 1000);
}
}
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const handleCardClick = (card: Card) => {
// do nothing if card is already face up or matched:
if (card.isFaceUp || card.isMatched) {
return;
}
// do nothing if there's already two actively face-up cards:
const faceUpCards = cards.filter(c => c.isFaceUp && !c.isMatched); // TODO: do we care about O(N) here? probably not
if (faceUpCards.length >= 2) {
return;
}
// flip the card face-up:
const newCards = cards.map(c =>
c.id === card.id ? { ...c, isFaceUp: true } : c
);
setCards(newCards);
// is this the second flip, and if so is it a match for the first?
const newFaceUpCards = newCards.filter(c => c.isFaceUp && !c.isMatched);
if (newFaceUpCards.length === 2) {
const [firstCard, secondCard] = newFaceUpCards;
if (firstCard.value === secondCard.value) {
// cards match, mark them as matched and keep them face up:
setCards(newCards.map(c =>
c.value === firstCard.value ? { ...c, isMatched: true } : c
));
} else {
// cards don't match, flip them back face-down after a delay:
setTimeout(() => {
setCards(cards => cards.map(c =>
c.id === firstCard.id || c.id === secondCard.id
? { ...c, isFaceUp: false }
: c
));
}, 1000);
}
}
};
const faceUpCards = useMemo(
() => cards.filter((c) => c.isFaceUp && !c.isMatched),
[cards]
);
useEffect(() => {
if (faceUpCards.length !== 2) {
return;
}
const [firstCard, secondCard] = faceUpCards;
if (firstCard.value === secondCard.value) {
// cards match, mark them as matched and keep them face up:
setCards((cards) =>
cards.map((c) =>
c.value === firstCard.value ? { ...c, isMatched: true } : c
)
);
} else {
// cards don't match, flip them back face-down after a delay:
setTimeout(() => {
setCards((cards) =>
cards.map((c) =>
c.id === firstCard.id || c.id === secondCard.id
? { ...c, isFaceUp: false }
: c
)
);
}, 1000);
}
}, [cards, faceUpCards]);
const handleCardClick = (card: Card) => {
// do nothing if card is already face up or matched
// or if there's already two actively face-up cards:
if (card.isFaceUp || card.isMatched || faceUpCards.length >= 2) {
return;
}
// flip the card face-up:
const newCards = cards.map((c) =>
c.id === card.id ? { ...c, isFaceUp: true } : c
);
setCards(newCards);
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suggestion isn't strictly necessary but does move state management out of the click handler and slightly deduplicates code

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Updated.

@pishposh pishposh merged commit 485f8ae into main Nov 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants