Merge pull request '#9: make the user-chosen path more clear to see.' (#10) from feature/9-improve-display-of-solution into main
Some checks reported errors
continuous-integration/drone/push Build encountered an error

Reviewed-on: #10
This commit is contained in:
Manuel Friedli 2025-01-11 00:31:13 +01:00
commit 9b52470f6b
5 changed files with 137 additions and 12 deletions

View file

@ -22,14 +22,88 @@
border-left-color: var(--color-maze-border); border-left-color: var(--color-maze-border);
} }
.user{ .userSELF {
background-color: var(--color-maze-cell-user); background: radial-gradient(
ellipse 16% 16% at center,
var(--color-maze-cell-user) 0,
var(--color-maze-cell-user) 100%,
#0000 100%
);
} }
.user:hover { .userSELF:hover {
background-color: var(--color-maze-cell-user-highlight); background: radial-gradient(
ellipse 33% 33% at center,
var(--color-maze-cell-user) 0,
var(--color-maze-cell-user) 80%,
#0000 100%
);
} }
.solution.user { .marker {
background-color: #c8ff00; display: inline-block;
position: absolute;
}
.marker:hover {
background: #fc08;
}
.userUP .marker.UP {
height: 50%;
width: 100%;
background: linear-gradient(
90deg,
#0000 0,
#0000 33%,
var(--color-maze-cell-user) 33%,
var(--color-maze-cell-user) 66%,
#0000 66%,
#0000 100%
);
}
.userRIGHT .marker.RIGHT {
height: 100%;
width: 50%;
left: 50%;
background: linear-gradient(
0deg,
#0000 0,
#0000 33%,
var(--color-maze-cell-user) 33%,
var(--color-maze-cell-user) 66%,
#0000 66%,
#0000 100%
);
}
.userDOWN .marker.DOWN {
height: 50%;
width: 100%;
top: 50%;
background: linear-gradient(
90deg,
#0000 0,
#0000 33%,
var(--color-maze-cell-user) 33%,
var(--color-maze-cell-user) 66%,
#0000 66%,
#0000 100%
);
}
.userLEFT .marker.LEFT {
height: 100%;
width: 50%;
background: linear-gradient(
0deg,
#0000 0,
#0000 33%,
var(--color-maze-cell-user) 33%,
var(--color-maze-cell-user) 66%,
#0000 66%,
#0000 100%
);
} }

View file

