extremely claude-assisted go game based on atproto! working on cleaning up and giving a more unique design, still has a bit of a slop vibe to it.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at feature/study-tab 95 lines 3.0 kB view raw
1import tenuki from 'tenuki'; 2import type { MoveRecord } from '$lib/types'; 3 4const { Game } = tenuki; 5 6/** 7 * Calculate liberties for all stones on the board. 8 * Returns a 2D array where each position contains the liberty count for that stone's group. 9 */ 10export function calculateLiberties( 11 moves: MoveRecord[], 12 boardSize: number = 19 13): Array<Array<number>> { 14 const game = new Game({ 15 boardSize, 16 }); 17 18 // Replay all moves 19 for (const move of moves) { 20 game.playAt(move.y, move.x); 21 } 22 23 // Get current board state 24 const state: Array<Array<'empty' | 'black' | 'white'>> = []; 25 for (let y = 0; y < boardSize; y++) { 26 const row: Array<'empty' | 'black' | 'white'> = []; 27 for (let x = 0; x < boardSize; x++) { 28 const intersection = game.intersectionAt(y, x); 29 row.push(intersection.value as 'empty' | 'black' | 'white'); 30 } 31 state.push(row); 32 } 33 34 // Initialize liberty counts 35 const liberties: Array<Array<number>> = Array(boardSize).fill(0).map(() => Array(boardSize).fill(0)); 36 const visited: Array<Array<boolean>> = Array(boardSize).fill(false).map(() => Array(boardSize).fill(false)); 37 38 // Helper to get adjacent coordinates 39 const getAdjacent = (y: number, x: number): Array<[number, number]> => { 40 const adj: Array<[number, number]> = []; 41 if (y > 0) adj.push([y - 1, x]); 42 if (y < boardSize - 1) adj.push([y + 1, x]); 43 if (x > 0) adj.push([y, x - 1]); 44 if (x < boardSize - 1) adj.push([y, x + 1]); 45 return adj; 46 }; 47 48 // Find all stones in a group and their liberties using flood fill 49 const findGroup = (startY: number, startX: number): { stones: Array<[number, number]>, libertyCount: number } => { 50 const color = state[startY][startX]; 51 if (color === 'empty') return { stones: [], libertyCount: 0 }; 52 53 const stones: Array<[number, number]> = []; 54 const libertySet = new Set<string>(); 55 const queue: Array<[number, number]> = [[startY, startX]]; 56 const groupVisited = new Set<string>(); 57 58 while (queue.length > 0) { 59 const [y, x] = queue.shift()!; 60 const key = `${y},${x}`; 61 62 if (groupVisited.has(key)) continue; 63 groupVisited.add(key); 64 stones.push([y, x]); 65 66 for (const [ny, nx] of getAdjacent(y, x)) { 67 const adjKey = `${ny},${nx}`; 68 if (state[ny][nx] === 'empty') { 69 libertySet.add(adjKey); 70 } else if (state[ny][nx] === color && !groupVisited.has(adjKey)) { 71 queue.push([ny, nx]); 72 } 73 } 74 } 75 76 return { stones, libertyCount: libertySet.size }; 77 }; 78 79 // Calculate liberties for each group 80 for (let y = 0; y < boardSize; y++) { 81 for (let x = 0; x < boardSize; x++) { 82 if (state[y][x] !== 'empty' && !visited[y][x]) { 83 const { stones, libertyCount } = findGroup(y, x); 84 85 // Set the liberty count for all stones in this group 86 for (const [sy, sx] of stones) { 87 liberties[sy][sx] = libertyCount; 88 visited[sy][sx] = true; 89 } 90 } 91 } 92 } 93 94 return liberties; 95}