diff react_games/src/random.tsx @ 51:68fa88ac73fe

Interview prep for xAI
author June Park <parkjune1995@gmail.com>
date Mon, 15 Dec 2025 19:55:17 -0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/react_games/src/random.tsx	Mon Dec 15 19:55:17 2025 -0800
@@ -0,0 +1,105 @@
+import { InputEvent, useCallback, useEffect, useRef, useState } from "react";
+import ReactDOM from "react-dom/client";
+
+// 1. input and listen to its key stroke fire findSuggestions
+// 2. debounce findSuggestions
+// 3. create structure for its to search
+
+const DEBOUNCER_WAIT_TIME = 500;
+
+const WORDS = [
+  "cat",
+  "call",
+  "cell",
+  "car",
+  "carpet",
+  "celcius"
+]
+
+interface Tries {
+  children: Record<string, Tries>;
+  words: Set<string>;
+}
+
+function TypeAhead() {
+  const inputRef = useRef<HTMLInputElement | null>(null);
+  const debounceTimerId = useRef<NodeJS.Timeout>(null);
+  const tries = useRef<Tries>({ children: {}, words: new Set(WORDS) })
+  const [suggestions, setSuggestions] = useState<string[]>([]);
+
+  const performSearch = useCallback((value: string) => {
+    let curr = tries.current
+    const res: string[] = []
+    function dfs(node: Tries, pos: number, off: number = 0, matching: number = 0) {
+      if (off > 2) {
+        if (matching > Math.ceil(value.length/2)) {
+          node.words.forEach(word => res.push(word));
+        }
+        return;
+      }
+
+      if (pos == value.length) {
+        node.words.forEach(word => res.push(word));
+        return;
+      }
+
+      const letter = value[pos];
+      if (!node.children[letter]) {
+        Object.keys(node.children).forEach((key) => {
+          dfs(node.children[key], pos+1, off+1, matching)
+        });
+      } else {
+        dfs(node.children[letter], pos+1, off, matching + 1)
+      }
+
+    }
+    dfs(curr, 0);
+    setSuggestions([...res]);
+  }, [])
+
+  const findSuggestions = useCallback(() => {
+    if (debounceTimerId.current) {
+      clearTimeout(debounceTimerId.current);
+    }
+    debounceTimerId.current = setTimeout(() => performSearch(inputRef.current?.value || ""), DEBOUNCER_WAIT_TIME)
+  }, [])
+
+  useEffect(() => {
+    WORDS.forEach(word => {
+      let curr = tries.current;
+      for (let letter of word) {
+        letter = letter.toLowerCase();
+        if (!curr.children[letter]) {
+          curr.children[letter] = { children: {}, words: new Set([word]) };
+        } else {
+          curr.children[letter].words.add(word) ;
+        }
+        curr = curr.children[letter];
+      }
+    })
+    return () => {
+      if (debounceTimerId.current)
+        clearTimeout(debounceTimerId.current)
+    }
+  }, [])
+
+  return (
+    <>
+      <h1>  Type ahead </h1>
+      <input ref={inputRef} onChange={findSuggestions}/>
+      {suggestions && (
+        <div style={{display: "flex", flexDirection: "column", gap: 8, border: "1px black solid"}}>
+        {suggestions.map(suggestion => {
+          return (
+            <div>{suggestion}</div>
+          )
+        })}
+        </div>
+      )}
+    </>
+  );
+}
+
+// Render
+const root = ReactDOM.createRoot(document.getElementById("root")!);
+root.render(<TypeAhead />);