Skip to content

Commit 1f8567b

Browse files
committed
add post
1 parent 0b9062a commit 1f8567b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+687
-196
lines changed

components/code.tsx

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ require("prismjs/components/prism-lua")
77
require("prismjs/components/prism-lisp")
88
// --
99

10-
import Highlight, { defaultProps } from "prism-react-renderer";
10+
import Highlight, { defaultProps, Language } from "prism-react-renderer";
1111

1212
import codeTheme from "./codeTheme";
1313

14-
export default function Code({ children, language }) {
14+
interface CodeOptions {
15+
showLineNumbers?: boolean;
16+
highlightLines?: number[];
17+
}
18+
19+
export default function Code({ children, language, options = { showLineNumbers: false, highlightLines: [] } }: { children: any, language: Language, options?: CodeOptions }) {
1520
return (
1621
<div className="code">
1722
<Highlight
@@ -22,20 +27,34 @@ export default function Code({ children, language }) {
2227
>
2328
{({ className, style, tokens, getLineProps, getTokenProps }) => (
2429
<div className={className} style={style}>
25-
{tokens.map((line, i) => (
26-
<div key={i} {...getLineProps({ line, key: i })}>
27-
{line.map((token, key) => (
28-
<span key={key} {...getTokenProps({ token, key })} />
29-
))}
30-
</div>
31-
))}
30+
{tokens.map((line, i) => {
31+
const lineProps = getLineProps({ line, key: i });
32+
return (
33+
<div
34+
key={i}
35+
{...lineProps}
36+
className={`${lineProps.className} code-line ${options.highlightLines?.includes(i) ? 'highlighted' : ''}`}
37+
>
38+
{options.showLineNumbers && <span style={{ color: "var(--light-text)", paddingRight: 15 }}>{i + 1}</span>}
39+
{line.map((token, key) => (
40+
<span key={key} {...getTokenProps({ token, key })} />
41+
))}
42+
</div>
43+
);
44+
})}
3245
</div>
3346
)}
3447
</Highlight>
3548
<style jsx>{`
36-
.code {
37-
padding-top: 16px;
38-
padding-bottom: 16px;
49+
.code-line {
50+
transition: background-color 0.2s;
51+
padding-left: 0.75rem;
52+
}
53+
54+
.code-line.highlighted {
55+
background-color: #fef3c7;
56+
border-left: 4px solid #f59e0b;
57+
padding-left: 0.5rem;
3958
}
4059
`}</style>
4160
</div>
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
import { useEffect, useState } from "react"
2+
import Code from "../../code"
3+
4+
export interface BitboardStep {
5+
highlightLines: number[] // Which lines of code to highlight (1-based)
6+
board: bigint | string // Bitboard after this step (64-bit integer)
7+
}
8+
9+
interface BitboardVisualizerProps {
10+
codeLines: string[] // Static array of code lines (shown left-side)
11+
steps: BitboardStep[] // Step-by-step transitions (each step updates the board and highlights lines)
12+
stepDelay?: number // Optional delay between steps (ms), default = 2000
13+
}
14+
15+
export default function BitboardVisualizer({ codeLines, steps, stepDelay = 2000 }: BitboardVisualizerProps) {
16+
const [currentStepIndex, setCurrentStepIndex] = useState(0)
17+
const [bitIndices, setBitIndices] = useState<number[]>([])
18+
19+
// Ensure we have valid steps and a valid current step
20+
const currentStep = steps && steps.length > 0 ? steps[currentStepIndex] : { highlightLines: [], board: 0n }
21+
const boardValue =
22+
currentStep && typeof currentStep.board === "string" ? BigInt(currentStep.board) : currentStep?.board || 0n
23+
24+
// Convert bitboard to binary string (padded to 64 bits)
25+
const binaryString = boardValue.toString(2).padStart(64, "0")
26+
// Split binary string into groups of 8 bits with spaces between
27+
const formattedBinary = binaryString.match(/.{1,8}/g)?.join(" ") || binaryString
28+
29+
// Calculate which bits are set (1)
30+
useEffect(() => {
31+
const indices: number[] = []
32+
const boardValueBigInt = typeof boardValue === 'string' ? BigInt(boardValue) : boardValue
33+
for (let i = 0; i < 64; i++) {
34+
if ((boardValueBigInt & (BigInt(1) << BigInt(i))) !== BigInt(0)) {
35+
indices.push(i)
36+
}
37+
}
38+
setBitIndices(indices)
39+
}, [boardValue])
40+
41+
// Auto-advance steps
42+
useEffect(() => {
43+
const timer = setTimeout(() => {
44+
setCurrentStepIndex((prevIndex) => (prevIndex + 1) % steps.length)
45+
}, stepDelay)
46+
47+
return () => clearTimeout(timer)
48+
}, [currentStepIndex, stepDelay, steps.length])
49+
50+
// Check if a bit is set at a specific position
51+
const isBitSet = (position: number) => {
52+
const boardValueBigInt = typeof boardValue === 'string' ? BigInt(boardValue) : boardValue
53+
return (boardValueBigInt & (BigInt(1) << BigInt(position))) !== BigInt(0)
54+
}
55+
56+
// Get file letter (A-H) from column index (0-7)
57+
const getFile = (col: number) => String.fromCharCode(72 - col) // H to A (reversed)
58+
59+
// Get rank number (1-8) from row index (0-7)
60+
const getRank = (row: number) => 8 - row // 8 to 1 (reversed)
61+
62+
return (
63+
<div className="visualizer-container">
64+
{/* Main content - responsive layout */}
65+
<div className="visualizer-content">
66+
{/* Left side - Code display */}
67+
<pre>
68+
<Code options={{ highlightLines: currentStep?.highlightLines.map(line => line - 1) }}
69+
language="javascript"
70+
children={codeLines.join("\n")}
71+
/>
72+
</pre>
73+
74+
<div className="board-container">
75+
<div className="chessboard">
76+
77+
{/* Chessboard view */}
78+
<div className="board-grid">
79+
{Array.from({ length: 64 }).map((_, index) => {
80+
const row = Math.floor(index / 8)
81+
const col = index % 8
82+
const position = row * 8 + col
83+
const isDarkSquare = (row + col) % 2 === 1
84+
const bitValue = isBitSet(position)
85+
86+
return (
87+
<div
88+
key={index}
89+
className={
90+
isDarkSquare
91+
? bitValue
92+
? "square dark-square bit-set"
93+
: "square dark-square"
94+
: bitValue
95+
? "square light-square bit-set"
96+
: "square light-square"
97+
}
98+
>
99+
<div className={bitValue ? "bit-overlay visible" : "bit-overlay"} />
100+
<span className="square-coord">
101+
{getFile(col)}
102+
{getRank(row)}
103+
</span>
104+
<span className="square-index">{position}</span>
105+
</div>
106+
)
107+
})}
108+
</div>
109+
110+
{/* Bitboard representations */}
111+
<div className="bitboard-info">
112+
<div className="info-item">
113+
<span className="info-label">Binary: </span>
114+
<span className="info-value binary">{formattedBinary}</span>
115+
</div>
116+
<div className="info-item">
117+
<span className="info-label">Set bits: </span>
118+
<span className="info-value">{bitIndices.length > 0 ? bitIndices.join(", ") : "none"}</span>
119+
</div>
120+
</div>
121+
</div>
122+
</div>
123+
</div>
124+
125+
<style jsx>{`
126+
.visualizer-container {
127+
width: 100%;
128+
max-width: 1200px;
129+
margin: 0 auto;
130+
}
131+
132+
.visualizer-content {
133+
display: flex;
134+
flex-direction: column;
135+
}
136+
137+
.code-line.highlighted {
138+
background-color: #fef3c7;
139+
border-left: 4px solid #f59e0b;
140+
padding-left: 0.5rem;
141+
}
142+
143+
.board-container {
144+
width: 100%;
145+
margin-top: 0.1rem;
146+
}
147+
148+
.chessboard {
149+
aspect-ratio: 1 / 1;
150+
width: 100%;
151+
max-width: 448px;
152+
margin: 0 auto;
153+
}
154+
155+
.board-grid {
156+
display: grid;
157+
grid-template-columns: repeat(8, 1fr);
158+
height: 100%;
159+
}
160+
161+
.square {
162+
position: relative;
163+
display: flex;
164+
flex-direction: column;
165+
align-items: center;
166+
justify-content: center;
167+
border: 1px solid #e5e7eb;
168+
}
169+
170+
.light-square {
171+
background-color: white;
172+
}
173+
174+
.dark-square {
175+
background-color: #d1d5db;
176+
}
177+
178+
.bit-set {
179+
box-shadow: inset 0 0 0 2px #3b82f6;
180+
}
181+
182+
.bit-overlay {
183+
position: absolute;
184+
inset: 0;
185+
display: flex;
186+
align-items: center;
187+
justify-content: center;
188+
transition: opacity 0.5s;
189+
background-color: rgba(59, 130, 246, 0.5);
190+
opacity: 0;
191+
}
192+
193+
.bit-overlay.visible {
194+
opacity: 1;
195+
}
196+
197+
.square-coord {
198+
font-size: 0.75rem;
199+
opacity: 0.5;
200+
position: absolute;
201+
top: 2px;
202+
left: 2px;
203+
}
204+
205+
.square-index {
206+
font-size: 0.75rem;
207+
opacity: 0.5;
208+
position: absolute;
209+
bottom: 2px;
210+
right: 2px;
211+
}
212+
213+
.bitboard-info {
214+
margin-top: 0.25rem;
215+
margin-bottom: 0.25rem;
216+
display: flex;
217+
flex-direction: column;
218+
gap: 0.25rem;
219+
font-family: "IBM Plex Mono", monospace;
220+
font-size: 0.875rem;
221+
width: 100%;
222+
max-width: 448px;
223+
margin-left: auto;
224+
margin-right: auto;
225+
}
226+
227+
.info-item {
228+
padding: 0.5rem;
229+
background-color: #f9fafb;
230+
border-radius: 0.25rem;
231+
}
232+
233+
.info-item.binary {
234+
overflow-x: auto;
235+
}
236+
237+
.info-value {
238+
white-space: normal;
239+
}
240+
241+
.info-value.binary {
242+
overflow-x: auto;
243+
}
244+
`}</style>
245+
</div>
246+
)
247+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import BitboardVisualizer from "./bitboard-visualizer"
2+
import { BitboardStep } from "./bitboard-visualizer"
3+
4+
const whitePawnAttacks: { codeLines: string[], steps: BitboardStep[] } = {
5+
codeLines: [
6+
"// Initial white pawn attacks",
7+
"FILE_A = 0x0101010101010101n;",
8+
"FILE_H = 0x8080808080808080n;",
9+
"white_pawns = 0x000000000000FF00n;",
10+
"attacks_left = (white_pawns & ~FILE_A) << 7n;",
11+
"attacks_right = (white_pawns & ~FILE_H) << 9n;",
12+
"pawn_attacks = attacks_left | attacks_right;",
13+
],
14+
steps: (() => {
15+
const FILE_A = 0x0101010101010101n
16+
const FILE_H = 0x8080808080808080n
17+
const white_pawns = 0x000000000000ff00n
18+
const attacks_left = (white_pawns & ~FILE_A) << 7n
19+
const attacks_right = (white_pawns & ~FILE_H) << 9n
20+
const pawn_attacks = attacks_left | attacks_right
21+
22+
return [
23+
{ highlightLines: [2], board: FILE_A },
24+
{ highlightLines: [3], board: FILE_H },
25+
{ highlightLines: [4], board: white_pawns },
26+
{ highlightLines: [5], board: attacks_left },
27+
{ highlightLines: [6], board: attacks_right },
28+
{ highlightLines: [7], board: pawn_attacks },
29+
]
30+
})(),
31+
}
32+
33+
const knightAttack: { codeLines: string[], steps: BitboardStep[] } = {
34+
codeLines: [
35+
"// Knight attacks from F5",
36+
"KNIGHT_POS = 0x0000000004000000n;",
37+
"attacks = (KNIGHT_POS << 17n) |",
38+
" (KNIGHT_POS << 15n) |",
39+
" (KNIGHT_POS << 10n & NOT_AB_FILE) |",
40+
" (KNIGHT_POS << 6n & NOT_GH_FILE) |",
41+
" (KNIGHT_POS >> 17n) |",
42+
" (KNIGHT_POS >> 15n) |",
43+
" (KNIGHT_POS >> 10n & NOT_AB_FILE) |",
44+
" (KNIGHT_POS >> 6n & NOT_GH_FILE);",
45+
],
46+
steps: (() => {
47+
const KNIGHT_POS = 0x0000000004000000n
48+
const NOT_AB_FILE = ~0x0303030303030303n // Correct mask for files A and B
49+
const NOT_GH_FILE = ~0xc0c0c0c0c0c0c0c0n // Correct mask for files G and H
50+
51+
const attacks = (KNIGHT_POS << 17n) |
52+
(KNIGHT_POS << 15n) |
53+
(KNIGHT_POS << 10n & NOT_AB_FILE) |
54+
(KNIGHT_POS << 6n & NOT_GH_FILE) |
55+
(KNIGHT_POS >> 17n) |
56+
(KNIGHT_POS >> 15n) |
57+
(KNIGHT_POS >> 10n & NOT_AB_FILE) |
58+
(KNIGHT_POS >> 6n & NOT_GH_FILE)
59+
60+
return [
61+
{ highlightLines: [2], board: KNIGHT_POS },
62+
{ highlightLines: [3], board: KNIGHT_POS << 17n },
63+
{ highlightLines: [4], board: KNIGHT_POS << 15n },
64+
{ highlightLines: [5], board: KNIGHT_POS << 10n & NOT_AB_FILE },
65+
{ highlightLines: [6], board: KNIGHT_POS << 6n & NOT_GH_FILE },
66+
{ highlightLines: [7], board: KNIGHT_POS >> 17n },
67+
{ highlightLines: [8], board: KNIGHT_POS >> 15n },
68+
{ highlightLines: [9], board: KNIGHT_POS >> 10n & NOT_AB_FILE },
69+
{ highlightLines: [10], board: KNIGHT_POS >> 6n & NOT_GH_FILE },
70+
{ highlightLines: [3, 4, 5, 6, 7, 8, 9, 10], board: attacks },
71+
]
72+
})(),
73+
}
74+
75+
export const KnightAttack = () => {
76+
return <BitboardVisualizer codeLines={knightAttack.codeLines} steps={knightAttack.steps} />
77+
}
78+
79+
export const WhitePawnAttacks = () => {
80+
return <BitboardVisualizer codeLines={whitePawnAttacks.codeLines} steps={whitePawnAttacks.steps} />
81+
}

0 commit comments

Comments
 (0)