Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 66 additions & 56 deletions src/components/Puzzles/Feedback.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Chess } from 'chess.ts'
import { useMemo, Dispatch, SetStateAction } from 'react'

import { Markdown } from 'src/components'
import { useTrainingController } from 'src/hooks'
import { PuzzleGame, Status } from 'src/types/puzzle'

Expand All @@ -14,6 +13,7 @@ interface Props {
controller: ReturnType<typeof useTrainingController>
lastAttemptedMove: string | null
setLastAttemptedMove: Dispatch<SetStateAction<string | null>>
solutionMoveSan: string | null
embedded?: boolean
}

Expand All @@ -26,81 +26,91 @@ export const Feedback: React.FC<Props> = ({
controller: controller,
lastAttemptedMove,
setLastAttemptedMove,
solutionMoveSan,
embedded = false,
}: Props) => {
const { targetIndex } = game

const turn =
new Chess(controller.gameTree.getLastMainlineNode().fen).turn() === 'w'
? 'white'
: 'black'

const archivedContent = `
##### PUZZLE COMPLETED
You already solved this puzzle. Use the boxes on the left to navigate to another puzzle.
`
const content = useMemo(() => {
if (status === 'archived') {
return {
titlePrefix: null,
title: 'You already solved this puzzle.',
detail: 'Choose another puzzle from the history list.',
titleClass: 'text-primary',
accentPrefixClass: '',
}
}

const defaultContent = `
##### YOUR TURN
Find the best move for **${turn}**!
`
const incorrectContent = `
##### ${lastAttemptedMove || 'Move'} is incorrect
Try again or give up to analyze the board and see the best move.
`
if (status === 'forfeit') {
return {
titlePrefix: null,
title: `${solutionMoveSan || 'That move'} is the best move.`,
detail: 'Explore the position or try the next puzzle.',
titleClass: 'text-primary',
accentPrefixClass: '',
}
}

const correctContent = `
##### Correct! ${lastAttemptedMove || 'Move'} is the best move.
You can now explore and analyze the position by making moves, or train on another position.
`
if (status === 'correct') {
return {
titlePrefix: 'Correct!',
title: ` ${lastAttemptedMove || 'That move'} is the best move.`,
detail: 'Explore the position or try the next puzzle.',
titleClass: 'text-primary',
accentPrefixClass: 'text-green-400',
}
}

const gaveUpContent = `
##### Explore the position
Explore the current position by making moves or train on another position.`
if (status === 'incorrect') {
return {
titlePrefix: 'Incorrect.',
title: ` ${lastAttemptedMove || 'That move'} is not the best move.`,
detail: 'Try again or give up to unlock analysis.',
titleClass: 'text-primary',
accentPrefixClass: 'text-human-2',
}
}

const content = useMemo(() => {
if (status === 'archived') {
return archivedContent
} else if (status === 'forfeit') {
return gaveUpContent
} else if (status === 'correct') {
return correctContent
} else if (status === 'incorrect') {
return incorrectContent
} else {
return defaultContent
return {
titlePrefix: null,
title: `Find the best move for ${turn}.`,
detail: 'Give up if you want to reveal the answer and analyze it.',
titleClass: 'text-primary',
accentPrefixClass: '',
}
}, [defaultContent, incorrectContent, correctContent, status, targetIndex])
}, [lastAttemptedMove, solutionMoveSan, status, turn])

return (
<div
className={
embedded
? 'flex w-screen flex-1 flex-col border-t border-glass-border bg-transparent p-3 md:w-auto md:p-5 lg:justify-between'
: 'flex w-screen flex-1 flex-col rounded-md border border-glass-border bg-glass p-3 backdrop-blur-md md:w-auto md:p-5 lg:justify-between'
: 'flex w-screen flex-col rounded-md border border-glass-border bg-glass p-4 shadow-[0_12px_32px_rgb(0_0_0_/_0.14)] backdrop-blur-md md:w-auto'
}
>
<div>
<Markdown>{content.trim()}</Markdown>
{(status === 'forfeit' || status === 'correct') && (
<div className="mt-4 flex items-start gap-2">
<div className="flex items-center gap-0.5">
<span className="material-symbols-outlined !text-xs text-human-3">
arrow_outward
</span>
<span className="text-xs text-human-3">Most Human Move</span>
</div>
<div className="flex items-center gap-0.5">
<span className="material-symbols-outlined !text-xs text-engine-3">
arrow_outward
<div className="flex flex-col gap-3">
<div className="space-y-2">
<h3
className={`text-[1.6rem] font-semibold leading-tight ${content.titleClass}`}
>
{content.titlePrefix ? (
<span className={content.accentPrefixClass}>
{content.titlePrefix}
</span>
<span className="text-xs text-engine-3">Best Engine Move</span>
</div>
</div>
)}
) : null}
{content.title}
</h3>
<p className="max-w-[32ch] text-sm leading-6 text-secondary/75">
{content.detail}
</p>
</div>
</div>

<div className="mt-2 flex min-w-32 flex-row gap-1.5 lg:mt-0 lg:flex-col">
<div className="mt-4 flex min-w-32 flex-row gap-1.5 lg:flex-col">
{status !== 'archived' && (
<>
{status === 'incorrect' && (
Expand All @@ -110,15 +120,15 @@ export const Feedback: React.FC<Props> = ({
setLastAttemptedMove(null)
controller.reset()
}}
className="flex w-full justify-center rounded-sm bg-engine-3 py-1.5 text-sm font-medium text-primary transition duration-300 hover:bg-engine-4 disabled:bg-backdrop disabled:text-secondary"
className="flex w-full justify-center rounded-md border border-engine-4/40 bg-engine-4/15 py-2 text-sm font-medium text-primary transition duration-300 hover:bg-engine-4/25 disabled:bg-backdrop disabled:text-secondary"
>
Try Again
</button>
)}
{status !== 'forfeit' && status !== 'correct' && (
<button
onClick={setAndGiveUp}
className="flex w-full justify-center rounded-sm bg-human-3 py-1.5 text-sm font-medium text-primary transition duration-300 hover:bg-human-4 disabled:bg-backdrop disabled:text-secondary"
className="flex w-full justify-center rounded-md bg-human-3 py-2 text-sm font-medium text-primary transition duration-300 hover:bg-human-4 disabled:bg-backdrop disabled:text-secondary"
>
Give Up
</button>
Expand All @@ -128,7 +138,7 @@ export const Feedback: React.FC<Props> = ({
onClick={async () => {
await getNewGame()
}}
className="flex w-full justify-center rounded-sm bg-human-3 py-1.5 text-sm font-medium text-primary transition duration-300 hover:bg-human-4 disabled:bg-backdrop disabled:text-secondary"
className="flex w-full justify-center rounded-md bg-human-3 py-2 text-sm font-medium text-primary transition duration-300 hover:bg-human-4 disabled:bg-backdrop disabled:text-secondary"
>
Next Puzzle
</button>
Expand Down
Loading
Loading