Skip to content

Commit

Permalink
auto move
Browse files Browse the repository at this point in the history
  • Loading branch information
tom-james-watson committed Apr 23, 2021
1 parent 9a64c51 commit a9c1b82
Show file tree
Hide file tree
Showing 11 changed files with 1,568 additions and 35 deletions.
1 change: 1 addition & 0 deletions .eslintcache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"/home/tomw/Projects/wiki-history-game-www/components/game.tsx":"1","/home/tomw/Projects/wiki-history-game-www/components/item-card.tsx":"2","/home/tomw/Projects/wiki-history-game-www/components/next-item-list.tsx":"3","/home/tomw/Projects/wiki-history-game-www/components/played-item-list.tsx":"4","/home/tomw/Projects/wiki-history-game-www/next-env.d.ts":"5","/home/tomw/Projects/wiki-history-game-www/pages/_app.tsx":"6","/home/tomw/Projects/wiki-history-game-www/pages/index.tsx":"7","/home/tomw/Projects/wiki-history-game-www/types/item.ts":"8"},{"size":6452,"mtime":1619166766365,"results":"9","hashOfConfig":"10"},{"size":5130,"mtime":1619167413354,"results":"11","hashOfConfig":"10"},{"size":895,"mtime":1619164981332,"results":"12","hashOfConfig":"10"},{"size":1534,"mtime":1619164948064,"results":"13","hashOfConfig":"10"},{"size":75,"mtime":1618692093674,"results":"14","hashOfConfig":"10"},{"size":184,"mtime":1618991924027,"results":"15","hashOfConfig":"10"},{"size":339,"mtime":1618771247380,"results":"16","hashOfConfig":"10"},{"size":318,"mtime":1619079048545,"results":"17","hashOfConfig":"10"},{"filePath":"18","messages":"19","errorCount":1,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"1yz0aiv",{"filePath":"20","messages":"21","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"22","messages":"23","errorCount":5,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"24","messages":"25","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"26","messages":"27","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"28","messages":"29","errorCount":1,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"30","messages":"31","errorCount":5,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"32","messages":"33","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/home/tomw/Projects/wiki-history-game-www/components/game.tsx",["34","35","36","37","38","39"],"/home/tomw/Projects/wiki-history-game-www/components/item-card.tsx",["40"],"/home/tomw/Projects/wiki-history-game-www/components/next-item-list.tsx",["41","42","43","44","45","46"],"/home/tomw/Projects/wiki-history-game-www/components/played-item-list.tsx",["47"],"/home/tomw/Projects/wiki-history-game-www/next-env.d.ts",[],"/home/tomw/Projects/wiki-history-game-www/pages/_app.tsx",["48","49"],"/home/tomw/Projects/wiki-history-game-www/pages/index.tsx",["50","51","52","53","54","55"],"/home/tomw/Projects/wiki-history-game-www/types/item.ts",[],{"ruleId":"56","severity":1,"message":"57","line":6,"column":3,"nodeType":"58","messageId":"59","endLine":6,"endColumn":19},{"ruleId":"56","severity":1,"message":"60","line":90,"column":24,"nodeType":"58","messageId":"59","endLine":90,"endColumn":37},{"ruleId":"61","severity":1,"message":"62","line":117,"column":16,"nodeType":"63","messageId":"64","endLine":117,"endColumn":31},{"ruleId":"65","severity":2,"message":"66","line":137,"column":12,"nodeType":"67","messageId":"68","endLine":137,"endColumn":16},{"ruleId":"69","severity":1,"message":"70","line":171,"column":6,"nodeType":"71","endLine":171,"endColumn":8,"suggestions":"72"},{"ruleId":"69","severity":1,"message":"73","line":245,"column":6,"nodeType":"71","endLine":245,"endColumn":30,"suggestions":"74"},{"ruleId":"61","severity":1,"message":"62","line":60,"column":16,"nodeType":"63","messageId":"64","endLine":60,"endColumn":47},{"ruleId":"61","severity":1,"message":"62","line":10,"column":16,"nodeType":"63","messageId":"64","endLine":10,"endColumn":63},{"ruleId":"75","severity":2,"message":"76","line":14,"column":5,"nodeType":"77","messageId":"78","endLine":14,"endColumn":39},{"ruleId":"75","severity":2,"message":"76","line":15,"column":7,"nodeType":"77","messageId":"78","endLine":15,"endColumn":60},{"ruleId":"75","severity":2,"message":"76","line":17,"column":11,"nodeType":"77","messageId":"78","endLine":17,"endColumn":43},{"ruleId":"75","severity":2,"message":"76","line":18,"column":13,"nodeType":"77","messageId":"78","endLine":22,"endColumn":14},{"ruleId":"75","severity":2,"message":"76","line":24,"column":17,"nodeType":"77","messageId":"78","endLine":24,"endColumn":75},{"ruleId":"61","severity":1,"message":"62","line":12,"column":16,"nodeType":"63","messageId":"64","endLine":12,"endColumn":67},{"ruleId":"61","severity":1,"message":"62","line":4,"column":1,"nodeType":"63","messageId":"64","endLine":4,"endColumn":49},{"ruleId":"75","severity":2,"message":"76","line":5,"column":10,"nodeType":"77","messageId":"78","endLine":5,"endColumn":38},{"ruleId":"61","severity":1,"message":"62","line":6,"column":16,"nodeType":"63","messageId":"64","endLine":6,"endColumn":32},{"ruleId":"75","severity":2,"message":"76","line":8,"column":5,"nodeType":"79","messageId":"78","endLine":8,"endColumn":7},{"ruleId":"75","severity":2,"message":"76","line":9,"column":7,"nodeType":"77","messageId":"78","endLine":9,"endColumn":13},{"ruleId":"75","severity":2,"message":"76","line":10,"column":9,"nodeType":"77","messageId":"78","endLine":10,"endColumn":16},{"ruleId":"75","severity":2,"message":"76","line":11,"column":9,"nodeType":"77","messageId":"78","endLine":11,"endColumn":48},{"ruleId":"75","severity":2,"message":"76","line":14,"column":7,"nodeType":"77","messageId":"78","endLine":14,"endColumn":15},"@typescript-eslint/no-unused-vars","'FluidDragActions' is defined but never used.","Identifier","unusedVar","'delta' is defined but never used.","@typescript-eslint/explicit-module-boundary-types","Missing return type on function.","FunctionDeclaration","missingReturnType","no-constant-condition","Unexpected constant condition.","Literal","unexpected","react-hooks/exhaustive-deps","React Hook React.useEffect has a missing dependency: 'state'. Either include it or remove the dependency array. You can also do a functional update 'setState(s => ...)' if you only need 'state' in the 'setState' call.","ArrayExpression",["80"],"React Hook React.useLayoutEffect has missing dependencies: 'move' and 'state'. Either include them or remove the dependency array. You can also do a functional update 'setState(s => ...)' if you only need 'state' in the 'setState' call.",["81"],"react/react-in-jsx-scope","'React' must be in scope when using JSX","JSXOpeningElement","notInScope","JSXOpeningFragment",{"desc":"82","fix":"83"},{"desc":"84","fix":"85"},"Update the dependencies array to be: [state]",{"range":"86","text":"87"},"Update the dependencies array to be: [move, state, state.badlyPlacedIndex]",{"range":"88","text":"89"},[3781,3783],"[state]",[5673,5697],"[move, state, state.badlyPlacedIndex]"]
22 changes: 22 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
env: {
browser: true,
es2021: true,
},
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: "module",
},
plugins: ["react", "@typescript-eslint"],
rules: {},
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# misc
.DS_Store
*.pem
.eslintcache

# debug
npm-debug.log*
Expand Down
7 changes: 7 additions & 0 deletions components/WhyDidYouReload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// import React from "react";
// import whyDidYouRender from "@welldone-software/why-did-you-render";
//
// whyDidYouRender(React, {
// trackAllPureComponents: true,
// trackExtraHooks: [],
// });
173 changes: 163 additions & 10 deletions components/game.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React, { useState } from "react";
import moment from "moment";
import { DragDropContext, DropResult } from "react-beautiful-dnd";
import {
DragDropContext,
DropResult,
FluidDragActions,
SensorAPI,
SnapDragActions,
} from "react-beautiful-dnd";
import { Item, PlayedItem } from "../types/item";
import NextItemList from "./next-item-list";
import PlayedItemList from "./played-item-list";
Expand All @@ -11,6 +17,7 @@ interface State {
deck: Item[];
next: Item | null;
played: PlayedItem[];
badlyPlacedIndex: number | null;
}

function checkCorrect(
Expand All @@ -29,12 +36,93 @@ function checkCorrect(
return true;
}

function wait(ms: number) {
return new Promise((res) => setTimeout(res, ms));
}

export interface UseRbdCommandsProps {
// isDragging: boolean;
moveDurationMs?: number;
}

export const useRbdCommands = ({
// isDragging,
moveDurationMs = 200,
}: UseRbdCommandsProps): {
useSensor: (api: SensorAPI) => void;
move: (id: string, delta: number) => Promise<void>;
} => {
const sensorApiRef = React.useRef<SensorAPI | null>(null);

const useSensor = React.useCallback(
(api: SensorAPI) => {
console.log("set sensorApi");
sensorApiRef.current = api;
},
[sensorApiRef]
);

const lift = React.useCallback(
// (id: string): FluidDragActions | null => {
(id: string): SnapDragActions | null => {
// if (isDragging) {
// return null;
// }

console.log("lift", { id });

const preDrag = sensorApiRef.current?.tryGetLock?.(id);

if (!preDrag) {
console.log("cant find or lock");
return null;
}

//return preDrag.fluidLift({ x: 0, y: 0 });
return preDrag.snapLift();
},
[sensorApiRef]
);

const move = React.useCallback(
async (id: string, delta: number) => {
const drag = lift(id);

console.log("move 1");

if (!drag) {
return;
}
console.log("move 2");

// drag.move({ x: 170 * delta, y: 0 });
drag.moveRight();
console.log("move 3");
await wait(moveDurationMs);
console.log("move 4");
drag.drop();
console.log("move 5");
},
[lift, moveDurationMs]
);

return {
useSensor,
move,
};
};

export default function Game() {
const [state, setState] = useState<State>({
loaded: false,
next: null,
deck: [],
played: [],
badlyPlacedIndex: null,
});

const { useSensor, move } = useRbdCommands({
// isDragging
});

function getRandomItem(deck: Item[], played: Item[]): Item {
Expand All @@ -44,7 +132,9 @@ export default function Game() {
return item.year;
});

while (true) {
let item: Item | undefined = undefined;

while (item === undefined) {
const index = Math.floor(Math.random() * deck.length);
next = deck[index];
const year = moment(next.date).year();
Expand All @@ -55,56 +145,115 @@ export default function Game() {

deck.splice(index, 1);

return { ...next, year };
item = { ...next, year };
}

return item;
}

React.useEffect(() => {
const fetchData = async () => {
const res = await fetch("/items.json");
const items = (await res.text()).split("\n");
const deck: Item[] = items.slice(0, 0 + 100).map((line) => {
const items = (await res.text()).trim().split("\n");
// const deck: Item[] = items.slice(0, 0 + 100).map((line) => {
console.time("json parse");
const deck: Item[] = items.map((line) => {
return JSON.parse(line);
});
console.timeEnd("json parse");
const next = getRandomItem(deck, []);
const played = [
{ ...getRandomItem(deck, []), played: { correct: true } },
];

setState({ next, deck, played, loaded: true });
setState((state) => {
return { ...state, next, deck, played, loaded: true };
});
};

fetchData();
}, []);

function onDragEnd(result: DropResult) {
async function onDragEnd(result: DropResult) {
// debugger;
const { source, destination } = result;
console.log("onDragEnd", { source, destination });

if (!destination || state.next === null) {
if (
!destination ||
state.next === null ||
(source.droppableId === "next" && destination.droppableId === "next")
) {
return;
}

const item = { ...state.next };

if (source.droppableId === "next" && destination.droppableId === "played") {
const newDeck = [...state.deck];
const newPlayed = [...state.played];
const newNext = getRandomItem(newDeck, newPlayed);

const correct = checkCorrect(newPlayed, state.next, destination.index);
const correct = checkCorrect(newPlayed, item, destination.index);
newPlayed.splice(destination.index, 0, {
...state.next,
played: { correct },
});

// setTimeout(async () => {
// await move(item.id, 1);
// }, 2000);

console.log("next to played");

setState({
...state,
deck: newDeck,
next: newNext,
played: newPlayed,
badlyPlacedIndex: correct ? null : destination.index,
});
} else if (
source.droppableId === "played" &&
destination.droppableId === "played"
) {
console.log("played to played");
const newPlayed = [...state.played];
newPlayed.splice(
destination.index,
0,
...newPlayed.splice(source.index, 1)
);

setState({
...state,
played: newPlayed,
badlyPlacedIndex: null,
});
}
}

React.useEffect(() => {
console.log("move changed");
}, [move]);

React.useLayoutEffect(() => {
(async () => {
console.log("layout effect");
if (state.badlyPlacedIndex === null) {
return;
}

// console.log("wait");
// await wait(3000);
console.log("do move", { badlyPlacedIndex: state.badlyPlacedIndex });

await move(state.played[state.badlyPlacedIndex].id, 1);

// setState({ ...state, badlyPlacedIndex: null });
})();
}, [move, state]);

console.log(state);

return (
Expand All @@ -117,13 +266,17 @@ export default function Game() {
// debugger;
}, 1000);
}}
sensors={[useSensor]}
>
<div className={styles.wrapper}>
<div className={styles.top}>
<NextItemList next={state.next} />
</div>
<div className={styles.bottom}>
<PlayedItemList items={state.played} />
<PlayedItemList
badlyPlacedIndex={state.badlyPlacedIndex}
items={state.played}
/>
</div>
</div>
</DragDropContext>
Expand Down
41 changes: 21 additions & 20 deletions components/item-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Item, PlayedItem } from "../types/item";
import styles from "../styles/item-card.module.scss";

interface Props {
draggable?: boolean;
flippedId?: null | string;
index: number;
item: Item | PlayedItem;
Expand All @@ -33,31 +34,31 @@ const datePropIdMap: { [datePropId: string]: string } = {
P7124: "first one",
};

const datePropIdMap2: { [datePropId: string]: string } = {
P575: "Discovery or invention of",
P7589: "Assent of ",
P577: "Publication of",
P1191: "First performance of",
P1619: "Official opening of",
P571: "Creation of",
P1249: "Earliest written record of",
P576: "Abolishing or demolishing of",
P8556: "Extinction of",
P6949: "Announcement of",
P1319: "Earliest record of",
P570: "Death of",
P582: "End of",
P580: "Start of",
P7125: "Date of latest",
P7124: "Date of first",
};
// const datePropIdMap2: { [datePropId: string]: string } = {
// P575: "Discovery or invention of",
// P7589: "Assent of ",
// P577: "Publication of",
// P1191: "First performance of",
// P1619: "Official opening of",
// P571: "Creation of",
// P1249: "Earliest written record of",
// P576: "Abolishing or demolishing of",
// P8556: "Extinction of",
// P6949: "Announcement of",
// P1319: "Earliest record of",
// P570: "Death of",
// P582: "End of",
// P580: "Start of",
// P7125: "Date of latest",
// P7124: "Date of first",
// };

function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}

export default function ItemCard(props: Props) {
const { flippedId, index, item, played, setFlippedId } = props;
const { draggable, flippedId, index, item, played, setFlippedId } = props;

const flipped = item.id === flippedId;

Expand All @@ -82,7 +83,7 @@ export default function ItemCard(props: Props) {
const yearStr = year < -10000 ? year.toLocaleString() : year.toString();

return (
<Draggable draggableId={item.id} index={index} isDragDisabled={played}>
<Draggable draggableId={item.id} index={index} isDragDisabled={!draggable}>
{(provided) => (
<div
className={classNames(styles.itemCard, {
Expand Down
4 changes: 3 additions & 1 deletion components/next-item-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ export default function NextItemList(props: NextItemListProps) {
{...provided.droppableProps}
className={styles.list}
>
{next && <ItemCard item={next} index={0} key={next.id} />}
{next && (
<ItemCard draggable index={0} item={next} key={next.id} />
)}
{provided.placeholder}
</div>
</div>
Expand Down
Loading

0 comments on commit a9c1b82

Please sign in to comment.