第一篇随笔,先写点简单的。初学OCaml请大家多多包涵,多提意见。
这篇文章实现一个最简单的分型--递归二叉树。当然这个分型是有限的,并没有制造它的无限放大模式。
首先构造递归二叉树的最小递归单元。
整个递归树就是在树叉部分不停的迭代这个结构制作成的。
现在分别是以当前点(current_point)位基准点,当前角度(current_angle )为基准角度计算一定长度(length)一定角度(angle)左子树和右子树定位的位置。
左子树:
(*float -> int -> float -> int * int = int * int*) let left angle length current_angle current_point=
let x = round ((sin (angle +. current_angle)) *. float_of_int length) + (fst current_point) and y = round ((cos (angle +. current_angle)) *. float_of_int length) + (snd current_point) in (x, y)
右子树:
(*float -> int -> float -> int * int = int * int*) let right angle length current_angle current_point= let x = round ((sin (current_angle -. angle)) *. float_of_int length) + (fst current_point) and y = round ((cos (current_angle -. angle)) *. float_of_int length) + (snd current_point) in (x, y)
其中:round函数式做四舍五入的,因为OCaml没有提供四舍五入的函数,自己动手实现
(* 制造一个四舍五入的函数, Ocaml并没有提供四舍五入的函数, 所以利用OCaml提供的 ceil float -> float函数 floor float -> float函数 构造四舍五入函数 round float -> int*)let round x = let decimals = x -. (float_of_int (truncate x)) in match decimals with | 0. -> int_of_float x | d when d >= 0.5 -> int_of_float (ceil x) | d -> int_of_float (floor x);;
递归的画整个树,并且还为整个树的每个层级分配一个颜色。以下是画树的代码
(*画树: 树的参数为左右张开的角度,angle 树的层次,由num step构成,num为第一层的高,step每层得递减高度 起始颜色:col代表起始颜色 大小是一个0 ~ 255*255*255的数字*)let draw_tree angle num step col = let colorstep = (255 * 255 * 255 - col ) / (num / step) in let convert_color col_int = Graphics.rgb (col_int mod (255 * 255)) (col_int / 255 mod 255) (col_int mod 255) in let left angle length current_angle current_point= let x = round ((sin (angle +. current_angle)) *. float_of_int length) + (fst current_point) and y = round ((cos (angle +. current_angle)) *. float_of_int length) + (snd current_point) in (x, y) and right angle length current_angle current_point= let x = round ((sin (current_angle -. angle)) *. float_of_int length) + (fst current_point) and y = round ((cos (current_angle -. angle)) *. float_of_int length) + (snd current_point) in (x, y) in let rec draw_subtree current_angle n innercol= match n with | n when n <= 0 -> (); | n -> let current_point = Graphics.current_point () in let left_point = left angle n current_angle current_point in let right_point = right angle n current_angle current_point in Graphics.set_color (convert_color innercol) ; Graphics.lineto (fst left_point) (snd left_point); draw_subtree (current_angle +. angle) (n - step) (innercol + colorstep); Graphics.moveto (fst current_point) (snd current_point); Graphics.set_color (convert_color innercol) ; Graphics.lineto (fst right_point) (snd right_point); draw_subtree (current_angle -. angle) (n - step) (innercol + colorstep); in draw_subtree 0. num col;;
完事具备,剩下的事情就是初始化系统环境,并画一棵树。
#load "graphics.cma";; (*加载OCaml图形库*)Graphics.open_graph "";; (*打开窗口*)Graphics.set_window_title "recursion_tree";; (*设置窗口标题*)
(*移动到图像中央*)Graphics.moveto 500 0 ;;(*画一棵树,角度为0.2,一层高度为45 每阶递减3 初始颜色 255 * 255*)draw_tree 0.2 45 3 (1 * 255 * 255);;
最终一颗递归树形成了:
以下为完整代码:
#load "graphics.cma";; (*加载OCaml图形库*)Graphics.open_graph "";; (*打开窗口*)Graphics.set_window_title "recursion_tree";; (*设置窗口标题*)(* 制造一个四舍五入的函数, Ocaml并没有提供四舍五入的函数, 所以利用OCaml提供的 ceil float -> float函数 floor float -> float函数 构造四舍五入函数 round float -> int*)let round x = let decimals = x -. (float_of_int (truncate x)) in match decimals with | 0. -> int_of_float x | d when d >= 0.5 -> int_of_float (ceil x) | d -> int_of_float (floor x);; (*画树: 树的参数为左右张开的角度,angle 树的层次,由num step构成,num为第一层的高,step每层得递减高度 起始颜色:col代表起始颜色 大小是一个0 ~ 255*255*255的数字*)let draw_tree angle num step col = let colorstep = (255 * 255 * 255 - col ) / (num / step) in let convert_color col_int = Graphics.rgb (col_int mod (255 * 255)) (col_int / 255 mod 255) (col_int mod 255) in let left angle length current_angle current_point= let x = round ((sin (angle +. current_angle)) *. float_of_int length) + (fst current_point) and y = round ((cos (angle +. current_angle)) *. float_of_int length) + (snd current_point) in (x, y) and right angle length current_angle current_point= let x = round ((sin (current_angle -. angle)) *. float_of_int length) + (fst current_point) and y = round ((cos (current_angle -. angle)) *. float_of_int length) + (snd current_point) in (x, y) in let rec draw_subtree current_angle n innercol= match n with | n when n <= 0 -> (); | n -> let current_point = Graphics.current_point () in let left_point = left angle n current_angle current_point in let right_point = right angle n current_angle current_point in Graphics.set_color (convert_color innercol) ; Graphics.lineto (fst left_point) (snd left_point); draw_subtree (current_angle +. angle) (n - step) (innercol + colorstep); Graphics.moveto (fst current_point) (snd current_point); Graphics.set_color (convert_color innercol) ; Graphics.lineto (fst right_point) (snd right_point); draw_subtree (current_angle -. angle) (n - step) (innercol + colorstep); in draw_subtree 0. num col;;(*移动到图像中央*)Graphics.moveto 500 0 ;;(*画一棵树,角度为0.2,一层高度为45 每阶递减3 初始颜色 255 * 255*)draw_tree 0.2 45 3 (1 * 255 * 255);;