components: refactor, prepare for Answer component

This commit is contained in:
Artur Tamborski 2020-12-27 22:23:33 +01:00
parent d2333a4267
commit 07f283f00e
5 changed files with 67 additions and 60 deletions

View File

@ -7,3 +7,7 @@
grid-column-gap: 0;
grid-row-gap: 0;
}
.Answer {
font-size: smaller;
}

View File

@ -10,14 +10,14 @@ export type Point = {
y: number;
}
export type Bar = {
export type Selection = {
start: Point;
end: Point;
}
export type Solution = {
bar: Bar;
answer: string;
selection: Selection;
key: string;
}
type Game = {
@ -30,13 +30,16 @@ type Game = {
export default class App extends React.Component {
private game: Game;
private readonly answers: Array<JSX.Element>;
constructor(props: object) {
super(props);
this.game = require(`../../constants/1.json`)
this.answers = this.game.solutions.map(s => s.answer).map(k => <p>{k}</p>);
}
renderAnswers(): Array<JSX.Element> {
return this.game.solutions.map(s => s.key).map(k =>
<p className="Answer">{k}</p>);
}
render() {
@ -60,7 +63,7 @@ export default class App extends React.Component {
/>
</div>
<div style={{paddingLeft: '30px'}}>
{this.answers}
{this.renderAnswers()}
</div>
</div>
);

View File

@ -1,12 +1,12 @@
import React from 'react';
import Line from '../Line/Line';
import {Point, Bar, Solution} from "../App/App";
import {Point, Selection, Solution} from "../App/App";
import './Board.scss';
type Answer = {
bar: Bar;
selection: Selection;
isCorrect: boolean;
}
@ -20,8 +20,8 @@ interface IBoardState {
score: number;
wasValidAnswer: boolean;
wasSelecting: boolean;
selections: Array<Answer>;
bar: Bar;
answers: Array<Answer>;
selection: Selection;
}
export default class Board extends React.Component<IBoardProps, IBoardState> {
@ -29,18 +29,18 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
constructor(props: IBoardProps) {
super(props);
const selections = [...new Array(props.solutions.length)].map(() =>
const answers = [...new Array(props.solutions.length)].map(() =>
Object.assign({}, {
bar: {start: {x: 0, y: 0}, end: {x: 0, y: 0}},
selection: {start: {x: 0, y: 0}, end: {x: 0, y: 0}},
isCorrect: false,
}));
this.state = {
answers,
score: 0,
selections,
wasValidAnswer: false,
wasSelecting: false,
bar: {start: {x: 0, y: 0}, end: {x: 0, y: 0}},
selection: {start: {x: 0, y: 0}, end: {x: 0, y: 0}},
}
}
@ -52,34 +52,35 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
const [parse, str] = [JSON.parse, JSON.stringify];
let score = this.state.score;
const selections: Array<Answer> = parse(str(this.state.selections));
const s = selections.find(v => !v.isCorrect);
const answers: Array<Answer> = parse(str(this.state.answers));
const currAnswer: Answer | undefined = answers.find(v => !v.isCorrect);
// skip if there are no lines left or the mouse is moving but not selecting
if (!s || (isMoving && !this.state.wasSelecting))
if (!currAnswer || (isMoving && !this.state.wasSelecting))
return;
const x = Math.abs(pos.x - this.state.bar.start.x);
const y = Math.abs(pos.y - this.state.bar.start.y);
const x = Math.abs(pos.x - this.state.selection.start.x);
const y = Math.abs(pos.y - this.state.selection.start.y);
const isValidMove = x === 0 || y === 0 || x === y;
const isMouseDown = isSelecting && !this.state.wasSelecting;
const isMouseUp = !isSelecting && this.state.wasSelecting && isValidMove;
const start: Point = isMouseDown ? pos : this.state.bar.start;
const bar: Bar = {start, end: pos};
const start: Point = isMouseDown ? pos : this.state.selection.start;
const selection: Selection = {start, end: pos};
if (isValidMove)
s.bar = bar;
currAnswer.selection = selection;
if (isMouseUp && this.state.wasValidAnswer)
[s.isCorrect, score] = [true, score + 1];
[currAnswer.isCorrect, score] = [true, score + 1];
const isValidSolution = this.props.solutions.some(v => str(v.bar) === str(s.bar));
const wasAlreadySelected = this.state.selections.some(v => str(v.bar) === str(s.bar));
const strBar: string = str(currAnswer.selection);
const isValidSolution = this.props.solutions.some(v => str(v.selection) === strBar);
const wasAlreadySelected = this.state.answers.some(v => str(v.selection) === strBar);
const isValidAnswer = isValidSolution && !wasAlreadySelected;
this.setState({
...this.state,
score, bar, selections,
score, selection, answers,
wasValidAnswer: isValidAnswer,
wasSelecting: isSelecting,
});
@ -110,7 +111,7 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
return (
<Line
key={`Line${n}`}
bar={s.bar}
selection={s.selection}
isCorrect={s.isCorrect}
cellSize={this.props.cellSize}
/>
@ -118,12 +119,11 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
}
render(): JSX.Element {
let cells =
this.props.cells.map((oy, y) =>
let cells = this.props.cells.map((oy, y) =>
oy.map((s, x) =>
this.renderCell(s, {x, y})));
let lines = this.state.selections.map((s, n) =>
let lines = this.state.answers.map((s, n) =>
this.renderLine(s, n));
const gridTemplateColumns = `repeat(${this.props.cells.length}, ${this.props.cellSize}px)`;

View File

@ -1,6 +1,6 @@
import React from 'react';
import {Bar} from '../App/App'
import {Selection} from '../App/App'
import './Line.scss';
@ -17,7 +17,7 @@ enum Dir {
}
interface ILineProps {
bar: Bar;
selection: Selection;
cellSize: number;
isCorrect: boolean;
}
@ -25,8 +25,8 @@ interface ILineProps {
export default function Line(props: ILineProps): JSX.Element {
const [m1, sqrt2] = [props.cellSize, Math.sqrt(2)];
const [m2, m4, m8] = [m1 / 2, m1 / 4, m1 / 8];
const [startX, endX] = [m1 * props.bar.start.x, m1 * props.bar.end.x];
const [startY, endY] = [m1 * props.bar.start.y, m1 * props.bar.end.y];
const [startX, endX] = [m1 * props.selection.start.x, m1 * props.selection.end.x];
const [startY, endY] = [m1 * props.selection.start.y, m1 * props.selection.end.y];
const dir = (v: number) => v < 0 ? 2 : v > 0 ? 1 : 0;
const d = Number(`${dir(startX-endX)}${dir(startY-endY)}`) as Dir;

View File

@ -18,29 +18,29 @@
["K", "R", "Z", "T", "A", "L", "E", "R", "Z", "E", "W", "O", "B"]
],
"solutions": [
{"bar": {"start": {"x": 3, "y": 0}, "end": {"x": 7, "y": 0}}, "answer": "PARYŻ"},
{"bar": {"start": {"x": 4, "y": 8}, "end": {"x": 9, "y": 8}}, "answer": "DUBLIN"},
{"bar": {"start": {"x": 8, "y": 9}, "end": {"x": 4, "y": 9}}, "answer": "PERŁA"},
{"bar": {"start": {"x": 10, "y": 11}, "end": {"x": 2, "y": 11}}, "answer": "KOPENHAGA"},
{"bar": {"start": {"x": 3, "y": 12}, "end": {"x": 9, "y": 12}}, "answer": "TALERZE"},
{"bar": {"start": {"x": 0, "y": 3}, "end": {"x": 0, "y": 7}}, "answer": "KLAUN"},
{"bar": {"start": {"x": 1, "y": 2}, "end": {"x": 1, "y": 8}}, "answer": "PLASTYK"},
{"bar": {"start": {"x": 2, "y": 1}, "end": {"x": 2, "y": 9}}, "answer": "SZTOKHOLM"},
{"bar": {"start": {"x": 4, "y": 2}, "end": {"x": 4, "y": 10}}, "answer": "AMSTERDAM"},
{"bar": {"start": {"x": 10, "y": 3}, "end": {"x": 10, "y": 10}}, "answer": "AKROBATA"},
{"bar": {"start": {"x": 11, "y": 9}, "end": {"x": 11, "y": 2}}, "answer": "TANCERKA"},
{"bar": {"start": {"x": 12, "y": 3}, "end": {"x": 12, "y": 9}}, "answer": "TALLINN"},
{"bar": {"start": {"x": 0, "y": 8}, "end": {"x": 4, "y": 12}}, "answer": "PRAGA"},
{"bar": {"start": {"x": 5, "y": 10}, "end": {"x": 1, "y": 6}}, "answer": "FAGOT"},
{"bar": {"start": {"x": 3, "y": 5}, "end": {"x": 8, "y": 10}}, "answer": "WERBEL"},
{"bar": {"start": {"x": 7, "y": 7}, "end": {"x": 3, "y": 3}}, "answer": "MINSK"},
{"bar": {"start": {"x": 3, "y": 1}, "end": {"x": 10, "y": 8}}, "answer": "WARSZAWA"},
{"bar": {"start": {"x": 4, "y": 1}, "end": {"x": 9, "y": 6}}, "answer": "DIADEM"},
{"bar": {"start": {"x": 4, "y": 0}, "end": {"x": 11, "y": 7}}, "answer": "AKORDEON"},
{"bar": {"start": {"x": 12, "y": 4}, "end": {"x": 8, "y": 0}}, "answer": "AKTOR"},
{"bar": {"start": {"x": 2, "y": 5}, "end": {"x": 6, "y": 1}}, "answer": "KOMIK"},
{"bar": {"start": {"x": 1, "y": 8}, "end": {"x": 9, "y": 0}}, "answer": "KONTRABAS"},
{"bar": {"start": {"x": 5, "y": 6}, "end": {"x": 10, "y": 1}}, "answer": "MADRYT"},
{"bar": {"start": {"x": 10, "y": 3}, "end": {"x": 6, "y": 7}}, "answer": "ATENY"}
{"selection": {"start": {"x": 3, "y": 0}, "end": {"x": 7, "y": 0}}, "key": "PARYŻ"},
{"selection": {"start": {"x": 4, "y": 8}, "end": {"x": 9, "y": 8}}, "key": "DUBLIN"},
{"selection": {"start": {"x": 8, "y": 9}, "end": {"x": 4, "y": 9}}, "key": "PERŁA"},
{"selection": {"start": {"x": 10, "y": 11}, "end": {"x": 2, "y": 11}}, "key": "KOPENHAGA"},
{"selection": {"start": {"x": 3, "y": 12}, "end": {"x": 9, "y": 12}}, "key": "TALERZE"},
{"selection": {"start": {"x": 0, "y": 3}, "end": {"x": 0, "y": 7}}, "key": "KLAUN"},
{"selection": {"start": {"x": 1, "y": 2}, "end": {"x": 1, "y": 8}}, "key": "PLASTYK"},
{"selection": {"start": {"x": 2, "y": 1}, "end": {"x": 2, "y": 9}}, "key": "SZTOKHOLM"},
{"selection": {"start": {"x": 4, "y": 2}, "end": {"x": 4, "y": 10}}, "key": "AMSTERDAM"},
{"selection": {"start": {"x": 10, "y": 3}, "end": {"x": 10, "y": 10}}, "key": "AKROBATA"},
{"selection": {"start": {"x": 11, "y": 9}, "end": {"x": 11, "y": 2}}, "key": "TANCERKA"},
{"selection": {"start": {"x": 12, "y": 3}, "end": {"x": 12, "y": 9}}, "key": "TALLINN"},
{"selection": {"start": {"x": 0, "y": 8}, "end": {"x": 4, "y": 12}}, "key": "PRAGA"},
{"selection": {"start": {"x": 5, "y": 10}, "end": {"x": 1, "y": 6}}, "key": "FAGOT"},
{"selection": {"start": {"x": 3, "y": 5}, "end": {"x": 8, "y": 10}}, "key": "WERBEL"},
{"selection": {"start": {"x": 7, "y": 7}, "end": {"x": 3, "y": 3}}, "key": "MINSK"},
{"selection": {"start": {"x": 3, "y": 1}, "end": {"x": 10, "y": 8}}, "key": "WARSZAWA"},
{"selection": {"start": {"x": 4, "y": 1}, "end": {"x": 9, "y": 6}}, "key": "DIADEM"},
{"selection": {"start": {"x": 4, "y": 0}, "end": {"x": 11, "y": 7}}, "key": "AKORDEON"},
{"selection": {"start": {"x": 12, "y": 4}, "end": {"x": 8, "y": 0}}, "key": "AKTOR"},
{"selection": {"start": {"x": 2, "y": 5}, "end": {"x": 6, "y": 1}}, "key": "KOMIK"},
{"selection": {"start": {"x": 1, "y": 8}, "end": {"x": 9, "y": 0}}, "key": "KONTRABAS"},
{"selection": {"start": {"x": 5, "y": 6}, "end": {"x": 10, "y": 1}}, "key": "MADRYT"},
{"selection": {"start": {"x": 10, "y": 3}, "end": {"x": 6, "y": 7}}, "key": "ATENY"}
]
}