Skip to content

Commit

Permalink
add solo play to coloree, add it to header menu, reveal answer on fai…
Browse files Browse the repository at this point in the history
…lure
  • Loading branch information
ayan4m1 committed Jan 29, 2024
1 parent 7a3f086 commit ee764d3
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 90 deletions.
158 changes: 84 additions & 74 deletions src/components/coloree/colorBuilder.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import PropTypes from 'prop-types';
import { SketchPicker } from 'react-color';
import { useState, useCallback, useMemo } from 'react';
import { useState, useCallback, useMemo, Fragment } from 'react';
import {
faDice,
faPaintBrush,
faPlusCircle
faPlusCircle,
faWandMagicSparkles
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
Expand All @@ -24,7 +24,7 @@ import {
getRemainingPct
} from 'utils/coloree';

export default function ColorBuilder({ colors, onSliceAdd }) {
export default function ColorBuilder({ colors, onSliceAdd, onSoloPlayClick }) {
const maxSlicePercentage = useMemo(() => getRemainingPct(colors), [colors]);
const [difficulty, setDifficulty] = useState(1);
const [selectedColor, setSelectedColor] = useState(createRandomColor());
Expand Down Expand Up @@ -60,81 +60,91 @@ export default function ColorBuilder({ colors, onSliceAdd }) {
);

return (
<Card body>
<Card.Title>Generate a Puzzle</Card.Title>
<Form>
<Form.Group>
<Form.Label>Difficulty (1 - 6)</Form.Label>
<Form.Control
type="number"
min={1}
max={6}
step={1}
value={difficulty}
onChange={handleDifficultyChange}
/>
</Form.Group>
<Form.Group className="text-end">
<Button
className="mt-2"
variant="success"
onClick={handlePuzzleRandomize}
>
<FontAwesomeIcon icon={faDice} /> Generate
</Button>
</Form.Group>
</Form>
<hr />
<Card.Title>Create a Puzzle</Card.Title>
<Alert variant="info">
Use the color picker and percentage inputs below to add colors up to
100%. Then, share your puzzle with friends and see if you can stump
them!
</Alert>
<Form>
<Row>
<Col xs={12} md={6} className="mb-2">
<Form.Label>Color</Form.Label>
<SketchPicker
color={selectedColor}
onChange={handleSliceColorChange}
presetColors={[]}
disableAlpha
<Fragment>
<Card body className="mb-3">
<Card.Title>Solo Play</Card.Title>
<Button className="mt-2" variant="success" onClick={onSoloPlayClick}>
<FontAwesomeIcon icon={faWandMagicSparkles} /> Start Game
</Button>
</Card>
<Card body className="mb-3">
<Card.Title>Generate a Puzzle</Card.Title>
<Form>
<Form.Group>
<Form.Label>Difficulty (1 - 6)</Form.Label>
<Form.Control
type="number"
min={1}
max={6}
step={1}
value={difficulty}
onChange={handleDifficultyChange}
/>
</Col>
<Col xs={12} md={6} className="mb-2">
<Form.Label>Percentage</Form.Label>
<InputGroup>
<Form.Control
type="number"
min={0}
max={maxSlicePercentage}
step={1}
onChange={handleSlicePctChange}
value={slicePercentage}
/>
<InputGroup.Text>
of {Math.round(maxSlicePercentage)}%
</InputGroup.Text>
</InputGroup>
</Col>
</Row>
<Form.Group className="text-end">
<ButtonGroup>
<Button variant="success" onClick={handleSliceAdd}>
<FontAwesomeIcon icon={faPlusCircle} /> Add Color
</Button>
<Button variant="info" onClick={handleSliceRandomize}>
<FontAwesomeIcon icon={faPaintBrush} /> Randomize Color
</Form.Group>
<Form.Group className="text-end">
<Button
className="mt-2"
variant="success"
onClick={handlePuzzleRandomize}
>
<FontAwesomeIcon icon={faDice} /> Generate
</Button>
</ButtonGroup>
</Form.Group>
</Form>
</Card>
</Form.Group>
</Form>
</Card>
<Card body className="mb-3">
<Card.Title>Create a Puzzle</Card.Title>
<Alert variant="info">
Use the color picker and percentage inputs below to add colors up to
100%. Then, share your puzzle with friends and see if you can stump
them!
</Alert>
<Form>
<Row>
<Col xs={12} md={6} className="mb-2">
<Form.Label>Color</Form.Label>
<SketchPicker
color={selectedColor}
onChange={handleSliceColorChange}
presetColors={[]}
disableAlpha
/>
</Col>
<Col xs={12} md={6} className="mb-2">
<Form.Label>Percentage</Form.Label>
<InputGroup>
<Form.Control
type="number"
min={0}
max={maxSlicePercentage}
step={1}
onChange={handleSlicePctChange}
value={slicePercentage}
/>
<InputGroup.Text>
of {Math.round(maxSlicePercentage)}%
</InputGroup.Text>
</InputGroup>
</Col>
</Row>
<Form.Group className="text-end">
<ButtonGroup>
<Button variant="success" onClick={handleSliceAdd}>
<FontAwesomeIcon icon={faPlusCircle} /> Add Color
</Button>
<Button variant="info" onClick={handleSliceRandomize}>
<FontAwesomeIcon icon={faDice} /> Randomize Color
</Button>
</ButtonGroup>
</Form.Group>
</Form>
</Card>
</Fragment>
);
}

ColorBuilder.propTypes = {
colors: PropTypes.arrayOf(PropTypes.object).isRequired,
onSliceAdd: PropTypes.func.isRequired
onSliceAdd: PropTypes.func.isRequired,
onSoloPlayClick: PropTypes.func.isRequired
};
2 changes: 1 addition & 1 deletion src/components/coloree/colorPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function ColorPicker({ diameter, finalColor, pieColors }) {
ctx.resetTransform();
}
}
}, [pieColors]);
}, [pieColors, canvasRef]);

