components: multi selecting and winning move recognision!
This commit is contained in:
parent
0c539cc616
commit
b1ba2b6209
@ -16,7 +16,7 @@ export default function App(): JSX.Element {
|
|||||||
<Board
|
<Board
|
||||||
numRows={10}
|
numRows={10}
|
||||||
numCols={10}
|
numCols={10}
|
||||||
numLines={5}
|
numLines={2}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div />
|
<div />
|
||||||
|
@ -35,12 +35,5 @@
|
|||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
color: brown;
|
color: brown;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
&:hover {
|
|
||||||
border-color: #8b8be5;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
&:not(hover) {
|
|
||||||
border-color: #e5e5ea;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,20 @@ import Line from '../Line/Line';
|
|||||||
|
|
||||||
import './Board.scss';
|
import './Board.scss';
|
||||||
|
|
||||||
export type Point = {
|
type Point = {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Bar = {
|
||||||
|
start: Point,
|
||||||
|
end: Point,
|
||||||
|
}
|
||||||
|
|
||||||
type Selection = {
|
type Selection = {
|
||||||
start: Point;
|
bar: Bar,
|
||||||
end: Point;
|
isVisible: boolean;
|
||||||
visible: boolean;
|
isCorrect: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IBoardProps {
|
interface IBoardProps {
|
||||||
@ -24,69 +29,67 @@ interface IBoardProps {
|
|||||||
interface IBoardState {
|
interface IBoardState {
|
||||||
cells: string[][];
|
cells: string[][];
|
||||||
selections: Selection[];
|
selections: Selection[];
|
||||||
isSelecting: boolean;
|
wasSelecting: boolean;
|
||||||
start: Point;
|
bar: Bar;
|
||||||
end: Point;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Point0: Point = {x: 0, y: 0};
|
const SOLUTIONS: Array<Bar> = [
|
||||||
const Selection0: Selection = {start: Point0, end: Point0, visible: false};
|
{start: {x: 0, y: 0}, end: {x: 5, y: 0}},
|
||||||
|
{start: {x: 2, y: 2}, end: {x: 4, y: 4}},
|
||||||
|
]
|
||||||
|
|
||||||
export default class Board extends React.Component<IBoardProps, IBoardState> {
|
export default class Board extends React.Component<IBoardProps, IBoardState> {
|
||||||
constructor(props: IBoardProps) {
|
constructor(props: IBoardProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
const selection: Selection = {
|
||||||
cells: Array(props.numCols).fill(Array(props.numRows).fill('A')),
|
bar: {
|
||||||
selections: Array(props.numLines).fill(Selection0),
|
start: {x: 0, y: 0},
|
||||||
isSelecting: false,
|
end: {x: 0, y: 0},
|
||||||
start: Point0,
|
},
|
||||||
end: Point0,
|
isCorrect: false,
|
||||||
|
isVisible: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
let s = this.state.selections.slice();
|
this.state = {
|
||||||
s[0].visible = true;
|
cells: Array(props.numCols).fill(Array(props.numRows).fill('A')),
|
||||||
this.setState({...this.state})
|
selections: [...new Array(props.numLines)].map(() => Object.assign({}, selection)),
|
||||||
|
wasSelecting: false,
|
||||||
|
bar: {start: {x: 0, y: 0}, end: {x: 0, y: 0}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveIsValid(pos: Point): boolean {
|
gameOver(): void {
|
||||||
const x = Math.abs(pos.x - this.state.start.x);
|
alert("You won!");
|
||||||
const y = Math.abs(pos.y - this.state.start.y);
|
|
||||||
const lineIsValid = x === 0 || y === 0 || x === y;
|
|
||||||
|
|
||||||
return this.state.isSelecting && lineIsValid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSelection(start: Point, end: Point): Array<Selection> {
|
updateSelection(pos: Point, isSelecting: boolean, isMoving: boolean = false): void {
|
||||||
let selections = this.state.selections.slice();
|
if (isMoving && !this.state.wasSelecting)
|
||||||
let s = selections.find(s => s.visible);
|
|
||||||
|
|
||||||
if (s !== undefined)
|
|
||||||
[s.start, s.end, s.visible] = [start, end, true];
|
|
||||||
|
|
||||||
return selections;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMouseDown(start: Point) {
|
|
||||||
const end = start;
|
|
||||||
const selections = this.updateSelection(start, start);
|
|
||||||
this.setState({...this.state, start, end, selections, isSelecting: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMouseUp(end: Point) {
|
|
||||||
if (!this.moveIsValid(end))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const selections = this.updateSelection(this.state.start, end);
|
const selections = this.state.selections.slice();
|
||||||
this.setState({...this.state, end, selections, isSelecting: false});
|
const s = selections.find(v => !v.isCorrect);
|
||||||
}
|
|
||||||
|
|
||||||
handleMouseOver(end: Point) {
|
if (!s)
|
||||||
if (!this.moveIsValid(end))
|
return this.gameOver();
|
||||||
return;
|
|
||||||
|
|
||||||
const selections = this.updateSelection(this.state.start, end);
|
const x = Math.abs(pos.x - this.state.bar.start.x);
|
||||||
this.setState({...this.state, end, selections});
|
const y = Math.abs(pos.y - this.state.bar.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};
|
||||||
|
|
||||||
|
if (isValidMove)
|
||||||
|
s.bar = bar;
|
||||||
|
|
||||||
|
if (isMouseUp)
|
||||||
|
s.isCorrect = SOLUTIONS.some(v =>
|
||||||
|
JSON.stringify(v) === JSON.stringify(bar));
|
||||||
|
|
||||||
|
this.setState({...this.state, bar, selections, wasSelecting: isSelecting});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCell(s: string, pos: Point): JSX.Element {
|
renderCell(s: string, pos: Point): JSX.Element {
|
||||||
@ -94,9 +97,9 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
|
|||||||
<button
|
<button
|
||||||
className="Cell"
|
className="Cell"
|
||||||
key={`Cell${pos.x}${pos.y}`}
|
key={`Cell${pos.x}${pos.y}`}
|
||||||
onMouseUp={() => this.handleMouseUp(pos)}
|
onMouseUp={() => this.updateSelection(pos, false)}
|
||||||
onMouseDown={() => this.handleMouseDown(pos)}
|
onMouseDown={() => this.updateSelection(pos, true)}
|
||||||
onMouseOver={() => this.handleMouseOver(pos)}
|
onMouseOver={() => this.updateSelection(pos, true, true)}
|
||||||
>
|
>
|
||||||
{s}
|
{s}
|
||||||
</button>
|
</button>
|
||||||
@ -107,9 +110,9 @@ export default class Board extends React.Component<IBoardProps, IBoardState> {
|
|||||||
return (
|
return (
|
||||||
<Line
|
<Line
|
||||||
key={`Line${n}`}
|
key={`Line${n}`}
|
||||||
start={s.start}
|
bar={s.bar}
|
||||||
end={s.end}
|
isVisible={s.isVisible}
|
||||||
visible={s.visible}
|
isCorrect={s.isCorrect}
|
||||||
cellSize={60}
|
cellSize={60}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -3,3 +3,8 @@
|
|||||||
stroke-width: 5px;
|
stroke-width: 5px;
|
||||||
fill: none;
|
fill: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.CorrectLine {
|
||||||
|
@extend .Line;
|
||||||
|
stroke: #60bf4f;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import {Point} from '../Board/Board'
|
import {Bar} from '../Board/Board'
|
||||||
|
|
||||||
import './Line.scss';
|
import './Line.scss';
|
||||||
|
|
||||||
@ -17,10 +17,10 @@ enum Direction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ILineProps {
|
interface ILineProps {
|
||||||
start: Point;
|
bar: Bar;
|
||||||
end: Point;
|
|
||||||
cellSize: number;
|
cellSize: number;
|
||||||
visible: boolean;
|
isVisible: boolean;
|
||||||
|
isCorrect: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Line(props: ILineProps): JSX.Element {
|
export default function Line(props: ILineProps): JSX.Element {
|
||||||
@ -28,6 +28,7 @@ export default function Line(props: ILineProps): JSX.Element {
|
|||||||
const margin = props.cellSize / 2;
|
const margin = props.cellSize / 2;
|
||||||
const padding = margin - offset * 2;
|
const padding = margin - offset * 2;
|
||||||
|
|
||||||
|
/* pls ignore */
|
||||||
const dir = (v: number) => v < 0 ? 2 : v > 0 ? 1 : 0;
|
const dir = (v: number) => v < 0 ? 2 : v > 0 ? 1 : 0;
|
||||||
const mid = (v: number) => v * props.cellSize + props.cellSize / 2;
|
const mid = (v: number) => v * props.cellSize + props.cellSize / 2;
|
||||||
const pad1 = (v: number) => mid(v) - margin + offset;
|
const pad1 = (v: number) => mid(v) - margin + offset;
|
||||||
@ -35,17 +36,15 @@ export default function Line(props: ILineProps): JSX.Element {
|
|||||||
const pad3 = (v: number) => mid(v) + padding + v * padding;
|
const pad3 = (v: number) => mid(v) + padding + v * padding;
|
||||||
const pad4 = (v: number) => mid(v - 1) + margin;
|
const pad4 = (v: number) => mid(v - 1) + margin;
|
||||||
|
|
||||||
const ox = dir(props.start.x - props.end.x);
|
const [startX, startY] = [props.bar.start.x, props.bar.start.y];
|
||||||
const oy = dir(props.start.y - props.end.y);
|
const [endX, endY] = [props.bar.end.x, props.bar.end.y];
|
||||||
|
const [ox, oy] = [dir(startX - endX), dir(startY - endY)];
|
||||||
const d = Number(`${ox}${oy}`) as Direction;
|
const d = Number(`${ox}${oy}`) as Direction;
|
||||||
|
|
||||||
const minX = Math.min(props.start.x, props.end.x);
|
const maxY = Math.max(startY, endY);
|
||||||
const minY = Math.min(props.start.y, props.end.y);
|
const [minX, minY] = [Math.min(startX, endX), Math.min(startY, endY)];
|
||||||
const maxY = Math.max(props.start.y, props.end.y);
|
const [absX, absY] = [Math.abs(startX - endX), Math.abs(startY - endY)];
|
||||||
const absX = Math.abs(props.start.x - props.end.x);
|
const [signX, signY] = [Math.sign(startX - endX), Math.sign(startY - endY)];
|
||||||
const absY = Math.abs(props.start.y - props.end.y);
|
|
||||||
const signX = Math.sign(props.start.x - props.end.x);
|
|
||||||
const signY = Math.sign(props.start.y - props.end.y);
|
|
||||||
|
|
||||||
/* uhh, edge cases for two directions, idk how to fix it */
|
/* uhh, edge cases for two directions, idk how to fix it */
|
||||||
const x = d === Direction.LeftDown ? pad4(minX) : pad1(minX);
|
const x = d === Direction.LeftDown ? pad4(minX) : pad1(minX);
|
||||||
@ -78,12 +77,12 @@ export default function Line(props: ILineProps): JSX.Element {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<rect
|
<rect
|
||||||
className="Line"
|
className={props.isCorrect ? 'CorrectLine' : 'Line'}
|
||||||
rx={margin - offset}
|
rx={margin - offset}
|
||||||
ry={margin - offset}
|
ry={margin - offset}
|
||||||
{...{x, y, width, height}}
|
{...{x, y, width, height}}
|
||||||
transform={`translate(${tx}, ${ty}), rotate(${r}, ${rx}, ${ry})`}
|
transform={`translate(${tx}, ${ty}), rotate(${r}, ${rx}, ${ry})`}
|
||||||
visibility={props.visible ? 'visible' : 'hidden'}
|
visibility={props.isVisible ? 'visible' : 'hidden'}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user