Skip to content

Commit

Permalink
add copy&paste registration
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-zibert committed Dec 7, 2023
1 parent 6fbca26 commit 511808e
Show file tree
Hide file tree
Showing 8 changed files with 604 additions and 14 deletions.
142 changes: 142 additions & 0 deletions frontend/src/components/PasteRegistration.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { Typography } from "@mui/material";
import Box from "@mui/material/Box";
import HashIcon from "@mui/icons-material/NumbersRounded";
import Button from "@mui/material/Button";
import Snackbar from "@mui/material/Snackbar";
import Alert from "@mui/material/Alert";
import { alpha, useTheme } from "@mui/material/styles";
import TextField from "components/TextField";
import { useAppDispatch } from "hooks/useAppDispatch";
import { useAppSelector } from "hooks/useAppSelector";
import { FC, useState } from "react";
import { commentsActions } from "store/slices/commentsSlice";
import { digitCodeActions } from "store/slices/digitCodeSlice";
import { registrationActions } from "store/slices/registrationSlice";
import { roundsActions } from "store/slices/roundsSlice";
import { parse as parseTuringInfo } from "parsing/turing-copy-paste";
import { parse as parseProblemBook } from "parsing/problem-book";

const PasteRegistration: FC = () => {
const dispatch = useAppDispatch();
const registration = useAppSelector((state) => state.registration);
const [cardText, setCardText] = useState("");
const [showNotFound, setShowNotFound] = useState(false);
const theme = useTheme();

function onSubmit() {
const problem = parseTuringInfo(cardText) || parseProblemBook(cardText);
console.log(problem);
if (problem === null) {
setShowNotFound(true);
return;
}
dispatch(registrationActions.updateHash(problem.code.toUpperCase()));
dispatch(roundsActions.reset());
dispatch(commentsActions.reset());
dispatch(digitCodeActions.reset());
dispatch(registrationActions.fetchDone());
dispatch(commentsActions.setCards(problem));
}

if (registration.status !== "new") {
return (
<TextField
prefixId="registration__hash"
disabled={true}
iconRender={<HashIcon />}
value={registration.hash}
maxChars={10}
customRadius={
registration.status === "ready"
? theme.spacing(0, 0, 2, 2)
: undefined
}
/>
);
}

return (
<>
<Snackbar
anchorOrigin={{ horizontal: "center", vertical: "bottom" }}
open={showNotFound}
onClose={() => {
setShowNotFound(false);
}}
>
<Alert
onClose={() => {
setShowNotFound(false);
}}
severity="error"
sx={{ width: "100%" }}
variant="filled"
>
Could not parse the game setup. Did you copy&paste the whole setup
from <a href="https://turingmachine.info/">turingmachine.info</a> or
the{" "}
<a href="https://boardgamegeek.com/filepage/251409/book-8500-problems-offline-or-analog-use">
problem book
</a>
?
</Alert>
</Snackbar>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmit();
}}
>
<Alert severity="info">
You can paste a game setup string in the following text box. Supported
methods are: <br />
1. You can copy a generated game from{" "}
<a href="https://turingmachine.info/">turingmachine.info</a>. The
copied text needs to include the "#" and all the cards and verifiers.
<br />
2. You can copy from the{" "}
<a href="https://boardgamegeek.com/filepage/251409/book-8500-problems-offline-or-analog-use">
problem book
</a>
. Be sure to include the whole problem line.
</Alert>
<Typography>Paste Game Setup</Typography>
<TextField
iconRender={<div />}
value={cardText}
onChange={(value) => {
setCardText(value);
}}
withReset={true}
onReset={() => {
setCardText("");
}}
/>

<Box pt={0.5}>
<Button
aria-label="search"
disabled={cardText === ""}
fullWidth
size="large"
type="submit"
sx={(theme) => ({
background: alpha(theme.palette.primary.main, 0.1),
borderRadius: theme.spacing(0, 0, 2, 2),
fontFamily: "Kalam",
fontSize: 24,
height: theme.spacing(6),
"&:hover": {
background: alpha(theme.palette.primary.main, 0.2),
},
})}
>
Start Game
</Button>
</Box>
</form>
</>
);
};

export default PasteRegistration;
38 changes: 38 additions & 0 deletions frontend/src/parsing/__test__/problem-book.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { parse } from "parsing/problem-book";

test("C65 6FF P", () => {
expect(
parse("5,#C65 6FF P,->,5,22,24,27,33,48,O252,O536,O658,O213,O613,O289")
).toStrictEqual({
code: "C656FFP",
color: 1,
ind: [5, 22, 24, 27, 33, 48],
crypt: [252, 536, 658, 213, 613, 289],
m: 0,
});
});

test("F4D EXI", () => {
expect(
parse("10,#F4D EXI,->,25,23,24,16,36,4,42,14,B749,B643,B586,B325")
).toStrictEqual({
code: "F4DEXI",
color: 2,
ind: [25, 24, 36, 42],
fake: [23, 16, 4, 14],
crypt: [749, 643, 586, 325],
m: 1,
});
});

test("I51 ZKH K", () => {
expect(
parse("4,#I51 ZKH K,->,N23,N24,N25,N41,N48,G681,G746,G440,G350,G771")
).toStrictEqual({
code: "I51ZKHK",
color: 0,
ind: [23, 24, 25, 41, 48],
crypt: [681, 746, 440, 350, 771],
m: 2,
});
});
102 changes: 102 additions & 0 deletions frontend/src/parsing/__test__/turing-copy-paste.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { parse } from "parsing/turing-copy-paste";

