diff --git a/client/src/components/hints.tsx b/client/src/components/hints.tsx
index 2692a7d..a2379d2 100644
--- a/client/src/components/hints.tsx
+++ b/client/src/components/hints.tsx
@@ -1,6 +1,7 @@
import { GameHint } from "./infoview/rpc_api";
import * as React from 'react';
import Markdown from './markdown';
+import { ProofStep } from "./infoview/context";
export function Hint({hint, step, selected, toggleSelection, lastLevel} : {hint: GameHint, step: number, selected: number, toggleSelection: any, lastLevel?: boolean}) {
return
@@ -43,3 +44,23 @@ export function DeletedHints({hints} : {hints: GameHint[]}) {
{hiddenHints.map((hint, i) =>
)}
>
}
+
+/** Filter hints to not show consequtive identical hints twice.
+ *
+ * This function takes a `ProofStep[]` and extracts the hints in form of an
+ * element of type `GameHint[][]` where it removes hints that are identical to hints
+ * appearing in the previous step.
+ *
+ * This effectively means we prevent consequtive identical hints from being shown.
+ */
+export function filterHints(proof: ProofStep[]): GameHint[][] {
+ return proof.map((step, i) => {
+ if (i == 0){
+ return step.hints
+ } else {
+ // TODO: Writing all fields explicitely is somewhat fragile to changes, is there a
+ // good way to shallow-compare objects?
+ return step.hints.filter((hint) => proof[i-1].hints.find((x) => (x.text == hint.text && x.hidden == hint.hidden)) === undefined)
+ }
+ })
+}
diff --git a/client/src/components/infoview/main.tsx b/client/src/components/infoview/main.tsx
index c7f553a..048aef8 100644
--- a/client/src/components/infoview/main.tsx
+++ b/client/src/components/infoview/main.tsx
@@ -34,7 +34,7 @@ import { Button } from '../button';
import { CircularProgress } from '@mui/material';
import { GameHint } from './rpc_api';
import { store } from '../../state/store';
-import { Hints } from '../hints';
+import { Hints, filterHints } from '../hints';
/** Wrapper for the two editors. It is important that the `div` with `codeViewRef` is
* always present, or the monaco editor cannot start.
@@ -367,9 +367,9 @@ export function TypewriterInterface({props}) {
function deleteProof(line: number) {
return (ev) => {
let deletedChat: Array = []
- proof.slice(line).map((step, i) => {
+ filterHints(proof).slice(line).map((hintsAtStep, i) => {
// Only add these hidden hints to the deletion stack which were visible
- deletedChat = [...deletedChat, ...step.hints.filter(hint => (!hint.hidden || showHelp.has(line + i)))]
+ deletedChat = [...deletedChat, ...hintsAtStep.filter(hint => (!hint.hidden || showHelp.has(line + i)))]
})
setDeletedChat(deletedChat)
diff --git a/client/src/components/level.tsx b/client/src/components/level.tsx
index 859711c..1251645 100644
--- a/client/src/components/level.tsx
+++ b/client/src/components/level.tsx
@@ -32,7 +32,7 @@ import { DeletedChatContext, InputModeContext, MobileContext, MonacoEditorContex
ProofContext, ProofStep, SelectionContext, WorldLevelIdContext } from './infoview/context'
import { DualEditor } from './infoview/main'
import { GameHint } from './infoview/rpc_api'
-import { DeletedHints, Hint, Hints } from './hints'
+import { DeletedHints, Hint, Hints, filterHints } from './hints'
import { PrivacyPolicyPopup } from './popup/privacy_policy'
import path from 'path';
@@ -138,19 +138,24 @@ function ChatPanel({lastLevel}) {
let introText: Array = level?.data?.introduction.split(/\n(\s*\n)+/)
+ // experimental: Remove all hints that appeared identically in the previous step
+ // This effectively prevent consequtive hints being shown.
+ let modifiedHints : GameHint[][] = filterHints(proof)
+
return
{introText?.filter(t => t.trim()).map(((t, i) =>
+ // Show the level's intro text as hints, too
))}
- {proof.map((step, i) => {
+ {modifiedHints.map((step, i) => {
// It the last step has errors, it will have the same hints
// as the second-to-last step. Therefore we should not display them.
if (!(i == proof.length - 1 && withErr)) {
// TODO: Should not use index as key.
return
}
})}