@ -4,6 +4,7 @@
height: 2em; height: 2em;
width: 2em; width: 2em;
padding: 0; padding: 0;
position: relative;
} }
.cell:hover { .cell:hover {

View file

@ -6,8 +6,41 @@ import "./cell.css";
import {State} from "./state/state.ts"; import {State} from "./state/state.ts";
import {ActionDispatch} from "react"; import {ActionDispatch} from "react";
function isMarked(x: number, y: number, marked: Coordinates[]): boolean { function getMarkedDirections(coords: Coordinates, marked: Coordinates[]): Direction[] {
return !!marked.find(e => e.x === x && e.y === y); const cellIndex: number = marked.findIndex(e => e.x === coords.x && e.y === coords.y);
if (cellIndex === -1) {
return [];
}
if (marked.length === 1) {
return [Direction.SELF];
}
if (cellIndex === 0) {
const next: Coordinates = marked[1];
return [Direction.SELF, getDirectionTo(coords, next)];
} else {
const previous = marked[cellIndex - 1];
if (cellIndex === marked.length - 1) {
return [Direction.SELF, getDirectionTo(coords, previous)];
}
const next: Coordinates = marked[cellIndex + 1];
return [Direction.SELF, getDirectionTo(coords, previous), getDirectionTo(coords, next)];
}
}
function getDirectionTo(me: Coordinates, other: Coordinates): Direction {
const xDiff = me.x - other.x;
switch (xDiff) {
case -1:
return Direction.RIGHT;
case 1:
return Direction.LEFT;
default:
const yDiff = me.y - other.y;
if (yDiff === -1) {
return Direction.DOWN;
}
return Direction.UP;
}
} }
export default function Cell({x, y, state, dispatch}: export default function Cell({x, y, state, dispatch}:
@ -24,8 +57,10 @@ export default function Cell({x, y, state, dispatch}:
if (cell.bottom) classes += " bottom"; if (cell.bottom) classes += " bottom";
if (cell.left) classes += " left"; if (cell.left) classes += " left";
if (cell.solution && state.showSolution) classes += " solution"; if (cell.solution && state.showSolution) classes += " solution";
const marked = isMarked(x, y, state.userPath); const markedDirections = getMarkedDirections({x, y}, state.userPath);
if (marked) classes += " user"; for (let i = 0; i < markedDirections.length; i++) {
classes += ` user${Direction[markedDirections[i]]}`;
}
return ( return (
<div className={styles.cell + classes} <div className={styles.cell + classes}
onMouseEnter={(e) => { onMouseEnter={(e) => {
@ -37,6 +72,14 @@ export default function Cell({x, y, state, dispatch}:
onClick={() => { onClick={() => {
dispatch(actionClickedCell(x, y)); dispatch(actionClickedCell(x, y));
}}> }}>
<div className={"marker UP"}></div>
<div className={"marker RIGHT"}></div>
<div className={"marker DOWN"}></div>
<div className={"marker LEFT"}></div>
</div> </div>
); );
} }
enum Direction {
UP, RIGHT, DOWN, LEFT, SELF
}

View file

@ -1,6 +1,12 @@
import {ActionDispatch, FormEvent, useState} from 'react'; import {ActionDispatch, FormEvent, useState} from 'react';
import ValidatingInputNumberField, {ValidatorFunction} from "./validating-input-number-field.tsx"; import ValidatingInputNumberField, {ValidatorFunction} from "./validating-input-number-field.tsx";
import {Action, actionLoadedMaze, actionLoadingFailed, actionStartedLoading} from "./state/action.ts"; import {
Action,
actionLoadedMaze,
actionLoadingFailed,
actionStartedLoading,
actionToggledShowSolution
} from "./state/action.ts";
import styles from "./input-form.module.css"; import styles from "./input-form.module.css";
import "./input-form.css"; import "./input-form.css";
import {State} from "@/app/state/state.ts"; import {State} from "@/app/state/state.ts";
@ -17,10 +23,10 @@ export default function InputForm({state, dispatch}: {
const handleSubmit = (e: FormEvent) => { const handleSubmit = (e: FormEvent) => {
e.preventDefault(); e.preventDefault();
dispatch(actionStartedLoading()); dispatch(actionStartedLoading());
dispatch(actionToggledShowSolution(false));
const url = `https://manuel.friedli.info/labyrinth/create/json?w=${width}&h=${height}&id=${id || ''}&algorithm=${algorithm}`; const url = `https://manuel.friedli.info/labyrinth/create/json?w=${width}&h=${height}&id=${id || ''}&algorithm=${algorithm}`;
fetch(url) fetch(url)
.then(response => response.json()) .then(response => response.json())
// .then(result => new Promise(resolve => setTimeout(resolve, 600, result)))
.then(result => { .then(result => {
dispatch(actionLoadedMaze(result)); dispatch(actionLoadedMaze(result));
}) })

View file

@ -25,6 +25,7 @@ export default function Home() {
<h1>The Maze ({state.maze!.width}x{state.maze!.height}, Algorithm: {state.maze!.algorithm}, <h1>The Maze ({state.maze!.width}x{state.maze!.height}, Algorithm: {state.maze!.algorithm},
ID: {state.maze!.id})</h1> ID: {state.maze!.id})</h1>
<input type={"checkbox"} <input type={"checkbox"}
checked={state.showSolution}
onChange={(e) => { onChange={(e) => {
dispatch(actionToggledShowSolution(e.target.checked)); dispatch(actionToggledShowSolution(e.target.checked));
}} }}