From a0f5264106e2a320624f30c43d4f669371c1e69d Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Tue, 14 Jul 2026 10:50:34 -0400 Subject: [PATCH] init(work): add JavaScript pattern recognition drills --- work/Blind/patterns.js | 211 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 work/Blind/patterns.js diff --git a/work/Blind/patterns.js b/work/Blind/patterns.js new file mode 100644 index 0000000..7190bd9 --- /dev/null +++ b/work/Blind/patterns.js @@ -0,0 +1,211 @@ +// ============================================================ +// PART A FINAL DRILL — Tuesday morning, before 11:30am. +// 8 snippets covering the most likely categories: +// nested loops + string accumulation, reference vs copy, +// sort() defaults, slice/immutability/off-by-one, +// Object.keys strings, splice-while-iterating, +// hidden-space parity, string coercion. +// +// RULES (same as the real thing): +// 1. No paper. No running the code until AFTER you answer. +// 2. For each snippet, deliver the full narration OUT LOUD: +// signature -> structures -> trace -> pattern name -> EXACT output. +// 3. Then scroll to the ANSWER KEY at the bottom and check. +// 4. Log any miss against the gotcha taxonomy. +// +// Target: < 90 seconds per snippet. Do NOT peek early. +// ============================================================ + + +// ---- SNIPPET 1: nested loop + string accumulation ---- +function s1(str) { + let out = ""; + for (let i = str.length - 1; i >= 0; i--) { + for (let j = 0; j < i; j++) out += "*"; + out += str[i]; + } + return out; +} +// console.log(s1("abc")); + + +// ---- SNIPPET 2: reference vs shallow copy ---- +function s2() { + const a = [1, 2, 3]; + const b = a; + const c = [...a]; + b.push(4); + c.push(5); + return [a.length, b.length, c.length]; +} +// console.log(s2()); + + +// ---- SNIPPET 3: sort() default behavior ---- +function s3(arr) { + arr.sort(); + return arr; +} +// console.log(s3([5, 100, 25, 3])); + + +// ---- SNIPPET 4: slice + string immutability + off-by-one ---- +function s4(str) { + str.slice(0, 3); + const tail = str.slice(-2); + return tail + str.slice(1, 2); +} +// console.log(s4("planet")); + + +// ---- SNIPPET 5: Object.keys returns strings ---- +function s5(nums) { + const freq = {}; + for (let n of nums) freq[n] = (freq[n] || 0) + 1; + const keys = Object.keys(freq); + return keys[0] + keys[1]; +} +// console.log(s5([9, 9, 30, 30])); + + +// ---- SNIPPET 6: splice while iterating ---- +function s6(arr) { + for (let i = 0; i < arr.length; i++) { + if (arr[i] < 0) arr.splice(i, 1); + } + return arr; +} +// console.log(s6([-1, -2, 3, -4, -5])); + + +// ---- SNIPPET 7: hidden character parity ---- +function s7(str) { + let out = ""; + for (let i = 0; i < str.length; i++) { + out += i % 2 === 0 ? str[i] : "_"; + } + return out; +} +// console.log(s7("go far")); + + +// ---- SNIPPET 8: string coercion mid-loop ---- +function s8(arr) { + let total = 0; + for (let x of arr) total += x; + return total; +} +// console.log(s8([1, 2, "3", 4])); + + +// ============================================================ +// ============================================================ +// +// S T O P. +// +// Narrate all 8 out loud first. Exact outputs stated. +// Then read the answer key below and check yourself. +// +// ============================================================ +// ============================================================ + + +// ---- ANSWER KEY ---- +// +// SNIPPET 1 -> "**c*ba" +// Loop runs BACKWARDS (i from 2 down to 0). Each pass pads +// i stars, then appends str[i]: +// i=2: "**" + "c" -> "**c" +// i=1: "*" + "b" -> "**c*b" +// i=0: (no stars) + "a" -> "**c*ba" +// Traps: reverse iteration direction + star count comes from +// the INDEX, not the character. Pattern name: "reverse walk +// with index-sized padding." +// Narration line: "The outer loop descends, so the last +// character is emitted first." +// +// SNIPPET 2 -> [4, 4, 4] +// b = a is an ALIAS (same array). c = [...a] is a real copy +// taken BEFORE the pushes. b.push(4) grows a AND b to 4. +// c was [1,2,3], its own push(5) grows it to 4. +// All three read 4 — for two different reasons. If you said +// [4, 4, 5] you forgot c was copied before b.push. If you +// said [3, 4, 4] you missed the alias. +// Narration line: "Assignment aliases; spread copies — and +// the copy freezes the state at the moment it's taken." +// +// SNIPPET 3 -> [100, 25, 3, 5] +// Default sort converts to STRINGS: "100" < "25" < "3" < "5" +// lexicographically (compares char by char: "1" < "2" < "3" +// < "5"). Also note: sort() MUTATES arr in place and returns +// the same reference. +// Narration line: "No comparator, so JavaScript sorts these +// as strings — 100 comes first because the character '1' is +// smallest." +// +// SNIPPET 4 -> "etl" +// Line 1 is a DECOY: strings are immutable and the slice +// result is thrown away — str is unchanged. +// str.slice(-2) = last two chars = "et". +// str.slice(1, 2) = index 1 only (end-exclusive) = "l". +// "et" + "l" = "etl". +// Traps: the dead line, negative slice, end-exclusivity. +// Narration line: "The first slice does nothing — the result +// isn't assigned. Strings are immutable." +// +// SNIPPET 5 -> "930" +// freq = {9: 2, 30: 2}. Object.keys returns ["9", "30"] — +// STRINGS, in ascending numeric order (JS orders integer-like +// keys numerically). "9" + "30" is string CONCATENATION, +// not addition: "930". If you said 39, you added numbers +// that were never numbers. +// Narration line: "Object.keys always returns strings, so +// plus means concatenate here." +// +// SNIPPET 6 -> [-2, 3, -5] +// The splice-while-iterating bug, adjacent-negatives flavor: +// i=0: -1 removed, everything shifts left -> [-2, 3, -4, -5] +// ...but i increments to 1, so -2 (now at index 0) +// is SKIPPED. +// i=1: 3, not negative, stays. +// i=2: -4 removed -> [-2, 3, -5]; -5 slides to index 2, +// i increments to 3, past the end. -5 SKIPPED. +// Every removal skips its right neighbor. Fix if asked: +// iterate backwards, or use filter. +// Narration line: "Each splice shifts the array left while i +// still moves right, so the element after every removal gets +// skipped." +// +// SNIPPET 7 -> "g_ _a_" +// "go far" = g(0) o(1) ' '(2) f(3) a(4) r(5). +// Even indices kept, odd replaced with underscore: +// g, _, ' ', _, a, _ -> "g_ _a_" +// The trap: the SPACE sits at an even index, so it's KEPT — +// the middle of the output is underscore-space-underscore, +// which looks wrong but isn't. Spaces are characters. They +// have indices. +// Narration line: "Index 2 is the space and 2 is even, so +// the space survives." +// +// SNIPPET 8 -> "334" +// total starts as NUMBER 0: +// 0 + 1 = 1, 1 + 2 = 3 (still numbers) +// 3 + "3" = "33" (+ with a string CONCATENATES, +// and total is now a STRING) +// "33" + 4 = "334" +// One string element permanently flips the accumulator's +// type. Everything after it concatenates. +// Narration line: "The plus operator concatenates the moment +// either side is a string — and the poison spreads." +// +// ============================================================ +// SCORING: 8/8 = ready. 6-7 = re-trace the misses out loud +// once and you're ready. Same gotcha missed twice = say that +// taxonomy row out loud three times, then stop. +// +// To verify any answer for real: uncomment its console.log +// and run `node partA-final-drill.js`. +// +// After this: cheatsheet once, decision rule out loud, +// close the laptop. 11:30 is yours. +// ============================================================