test("A518FRM", () => {
expect(
parse(
`op #A51 8FR M Share Get Criteria and Verification cards in the box. A 1 652 B 7 405 C 12 616 D 15 331 E 16 505 Back to Homepage`
)
).toStrictEqual({
ind: [1, 7, 12, 15, 16],
crypt: [652, 405, 616, 331, 505],
color: 2,
m: 0,
code: "A518FRM",
});
});

test("A4BL4O", () => {
expect(
parse(
`op #A4B L4O Share Get Criteria and Verification cards in the box. A 5 578 B 10 376 C 11 566 D 17 618 Back to Homepage`
)
).toStrictEqual({
ind: [5, 10, 11, 17],
crypt: [578, 376, 566, 618],
color: 0,
m: 0,
code: "A4BL4O",
});
});

test("A4BL4O lowercase", () => {
expect(
parse(
`op #A4B L4O Share Get Criteria and Verification cards in the box. A 5 578 B 10 376 C 11 566 D 17 618 Back to Homepage`.toLowerCase()
)
).toStrictEqual({
ind: [5, 10, 11, 17],
crypt: [578, 376, 566, 618],
color: 0,
m: 0,
code: "A4BL4O",
});
});

test("A4BL4O uppercase", () => {
expect(
parse(
`op #A4B L4O Share Get Criteria and Verification cards in the box. A 5 578 B 10 376 C 11 566 D 17 618 Back to Homepage`.toUpperCase()
)
).toStrictEqual({
ind: [5, 10, 11, 17],
crypt: [578, 376, 566, 618],
color: 0,
m: 0,
code: "A4BL4O",
});
});

test("C65 6FF P", () => {
expect(
parse(
`op #C65 6FF P Share Get Criteria and Verification cards in the box. A 5 252 B 22 536 C 24 658 D 27 213 E 33 613 F 48 289 Back to Homepage`
)
).toStrictEqual({
ind: [5, 22, 24, 27, 33, 48],
crypt: [252, 536, 658, 213, 613, 289],
color: 1,
m: 0,
code: "C656FFP",
});
});

test("E52 NBU A", () => {
expect(
parse(
`rulebook page 3 #E52 NBU A Share Get Criteria and Verification cards in the box. a 1721 499 b 2214 296 c 2319 237 d 210 378 e 1815 594 Back t`
)
).toStrictEqual({
ind: [17, 22, 23, 2, 18],
fake: [21, 14, 19, 10, 15],
crypt: [499, 296, 237, 378, 594],
color: 2,
m: 1,
code: "E52NBUA",
});
});

//

test("H5K M7S", () => {
expect(
parse(
`Nightmare Mode: see rulebook page 3 #H5K M7S Share Get Criteria and Verification cards in the box. 212171922 A 485 B 537 C 315 D 413 E 614 Back to Homepage`
)
).toStrictEqual({
ind: [2, 12, 17, 19, 22],
crypt: [485, 537, 315, 413, 614],
color: 0,
m: 2,
code: "H5KM7S",
});
});
70 changes: 70 additions & 0 deletions frontend/src/parsing/problem-book.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { parseCode, getColor, type ParsedGame } from "./util";

export function parse(text: string): ParsedGame | null {
const problem = text.split("#")[1];
if (!problem) {
return null;
}
const hashEnd = problem.indexOf(",");
const code = problem.slice(0, hashEnd).replace(/\s+/g, "");
const parsedCode = parseCode(code);
if (parsedCode === null) {
return null;
}
const { mode, numVerifiers } = parsedCode;
const cardText = problem.split("->,")[1];
if (!cardText) {
return null;
}
const cards = cardText.split(",");
if (mode === 0) {
// CLASSIC
const ind = [];
for (let i = 0; i < numVerifiers; i += 1) {
ind.push(Number(cards[i]));
}
const crypt = [];
for (let i = numVerifiers; i < numVerifiers * 2; i += 1) {
crypt.push(Number(cards[i].slice(1)));
}
const color = getColor(crypt[0]);
if (color === null) {
return null;
}
return { ind, m: mode, crypt, code, color };
} else if (mode === 1) {
// EXTREME
const ind = [];
const fake = [];
for (let i = 0; i < numVerifiers * 2; i += 2) {
ind.push(Number(cards[i]));
fake.push(Number(cards[i + 1]));
}
const crypt = [];
for (let i = numVerifiers * 2; i < numVerifiers * 3; i += 1) {
crypt.push(Number(cards[i].slice(1)));
}
const color = getColor(crypt[0]);
if (color === null) {
return null;
}
return { ind, fake, m: mode, crypt, code, color };
} else if (mode === 2) {
// NIGHTMARE
const ind = [];
for (let i = 0; i < numVerifiers; i += 1) {
ind.push(Number(cards[i].slice(1)));
}
const crypt = [];
for (let i = numVerifiers; i < numVerifiers * 2; i += 1) {
crypt.push(Number(cards[i].slice(1)));
}
const color = getColor(crypt[0]);
if (color === null) {
return null;
}
return { ind, m: mode, crypt, code, color };
} else {
return null;
}
}
Loading

0 comments on commit 511808e

Please sign in to comment.