|
type operands = |
|
| Incr_PTR |
|
| Decr_PTR |
|
| Incr_value |
|
| Decr_value |
|
| Output |
|
| Input |
|
| While' |
|
| End |
|
|
|
type instructions = IntCst of int |
|
|
|
let get_correction base previous ch = |
|
let factor, delta = |
|
let factor = ch / base in |
|
let delta = ch - (factor * base) in |
|
if delta > base / 2 then |
|
let corr = ch - ((factor + 1) * base) in |
|
(factor + 1, corr) |
|
else (factor, delta) |
|
in |
|
let adelta = abs delta and delta_previous = ch - previous in |
|
if adelta + 3 + factor < abs delta_previous then (factor, delta) |
|
else (0, delta_previous) |
|
|
|
(* Count the instruction number for represent the character ch inside a loop *) |
|
let get_loop_size base (previous_char, current_base) ch = |
|
let factor, delta = get_correction base previous_char ch in |
|
let count_letter = if factor = 0 then 0 else 3 in |
|
(ch, current_base + factor + abs delta + count_letter) |
|
|
|
(* Extract the min and max values from the different values *) |
|
let get_extrema (mini, maxi) chr = (min mini chr, max maxi chr) |
|
|
|
let choose_base str = |
|
let min_base, max_base = |
|
Common.fold_string get_extrema (max_int, min_int) str |
|
in |
|
let rec _choose_base (current, value) base = |
|
if base > max_base then current |
|
else |
|
let base_value = |
|
Common.fold_string (get_loop_size base) (0, base) str |> snd |
|
in |
|
let new_val = |
|
if base_value < value then (base, base_value) else (current, value) |
|
in |
|
_choose_base new_val (base + 1) |
|
in |
|
|
|
let init_base = float_of_int min_base |> sqrt |> int_of_float in |
|
_choose_base (init_base, max_int) 1 |
|
|
|
let rec to_instruction = function |
|
| IntCst i -> |
|
let op = if i > 0 then Incr_value else Decr_value in |
|
Common.make_list (abs i) op |
|
|
|
and print str = |
|
let base = choose_base str in |
|
|
|
let build_char factor _delta = to_instruction (IntCst factor) |
|
and print_char _factor delta = to_instruction (IntCst delta) @ [ Output ] in |
|
|
|
let build_str (previous, coef_acc, printer_acc) ch = |
|
let factor, delta = get_correction base previous ch in |
|
let prev = match factor with 0 -> [] | _ -> [ Incr_PTR ] in |
|
( ch, |
|
coef_acc @ prev @ build_char factor delta, |
|
printer_acc @ prev @ print_char factor delta ) |
|
in |
|
|
|
let _, coef, printer = Common.fold_string build_str (0, [], []) str in |
|
let count_letter = Common.count_list Incr_PTR coef in |
|
|
|
to_instruction (IntCst base) |
|
@ (While' :: coef) |
|
@ Common.make_list count_letter Decr_PTR |
|
@ (Decr_value :: End :: printer) |
|
|
|
let to_brainfuck = function |
|
| Incr_PTR -> ">" |
|
| Decr_PTR -> "<" |
|
| Incr_value -> "+" |
|
| Decr_value -> "-" |
|
| Output -> "." |
|
| Input -> "+" |
|
| While' -> "[" |
|
| End -> "]" |
|
|
|
let to_ook = function |
|
| Incr_PTR -> "Ook. Ook? " |
|
| Decr_PTR -> "Ook? Ook. " |
|
| Incr_value -> "Ook. Ook. " |
|
| Decr_value -> "Ook! Ook! " |
|
| Output -> "Ook! Ook. " |
|
| Input -> "Ook. Ook! " |
|
| While' -> "Ook! Ook? " |
|
| End -> "Ook? Ook! " |
|
|
|
(* |
|
let _ = |
|
let str = "Hello_ World!" in |
|
print str |
|
|> List.iter (fun x -> print_string (to_brainfuck x)) |
|
|
|
|
|
; print_endline "Ook? Ook?" |
|
|
|
|
|
*) |