Fri, 07 Jul 2006

Functional Triangles.

Our friend Mark Greenaway has been playing around with Ocaml. He's written a program that draws n-sided polygons (for odd n) and then draws lines between the midpoint of each line segment and the opposite vertex to show that all of those lines will coincide at a point which is the middle of the polygon.

Mark's solution to this problem is pretty typical of a programmer who comes to Ocaml from imperative languages. Typically it uses a bunch of for loops when better, more functional techniques exist :-).

Here's my solution to the problem:

(* To compile this: ocamlc graphics.cma triangles2.ml -o triangles2 *)
open Graphics

let pi = 3.1415926535897932384626433832795
let window_width = 640
let window_height = 480

let gen_points count =
  let cx = window_width / 2 in
  let cy = window_height / 2 in
  let ary = Array.create count 0 in
  let radius = 0.9 *. float_of_int cy in
  let delta_angle = 2.0 *. pi /. (float_of_int count) in
  Array.mapi (fun i x ->
    ( cx + truncate (radius *. sin (float_of_int i *. delta_angle)),
      cy + truncate (radius *. cos (float_of_int i *. delta_angle))
    )) ary

let gen_outer_lines points =
  set_color black ;
  let (x, y) =  points.(Array.length points - 1) in
  moveto x y ;
  Array.iter (fun (x, y) -> lineto x y) points

let gen_center_lines points =
  set_color red ;
  let do_line sx sy ex ey =
    moveto sx sy ;
    lineto ex ey
  in
  let len = Array.length points in
  let mid = len / 2 in
  Array.iteri (fun i (sx, sy) ->
    let (first, second) = ((i + mid) mod len, (i + mid + 1) mod len) in
    let (ex1,  ey1) = points.(first) in
    let (ex2,  ey2) = points.(second) in
    do_line sx sy ((ex1 + ex2) / 2) ((ey1 + ey2) / 2)
    ) points

let _ =
  let points = gen_points 5 in
  open_graph " 640x480" ;
  gen_outer_lines points ;
  gen_center_lines points ;
  set_color blue ;
  Array.iter (fun (x, y) -> fill_circle x y 10) points ;
  ignore (read_line ())

There's a few algorithmic tweaks here and there but the big difference is the complete lack of for loops.

Posted at: 00:09 | Category: CodeHacking/Ocaml | Permalink