Odin SolutionsOdin Solutions
☠️
X Marks the Spot
Week 2, 2026
All SolutionsOdin Plotting with Raylib | greenya | Odin Solutions
// - use "odin run ." to run the code
// - input.txt should be nearby with the input data
// - map.jpg should be nearby
package main
import "core:fmt"
import "core:strconv"
import "core:strings"
import rl "vendor:raylib"
input_txt_bytes := #load("input.txt")
map_jpg_bytes := #load("map.jpg")
main :: proc () {
rl.SetTraceLogLevel(.WARNING)
rl.SetConfigFlags({ .VSYNC_HINT })
map_img := rl.LoadImageFromMemory(".jpg", raw_data(map_jpg_bytes), i32(len(map_jpg_bytes)))
rl.InitWindow(map_img.width, map_img.height, "week2")
defer rl.CloseWindow()
map_tex := rl.LoadTextureFromImage(map_img)
rl.UnloadImage(map_img)
defer rl.UnloadTexture(map_tex)
path_tex, path_map_origin := plot()
path_tex_center := [2] f32 { f32(path_tex.width/2), f32(path_tex.height/2) }
defer rl.UnloadTexture(path_tex)
path_tex_top_left: [2] f32
is_align_mode := true
for !rl.WindowShouldClose() {
if rl.IsMouseButtonPressed(.LEFT) do is_align_mode ~= true
mouse_pos := rl.GetMousePosition()
mouse_pos_map := [2] f32 {
path_map_origin.x - path_tex_top_left.x + mouse_pos.x,
path_map_origin.y + path_tex_top_left.y - mouse_pos.y,
}
if is_align_mode {
path_tex_top_left = mouse_pos - path_tex_center
}
rl.BeginDrawing()
rl.DrawTexture(map_tex, 0, 0, rl.WHITE)
rl.DrawTextureV(path_tex, path_tex_top_left, rl.WHITE)
hint_cstr := fmt.ctprintf(
"1. Align start of the path with the ship\n" +
"2. Click with LMB to toggle Align Mode [%s]\n" +
"3. Mouse over the cross in the path to see coordinates %v of the treasure",
is_align_mode ? "ON" : "OFF",
mouse_pos_map,
)
rl.DrawText(hint_cstr, 20+1, 20+2, 20, rl.BLACK)
rl.DrawText(hint_cstr, 20, 20, 20, rl.YELLOW)
rl.EndDrawing()
free_all(context.temp_allocator)
}
}
plot :: proc () -> (path_tex: rl.Texture, path_map_origin: [2] f32) {
context.allocator = context.temp_allocator
path_img := rl.GenImageColor(4000, 4000, {0,0,0,100})
path_off := [2] i32 { path_img.width/2, path_img.height/2 }
path_pos := path_off
path_box := struct { left, right, top, bottom: i32 } {
left = path_pos.x,
right = path_pos.x,
top = path_pos.y,
bottom = path_pos.y,
}
input := strings.trim(string(input_txt_bytes), "\n\t ")
entries := strings.split(input, " ")
last_pos: [2] i32
#reverse for entry in entries {
values := strings.split(entry, ",")
assert(len(values) == 2)
v1_str, v2_str := values[0], values[1]
if v1_str[0]!='N' && v1_str[0]!='S' {
x, x_ok := strconv.parse_f32(v1_str)
y, y_ok := strconv.parse_f32(v2_str)
assert(x_ok && y_ok)
assert(last_pos == {}, "last pos already set")
last_pos = { i32(x), i32(y) }
continue
}
for v in values {
dist, dist_ok := strconv.parse_int(v[1:], base=10)
assert(dist_ok)
if dist != 0 {
dir: [2] i32
switch v[0] {
case 'N': dir = {0,+1}
case 'S': dir = {0,-1}
case 'W': dir = {+1,0}
case 'E': dir = {-1,0}
case : panic("unexpected direction")
}
path_pos += dir * i32(dist)
}
}
assert(path_pos.x>=0 && path_pos.x<path_img.width, "plot x pos overflow")
assert(path_pos.y>=0 && path_pos.y<path_img.height, "plot y pos overflow")
path_box = {
left = min(path_box.left, path_pos.x),
right = max(path_box.right, path_pos.x),
top = min(path_box.top, path_pos.y),
bottom = max(path_box.bottom, path_pos.y),
}
rl.ImageDrawCircle(&path_img, path_pos.x, path_pos.y, 2, rl.WHITE)
}
rl.ImageCrop(&path_img, {
x = f32(path_box.left),
y = f32(path_box.top),
width = f32(path_box.right - path_box.left + 1),
height = f32(path_box.bottom - path_box.top + 1),
})
path_tex = rl.LoadTextureFromImage(path_img)
rl.UnloadImage(path_img)
path_map_origin = [2] f32 {
f32(path_box.left - path_off.x + last_pos.x),
f32(-path_box.top + path_off.y + last_pos.y),
}
fmt.printfln("last pos: %v", last_pos)
fmt.printfln("path box: %#v", path_box)
fmt.printfln("path box size: %i x %i", path_box.right-path_box.left, path_box.bottom-path_box.top)
fmt.printfln("path_map_origin: %v", path_map_origin)
return
}