#!meta {"kernelInfo":{"defaultKernelName":"spiral","items":[{"aliases":[],"name":"spiral"}]}} #!markdown # cube #!markdown ## cube #!fsharp open System open System.Threading.Tasks open System.Text #!fsharp let width = 160 let height = 44 let backgroundChar = '.' let distanceFromCam = 100.0 let k1 = 40.0 let incrementSpeed = 0.6 #!markdown ### get_width #!spiral inl get_width () = 160i32 #!markdown ### get_height #!spiral inl get_height () = 44i32 #!markdown ### get_background_char #!spiral inl get_background_char () = '.' #!markdown ### get_distance_from_cam #!spiral inl get_distance_from_cam () = 100f64 #!markdown ### get_k1 #!spiral inl get_k1 () = 40f64 #!markdown ### get_increment_speed #!spiral inl get_increment_speed () = 0.6f64 #!markdown ### rotation #!fsharp type Rotation = { a: float; b: float; c: float } #!spiral type rotation = { a : f64 b : f64 c : f64 } #!markdown ### cube #!fsharp type Cube = { cubeWidth: float; horizontalOffset: float } #!spiral type cube = { cube_width : f64 horizontal_offset : f64 } #!markdown ### get_cubes #!fsharp let cubes = [ { cubeWidth = 20.0; horizontalOffset = -40.0 } { cubeWidth = 10.0; horizontalOffset = 10.0 } { cubeWidth = 5.0; horizontalOffset = 40.0 } ] #!spiral inl get_cubes () : list cube = [ { cube_width = 20; horizontal_offset = -40 } { cube_width = 10; horizontal_offset = 10 } { cube_width = 5; horizontal_offset = 40 } ] #!markdown ### calculate_x #!fsharp let calculateX i j k (rot: Rotation) = let a, b, c = rot.a, rot.b, rot.c j * sin a * sin b * cos c - k * cos a * sin b * cos c + j * cos a * sin c + k * sin a * sin c + i * cos b * cos c #!spiral inl calculate_x i j k (rot : rotation) = inl a, b, c = rot.a, rot.b, rot.c j * sin a * sin b * cos c - k * cos a * sin b * cos c + j * cos a * sin c + k * sin a * sin c + i * cos b * cos c #!markdown ### calculate_y #!fsharp let calculateY i j k (rot: Rotation) = let a, b, c = rot.a, rot.b, rot.c j * cos a * cos c + k * sin a * cos c - j * sin a * sin b * sin c + k * cos a * sin b * sin c - i * cos b * sin c #!spiral inl calculate_y i j k (rot : rotation) = inl a, b, c = rot.a, rot.b, rot.c j * cos a * cos c + k * sin a * cos c - j * sin a * sin b * sin c + k * cos a * sin b * sin c - i * cos b * sin c #!markdown ### calculate_z #!fsharp let calculateZ i j k (rot: Rotation) = let a, b, c = rot.a, rot.b, rot.c k * cos a * cos b - j * sin a * cos b + i * sin b #!spiral inl calculate_z i j k (rot : rotation) = inl a, b, c = rot.a, rot.b, rot.c k * cos a * cos b - j * sin a * cos b + i * sin b #!markdown ### calculate_for_surface #!fsharp let calculateForSurface cubeX cubeY cubeZ ch rot horizontalOffset = let x = calculateX cubeX cubeY cubeZ rot let y = calculateY cubeX cubeY cubeZ rot let z = calculateZ cubeX cubeY cubeZ rot + distanceFromCam let ooz = 1.0 / z let xp = int (float width / 2.0 + horizontalOffset + k1 * ooz * x * 2.0) let yp = int (float height / 2.0 + k1 * ooz * y) let idx = xp + yp * width if idx >= 0 && idx < width * height then Some (idx, (ooz, ch)) else None #!spiral let calculate_for_surface cube_x cube_y cube_z ch rot horizontal_offset = inl x = calculate_x cube_x cube_y cube_z rot inl y = calculate_y cube_x cube_y cube_z rot inl z = calculate_z cube_x cube_y cube_z rot + get_distance_from_cam () inl ooz = 1.0 / z inl xp = i32 (f64 (get_width ()) / 2.0 + horizontal_offset + get_k1 () * ooz * x * 2.0) inl yp = i32 (f64 (get_height ()) / 2.0 + get_k1 () * ooz * y) inl idx = xp + yp * get_width () if idx >= 0 && idx < get_width () * get_height () then Some (idx, (ooz, ch)) else None #!markdown ### frange #!fsharp let frange start stop step = seq { let mutable current = start while (step > 0.0 && current < stop) || (step < 0.0 && current > stop) do yield current current <- current + step } #!spiral inl frange start stop step : _ f64 = fun () => inl current = mut start loopw.while fun () => (step > 0f64 && *current < stop) || (step < 0 && *current > stop) fun () => *current |> yield current <- *current + step |> seq.new_seq #!markdown ### get_cube_points #!fsharp let getCubePoints (cube: Cube) rot = let cw = cube.cubeWidth let ho = cube.horizontalOffset let cubeRange = frange (-cw) cw incrementSpeed seq { for cubeX in cubeRange do for cubeY in cubeRange do let x = [ calculateForSurface cubeX cubeY (-cw) '@' rot ho calculateForSurface cw cubeY cubeX '$' rot ho calculateForSurface (-cw) cubeY (-cubeX) '~' rot ho calculateForSurface (-cubeX) cubeY cw '#' rot ho calculateForSurface cubeX (-cw) (-cubeY) ';' rot ho calculateForSurface cubeX cw cubeY '+' rot ho ] |> Seq.choose id yield! x } #!spiral inl get_cube_points (cube : cube) rot = inl cw = cube.cube_width inl ho = cube.horizontal_offset inl cube_range = frange -cw cw (get_increment_speed ()) inl cube_range = join cube_range inl get cube_x cube_y = [ calculate_for_surface cube_x cube_y -cw ';' rot ho calculate_for_surface cw cube_y cube_x '\\' rot ho calculate_for_surface -cw cube_y -cube_x '/' rot ho calculate_for_surface -cube_x cube_y cw '=' rot ho calculate_for_surface cube_x -cw -cube_y '>' rot ho calculate_for_surface cube_x cw cube_y '<' rot ho ] |> listm'.box inl get = join get inl box x : _ (i32 * f64 * char) = optionm'.box x inl box = join box fun () => backend_switch { Fsharp = fun () => $'for cube_x in !cube_range do' $'for cube_y in !cube_range do' $'let x = !get cube_x cube_y |> Seq.choose !box ' $'yield\! x' : () Python = fun () => $'cube_range = !cube_range ' $'get = !get ' $'box = !box ' $'for cube_x in cube_range:' $' for cube_y in cube_range:' $' x = get(cube_x)(cube_y)' $' for i in x:' $' i_ = box(i)' $' if i_ is not None: yield i' : () } |> seq.new_seq #!markdown ### generate_frame #!fsharp let generateFrame rot = let updates = cubes |> Seq.collect (fun cube -> getCubePoints cube rot) let buffer = Array.create (width * height) None updates |> Seq.iter (fun (idx, (ooz, ch)) -> match buffer.[idx] with | Some (prevOoz, _) when prevOoz >= ooz -> () | _ -> buffer.[idx] <- Some (ooz, ch) ) let sb = StringBuilder() for row in 0 .. (height - 1) do for col in 0 .. (width - 1) do let idx = col + row * width let ch = match buffer.[idx] with | Some (_, ch) -> ch | None -> backgroundChar sb.Append(ch) |> ignore sb.AppendLine() |> ignore sb.ToString() #!fsharp //// test let rot = { a = 0.0; b = 0.0; c = 0.0 } let frame = generateFrame rot Console.Write frame #!spiral inl generate_frame rot = inl updates : seq.seq' (int * (f64 * char)) = inl get_cube_points' cube : seq.seq' (int * (f64 * char)) = get_cube_points cube rot inl cubes = get_cubes () |> listm'.box backend_switch { Fsharp = fun () => inl get_cube_points' = join get_cube_points' (cubes |> $'Seq.collect !get_cube_points' ') : seq.seq' (int * (f64 * char)) Python = fun () => $'cubes = !cubes ' $'get_cube_points = !get_cube_points' ' $'[x for cube in cubes for x in get_cube_points(*cube)]' : seq.seq' (int * (f64 * char)) } inl none : _ (f64 * char) = None inl width = get_width () inl height = get_height () inl buffer = backend_switch { Fsharp = fun () => $'Array.create (!width * !height) !none ' : a int (option (f64 * char)) Python = fun () => $'[!none for _ in range(!width * !height)]' : a int (option (f64 * char)) } inl fn idx ((ooz : f64), (ch : char)) = match buffer |> am'.index idx with | Some (prev_ooz, _) when prev_ooz >= ooz => () | _ => inl x = (ooz, ch) |> Some backend_switch { Fsharp = fun () => $'!buffer.[!idx] <- !x ' : () Python = fun () => $'!buffer[!idx] = !x ' : () } backend_switch { Fsharp = fun () => updates |> $'Seq.iter (fun (struct (idx, ooz, ch)) -> !fn idx (ooz, ch))' : () Python = fun () => $'for (idx, ooz, ch) in !updates: !fn(idx)(ooz, ch)' : () } inl sb = "" |> sm'.string_builder inl fn1 row = inl fn2 col = inl idx = col + row * width inl ch = match buffer |> am'.index idx with | Some (_, ch) => ch | None => get_background_char () sb |> sm'.builder_append (ch |> sm'.obj_to_string) |> ignore backend_switch { Fsharp = fun () => $'for col in 0 .. (!width - 1) do !fn2 col' : () Python = fun () => $'for col in range(!width): !fn2(col)' : () } sb |> sm'.builder_append_line |> ignore backend_switch { Fsharp = fun () => $'for row in 0 .. (!height - 1) do !fn1 row' : () Python = fun () => $'for row in range(!height): !fn1(row)' : () } sb |> sm'.obj_to_string #!spiral //// test ///! fsharp ///! cuda ///! rust ///! typescript ///! python { a = 0.0; b = 0.0; c = 0.0 } |> generate_frame |> console.write_line #!markdown ### main_loop #!fsharp let rec mainLoop rot = async { let frame = generateFrame rot // Console.SetCursorPosition(0, 0) Console.Write(frame) let rot' = { a = rot.a + 0.05; b = rot.b + 0.05; c = rot.c + 0.01 } do! Async.Sleep 16 return! mainLoop rot' } #!spiral let rec main_loop max i rot = fun () => inl rot = join rot inl frame = rot |> generate_frame if max < 0 then run_target function | Fsharp (Native) => fun () => $'System.Console.SetCursorPosition (0, 0)' | Rust _ => fun () => open rust.rust_operators !\($'$"print\!(\\\"\\\\x1B[1;1H\\\")"') | TypeScript _ => fun () => open typescript_operators !\($'$"process.stdout.write(\'\\\\u001B[1;1H\')"') | Python _ => fun () => open python_operators // global "import sys" !\($'$"sys.stdout.write(\\\"\\\\033[1;1H\\\")"') | Cuda _ => fun () => global "import sys" $'sys.stdout.write("\\033[1;1H")' | _ => fun () => () frame |> console.write_line async.sleep 1 |> async.do if max > 0 && i >= max then () else { a = rot.a + 0.05; b = rot.b + 0.05; c = rot.c + 0.01 } |> main_loop max (i + 1) |> async.return_await' |> async.new_async_unit #!markdown ### main #!fsharp // [] let main argv = // Console.CursorVisible <- false Async.StartImmediate (mainLoop { a = 0.0; b = 0.0; c = 0.0 }) System.Threading.Thread.Sleep(1000) #!fsharp // main [||] #!spiral inl main (_args : array_base string) = inl console = run_target function | Fsharp (Wasm) => fun () => false | _ => fun () => ((join "VSCODE_PID") |> env.get_environment_variable |> sm'.length |> (=) 0i32) && ("AUTOMATION" |> env.get_environment_variable |> sm'.length |> (=) 0i32) if console then run_target function | Fsharp (Native) => fun () => $'System.Console.CursorVisible <- false' | Rust _ => fun () => open rust.rust_operators !\($'$"print\!(\\\"\\\\x1B[?25l\\\")"') | TypeScript _ => fun () => open typescript_operators !\($'$"process.stdout.write(\'\\\\u001B[?25l\')"') | Python _ => fun () => open python_operators python.import_all "sys" !\($'$"sys.stdout.write(\\\"\\\\033[?25l\\\")"') | _ => fun () => () main_loop (if console then -1i32 else 50) 1i32 { a = 0.0; b = 0.0; c = 0.0 } |> fun x => run_target_args' x function | Fsharp (Wasm) | TypeScript _ => fun x => x |> async.start_child |> ignore | Python _ => fun x => x |> async.start_immediate threading.sleep' 2000 | _ => fun x => x |> async.run_synchronously inl main () = backend_switch { Fsharp = fun () => $'let main_ = !main ' $'\#if \!FABLE_COMPILER_RUST' $'main_ [||]' : () $'\#else' $'let main args = main_ [||]; 0' : () $'\#endif' : () Python = fun () => main ;[] } : ()