Odin SolutionsOdin Solutions

Counting Stars

Week 18, 2026

All Solutions

Food fill to mark all pixels of a star | greenya | Odin Solutions

package main import "core:fmt" import "core:image" import "core:image/bmp" import "core:image/jpeg" import "core:image/png" _, _ :: jpeg, png // IMAGE1_BYTES :: #load("stars-example1.png") // IMAGE2_BYTES :: #load("stars-example2.png") IMAGE1_BYTES :: #load("stars1.png") IMAGE2_BYTES :: #load("stars2.jpg") RGB_THRESHOLD :: 140 // 0..255*3 main :: proc () { fmt.printfln("RGB threshold: %d (0-%d)", RGB_THRESHOLD, 255*3) process_image_bytes(IMAGE1_BYTES, RGB_THRESHOLD, "result1.bmp") process_image_bytes(IMAGE2_BYTES, RGB_THRESHOLD, "result2.bmp") } R_NEW :: 254 R_VISITED :: 255 process_image_bytes :: proc (bytes: [] u8, rgb_threshold: int, save_result_bmp := "") { img, err := image.load_from_bytes(bytes) fmt.assertf(err == nil, "Failed to load image: %v", err) fmt.assertf(img.channels == 3, "Image must have exactly 3 channels (RGB, no alpha)") defer image.destroy(img) fmt.println("------------------------------") defer fmt.println("------------------------------") fmt.printfln("Image resolution: %d x %d", img.width, img.height) assert(img.width * img.height == len(img.pixels.buf) / 3) pixels := transmute ([][3] u8) img.pixels.buf[:len(img.pixels.buf)/3] fmt.println("Applying threshold...") star_pixel_count: int for i in 0..<img.width*img.height { r := int(pixels[i].r) g := int(pixels[i].g) b := int(pixels[i].b) if r + g + b > RGB_THRESHOLD { pixels[i] = {R_NEW,255,255} star_pixel_count += 1 } else { pixels[i] = {} } } fmt.println("Counting stars...") star_count := count_stars(pixels, img.width, img.height) fmt.printfln("Stars : %d", star_count) fmt.printfln("Coverage (%%) : %.1f", (f32(star_pixel_count)*100) / f32(len(pixels))) if save_result_bmp != "" { fmt.printfln("Writing %s...", save_result_bmp) bmp.save(save_result_bmp, img) } } count_stars :: proc (pixels: [][3] u8, width, height: int) -> (count: int) { for y in 0..<height do for x in 0..<width { if pixels[y*width+x].r == R_NEW { fill_star(pixels, width, height, x, y) count += 1 } } return } fill_star :: proc (pixels: [][3] u8, width, height, x, y: int) { list := make([dynamic] int, len=0, cap=400) append(&list, y*width+x) defer delete(list) for len(list) > 0 { i := pop(&list) pixels[i].r = R_VISITED for d in ([?] [2] int { { -1, -1 }, { 0, -1 }, { +1, -1 }, { -1, 0 }, { +1, 0 }, { -1, +1 }, { 0, +1 }, { +1, +1 }, }) { j := i + d.y * width + d.x if j < 0 || j >= width*height do continue if pixels[j].r == R_NEW do append(&list, j) } } }