full function, no memory

This commit is contained in:
Joshua Seigler 2025-04-05 19:44:50 -07:00
parent 7aa4a156e7
commit bc29510bb5
3 changed files with 205 additions and 107 deletions

View file

@ -1,4 +1,9 @@
*, :before, :after {
box-sizing: inherit;
}
:root {
box-sizing: border-box;
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
@ -76,6 +81,22 @@
margin: 0 auto;
}
.puzzle-header {
display: flex;
flex-direction: row;
> h1 {
flex-grow: 1;
text-align: left;
margin: 0;
}
}
.puzzle-header-actions {
display: flex;
flex-direction: row;
gap: calc(1 * var(--unit));
}
.puzzle-row {
display: flex;
justify-content: center;
@ -149,6 +170,13 @@
min-width: calc(20 * var(--unit));
}
select {
font-size: 0.8em;
line-height: 1;
margin: 0;
padding: 1em;
}
a {
font-weight: 500;
color: #646cff;

View file

@ -1,118 +1,58 @@
import { For } from "solid-js";
import connections from "./assets/connections.json";
import "./App.css";
import { shuffleArray } from "./utils";
import { createStore } from "solid-js/store";
type Connection = (typeof connections)[number];
type Answer = Connection["answers"][number];
function fromIndex(index: number): [number, number] {
const col = index % 4;
const row = (index - col) / 4;
return [row, col];
}
import useAppModel from "./useAppModel";
function App() {
const [store, setStore] = createStore({
puzzleIndex: 0,
pinnedCount: 3,
selected: [] as number[],
solvedGroups: [] as Answer[],
puzzle: shuffleArray(Array.from({ length: 16 }, (_, i) => i)),
get answers() {
return connections[store.puzzleIndex].answers;
},
});
const getFromPuzzle = (index: number) => {
const puzzleIndex = store.puzzle[index];
const [groupIndex, memberIndex] = fromIndex(puzzleIndex);
const group = store.answers[groupIndex];
return {
group: group.group,
level: group.level,
answer: store.answers[groupIndex].members[memberIndex],
};
};
const handleGuess = () => {
const selectedAnswers = store.selected.map((x) => getFromPuzzle(x));
const { level } = selectedAnswers[0];
const isCorrect = selectedAnswers.every((x) => x.level === level);
if (!isCorrect) {
// TODO you got it wrong
alert("wrong");
return;
}
const selectedPinnedCount = store.selected.reduce(
(acc, cur) => acc + (cur < store.pinnedCount ? 1 : 0),
0
);
setStore({
pinnedCount: store.pinnedCount - selectedPinnedCount,
puzzle: store.puzzle.filter((x) =>
store.selected.every((s) => store.puzzle[s] !== x)
),
selected: [],
});
const newSolvedGroup = store.answers.find((x) => x.level === level);
if (newSolvedGroup != null) {
setStore({
solvedGroups: [...store.solvedGroups, newSolvedGroup],
});
}
if (store.puzzle.length === 0) {
// completely solved!
}
};
const handleShuffle = () => {
const pinned = store.puzzle.slice(0, store.pinnedCount);
const toShuffle = store.puzzle.slice(store.pinnedCount);
setStore({
puzzle: [...pinned, ...shuffleArray(toShuffle)],
});
};
const handlePinUnpin = () => {
if (store.selected.every((x) => x < store.pinnedCount)) {
// we are unpinning
const puzzleStart = Array.from({ length: store.pinnedCount }, (_, i) => i)
.filter((x) => !store.selected.includes(x))
.map((x) => store.puzzle[x]);
const puzzleMiddle = store.selected.map((x) => store.puzzle[x]);
const puzzleEnd = store.puzzle.slice(store.pinnedCount);
const newPuzzle = [...puzzleStart, ...puzzleMiddle, ...puzzleEnd];
setStore({
pinnedCount: store.pinnedCount - store.selected.length,
selected: [],
puzzle: newPuzzle,
});
return;
}
// we are pinning
const puzzleStart = store.puzzle.slice(0, store.pinnedCount);
const puzzleMid = store.selected
.filter((x) => x >= store.pinnedCount)
.map((x) => store.puzzle[x]);
const puzzleEnd = Array.from(
{ length: 16 - store.pinnedCount },
(_, i) => i + store.pinnedCount
)
.filter((x) => !store.selected.includes(x))
.map((x) => store.puzzle[x]);
setStore({
pinnedCount: puzzleStart.length + puzzleMid.length,
selected: [],
puzzle: [...puzzleStart, ...puzzleMid, ...puzzleEnd]
})
};
const {
connections,
store,
setStore,
handleGuess,
handlePinUnpin,
handleSelectGame,
handleShuffle,
getFromPuzzle,
} = useAppModel();
return (
<main class="container">
<h1>Slick Connections</h1>
<div class="puzzle">
<header class="puzzle-header">
<h1>Slick Connections</h1>
<div class="puzzle-header-actions">
<button
type="button"
on:click={() => {
handleSelectGame(store.puzzleId - 1);
}}
disabled={store.puzzleId === 1}
>
-
</button>
<select
name="puzzleNumber"
id="puzzleNumber"
on:input={({ target: { value } }) =>
handleSelectGame(parseInt(value, 10))
}
>
<For each={connections}>
{({ id }) => <option value={id}>{id}</option>}
</For>
</select>
<button
type="button"
on:click={() => {
handleSelectGame(store.puzzleId + 1);
}}
disabled={
store.puzzleId === connections[connections.length - 1].id
}
>
+
</button>
</div>
</header>
<For each={store.solvedGroups}>
{({ group, level, members }) => (
<div class="puzzle-row">

130
src/useAppModel.ts Normal file
View file

@ -0,0 +1,130 @@
import connections from "./assets/connections.json";
import { shuffleArray } from "./utils";
import { createStore } from "solid-js/store";
type Connection = (typeof connections)[number];
type Answer = Connection["answers"][number];
function fromIndex(index: number): [number, number] {
const col = index % 4;
const row = (index - col) / 4;
return [row, col];
}
export default function useAppModel() {
const [store, setStore] = createStore({
puzzleId: 1,
pinnedCount: 0,
selected: [] as number[],
solvedGroups: [] as Answer[],
puzzle: shuffleArray(Array.from({ length: 16 }, (_, i) => i)),
get answers() {
return connections.find((x) => x.id === store.puzzleId)!.answers;
},
});
const handleSelectGame = (newId: number) => {
setStore({
puzzleId: newId,
selected: [],
pinnedCount: 0,
puzzle: shuffleArray(Array.from({ length: 16 }, (_, i) => i)),
solvedGroups: [],
});
};
const getFromPuzzle = (index: number) => {
const puzzleIndex = store.puzzle[index];
const [groupIndex, memberIndex] = fromIndex(puzzleIndex);
const group = store.answers[groupIndex];
return {
group: group.group,
level: group.level,
answer: store.answers[groupIndex].members[memberIndex],
};
};
const handleGuess = () => {
const selectedAnswers = store.selected.map((x) => getFromPuzzle(x));
const { level } = selectedAnswers[0];
const isCorrect = selectedAnswers.every((x) => x.level === level);
if (!isCorrect) {
// TODO you got it wrong
alert("wrong");
return;
}
const selectedPinnedCount = store.selected.reduce(
(acc, cur) => acc + (cur < store.pinnedCount ? 1 : 0),
0
);
setStore({
pinnedCount: store.pinnedCount - selectedPinnedCount,
puzzle: store.puzzle.filter((x) =>
store.selected.every((s) => store.puzzle[s] !== x)
),
selected: [],
});
const newSolvedGroup = store.answers.find((x) => x.level === level);
if (newSolvedGroup != null) {
setStore({
solvedGroups: [...store.solvedGroups, newSolvedGroup],
});
}
if (store.puzzle.length === 0) {
// completely solved!
}
};
const handleShuffle = () => {
const pinned = store.puzzle.slice(0, store.pinnedCount);
const toShuffle = store.puzzle.slice(store.pinnedCount);
setStore({
puzzle: [...pinned, ...shuffleArray(toShuffle)],
});
};
const handlePinUnpin = () => {
if (store.selected.every((x) => x < store.pinnedCount)) {
// we are unpinning
const puzzleStart = Array.from({ length: store.pinnedCount }, (_, i) => i)
.filter((x) => !store.selected.includes(x))
.map((x) => store.puzzle[x]);
const puzzleMiddle = store.selected.map((x) => store.puzzle[x]);
const puzzleEnd = store.puzzle.slice(store.pinnedCount);
const newPuzzle = [...puzzleStart, ...puzzleMiddle, ...puzzleEnd];
setStore({
pinnedCount: store.pinnedCount - store.selected.length,
selected: [],
puzzle: newPuzzle,
});
return;
}
// we are pinning
const puzzleStart = store.puzzle.slice(0, store.pinnedCount);
const puzzleMid = store.selected
.filter((x) => x >= store.pinnedCount)
.map((x) => store.puzzle[x]);
const puzzleEnd = Array.from(
{ length: 16 - store.pinnedCount },
(_, i) => i + store.pinnedCount
)
.filter((x) => !store.selected.includes(x))
.map((x) => store.puzzle[x]);
setStore({
pinnedCount: puzzleStart.length + puzzleMid.length,
selected: [],
puzzle: [...puzzleStart, ...puzzleMid, ...puzzleEnd],
});
};
return {
connections,
store,
setStore,
handleGuess,
handlePinUnpin,
handleSelectGame,
handleShuffle,
getFromPuzzle,
};
}