return (
<Fragment>
Expand Down
16 changes: 11 additions & 5 deletions src/components/coloree/colorSolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {

import SolverChoice from 'components/coloree/solverChoice';

const totalGuesses = 5;

export default function ColorSolver({
colors,
colorPalette,
Expand All @@ -22,9 +24,13 @@ export default function ColorSolver({
onGuessRemove
}) {
const remainingGuesses = useMemo(
() => 5 - guessHistory.length,
() => totalGuesses - guessHistory.length,
[guessHistory]
);
const guessPercentage = useMemo(
() => (remainingGuesses / totalGuesses) * 100,
[remainingGuesses]
);

return (
<Card body>
Expand All @@ -36,10 +42,11 @@ export default function ColorSolver({
<Col xs={4} className="d-flex align-items-center">
<ProgressBar
className="w-100"
variant="success"
variant={guessPercentage > 0 ? 'success' : 'danger'}
min={0}
max={100}
now={(remainingGuesses / 5) * 100}
now={guessPercentage > 0 ? guessPercentage : 100}
label={guessPercentage > 0 ? `${guessPercentage}%` : 'You Lost'}
/>
</Col>
</Row>
Expand Down Expand Up @@ -104,8 +111,7 @@ ColorSolver.propTypes = {
colors: PropTypes.arrayOf(PropTypes.object).isRequired,
colorPalette: PropTypes.arrayOf(PropTypes.object).isRequired,
currentGuess: PropTypes.arrayOf(PropTypes.string).isRequired,
guessHistory: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.object))
.isRequired,
guessHistory: PropTypes.arrayOf(PropTypes.object).isRequired,
onGuessAdd: PropTypes.func.isRequired,
onGuessRemove: PropTypes.func.isRequired
};
7 changes: 3 additions & 4 deletions src/components/coloree/colorViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ import ColorNamer from 'color-namer';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faLink, faUndo } from '@fortawesome/free-solid-svg-icons';

import { getSolveUrl } from 'utils/coloree';

export default function ColorViewer({ colors, finalColor, onResetClick }) {
const handleUrlCopyClick = useCallback(
() =>
navigator.clipboard.writeText(
`${window.location.href}?mode=solve#${btoa(JSON.stringify(colors))}`
),
() => navigator.clipboard.writeText(getSolveUrl(colors)),
[colors]
);

Expand Down
30 changes: 25 additions & 5 deletions src/components/coloree/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import ColorViewer from 'components/coloree/colorViewer';
import ColorBuilder from 'components/coloree/colorBuilder';
import {
getRemainingPct,
createRandomPuzzle,
createColorPalette,
combineColorChoices,
combineColors,
getColorSimilarity
getColorSimilarity,
getSolveUrl
} from 'utils/coloree';

export default function ColoreeGame() {
Expand All @@ -22,14 +24,15 @@ export default function ColoreeGame() {
const [guessHistory, setGuessHistory] = useState([]);
const [colorPalette, setColorPalette] = useState([]);
const [solved, setSolved] = useState(false);
const [failed, setFailed] = useState(false);
const [solving, setSolving] = useState(false);

const finalColor = useMemo(
() =>
!solving || currentGuess.length !== colors.length
failed || !solving || currentGuess.length !== colors.length
? combineColors(colors)
: combineColors(combineColorChoices(colors, currentGuess)),
[solving, currentGuess, colors]
[failed, solving, currentGuess, colors]
);

const handleColorAdd = useCallback(
Expand Down Expand Up @@ -61,6 +64,8 @@ export default function ColoreeGame() {
setGuessHistory((prevVal) => {
if (colors.every(({ color }, index) => guess[index] === color)) {
setSolved(true);
} else if (prevVal.length === 4) {
setFailed(true);
}

const finalColor = combineColors(combineColorChoices(colors, guess));
Expand Down Expand Up @@ -128,6 +133,13 @@ export default function ColoreeGame() {
[colors, handleGuessComplete]
);
const handleBuilderReset = useCallback(() => setColors([]), []);
const handleSoloPlayClick = useCallback(() => {
if (typeof window === 'undefined') {
return;
}

window.location.href = getSolveUrl(createRandomPuzzle());
}, []);

useEffect(() => {
if (typeof window === 'undefined' || !window.location.hash) {
Expand All @@ -149,6 +161,10 @@ export default function ColoreeGame() {
}, []);

useEffect(() => {
if (!colors.length) {
return;
}

setColorPalette(createColorPalette(colors));
}, [colors]);

Expand All @@ -160,7 +176,7 @@ export default function ColoreeGame() {
<ColorPicker
diameter={Math.min(400, width / 2 - 24)}
pieColors={
solving
solving && !failed
? colors.map(({ pct }, index) => ({
color: currentGuess[index] ?? '#666',
pct
Expand All @@ -172,7 +188,11 @@ export default function ColoreeGame() {
</Col>
<Col xs={12} md={6} className="mb-2">
{getRemainingPct(colors) > 0 ? (
<ColorBuilder colors={colors} onSliceAdd={handleColorAdd} />
<ColorBuilder
colors={colors}
onSliceAdd={handleColorAdd}
onSoloPlayClick={handleSoloPlayClick}
/>
) : !solving ? (
<ColorViewer
colors={colors}
Expand Down
4 changes: 4 additions & 0 deletions src/components/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
faHeart,
faMoon,
faNewspaper,
faPaintBrush,
faRectangleList,
faSun,
faTable
Expand Down Expand Up @@ -83,6 +84,9 @@ export default function Header() {
<Nav.Link as={Link} to="/mahjong" className="text-dark">
<FontAwesomeIcon icon={faRectangleList} /> Mahjong
</Nav.Link>
<Nav.Link as={Link} to="/coloree" className="text-dark">
<FontAwesomeIcon icon={faPaintBrush} /> Coloree
</Nav.Link>
</NavDropdown>
</Nav>
<Nav
Expand Down
6 changes: 5 additions & 1 deletion src/pages/coloree.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Col, Container, Row } from 'react-bootstrap';
import Layout from 'components/layout';
import SEO from 'components/seo';
import ColoreeGame from 'components/coloree/game';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPaintBrush } from '@fortawesome/free-solid-svg-icons';

export default function ColoreePage() {
return (
Expand All @@ -11,7 +13,9 @@ export default function ColoreePage() {
<Container>
<Row>
<Col>
<h1>Coloree</h1>
<h1>
<FontAwesomeIcon icon={faPaintBrush} /> Coloree
</h1>
</Col>
</Row>
<Row>
Expand Down
3 changes: 3 additions & 0 deletions src/utils/coloree.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,6 @@ export const getRemainingPct = (colors) =>
Math.round(
Math.max(0, (1 - colors.reduce((prev, curr) => prev + curr.pct, 0)) * 100)
);

export const getSolveUrl = (colors) =>
`${window.location.href}?mode=solve#${btoa(JSON.stringify(colors))}`;

0 comments on commit ee764d3

Please sign in to comment.