用于跟踪OCaml中游戏板的数据结构

时间:2012-11-10 22:05:28

标签: arrays ocaml

我对OCaml相当新,我想实现一个类似于四线的游戏。 我需要的是一些保持游戏状态的数据结构。游戏板是一个4x4的正方形,共有16块瓷砖。 我正在寻找OCaml中的表示,这将使得在整个列,行或对角线中检索(或执行某些操作)所有元素变得容易和快速。 我会在这个游戏上进行极小极大搜索,这就是速度很重要的原因。

到目前为止,我已经考虑过一维列表。列表的问题在于很难确定哪些元素属于每个行/列/对角线,然后使用List.map检索它们。

我考虑过使用Array.make 4 (Array.make 4 Empty);;。这对于行来说绝对是完美的。很容易得到它们并在其上进行模式匹配。但是在单个列和对角线上进行模式匹配是一件苦差事。

我希望能够做的是有一个游戏板并返回包含所有行/列/对角线的列表列表的功能。我想做,例如,match (rows,columns,diagonals) with (Empty, Empty, Empty, Empty) -> something

3 个答案:

答案 0 :(得分:2)

由于长度是固定的,因此首选数组优于列表:它们使用的内存更少,读写速度更快。

我担心你需要编写一个函数来获取对角线,没有简单的模式匹配。 当你写“在[对角线]上做一些操作”时,我假设你正在考虑一个函数f,它采用一个长度为4的数组存储元素,例如[|Empty;Empty;Empty;Empty|]。 也许f可以将位置p作为参数,并将位置内的索引数组作为参数: f p [|x1,y1; x2,y2; x3,y3; x4,y4|]会提取正方形p.(x1).(y1) ... p.(x4).(y4)。然后,只需传递不同的xy,即可使f对行/列/对角线进行操作。

一旦代码正常运行并且您转向优化,您可能需要查看位向量: 如果你的minmax搜索树中存储了很多位置,减少内存占用意味着更多的缓存命中和更快的执行。你可能想要自己想在一个int中编码一个位置,但这是一些棘手的工作,你不想太早做。

答案 1 :(得分:1)

如何使用相应的坐标索引瓷砖?因此,您的一维列表中的元素将采用以下形式:

(int * int * ref tile)

然后你可以像这样过滤行/列/对角线:

行n: (前提条件:0< = n,u,v< = 3)

List.filter tiles (fun x -> match x with (u, v, _) -> u = n);;

列n: (前提条件:0< = n,u,v< = 3)

List.filter tiles (fun x -> match x with (u, v, _) -> v = n);;

对角线1: (前提条件:0< = u,v< = 3)

List.filter tiles (fun x -> match x with (u, v, _) -> u = v);;

对角线2: (前提条件:0< = u,v< = 3)

List.filter tiles (fun x -> match x with (u, v, _) -> u + v = 3);;

也应该可以用一个整数(一维列表中的瓦片的索引)来索引瓦片,但这需要在滤波器函数中进行一些计算(给定索引,找出坐标,然后决定它是否属于所需的行/列/对角线。

答案 2 :(得分:1)

有时匹配不起作用。在这里,我认为你应该尝试尽可能多地使用函数,然后将你的单元格排在第一列或第一列不会那么复杂,你甚至可以通过反转索引顺序从一个表示移动到另一个表示。 / p>

如果我使用以下类型:

type color = Red | Yellow;;
type cell  = Empty | Color of color;;
type board = Array.make 4 (Array.make 4 Empty);;

并首先决定列,然后以下函数将获取行或列:

let column (b: board) i j = b.(i).(j)
let row (b: board) i j = b.(j).(i)

对于对角线,有两组,一组向左上方向右下方,另一组向另一方向(从右上方向左下方):

let ldiag (b: board) i j = b.((i + j) mod 4).(j)
let rdiag (b: board) i j = b.((i - j + 4) mod 4).(j)

然后我想检查行,列或对角线只是检查该行的4个单元格。

let check predicate linef k = predicate (linef b k 0) && 
                               predicate (linef b k 1) && 
                               predicate (linef b k 2) && 
                               predicate (linef b k 3)
然后,例如,检查是否有红色的对角线:

let has_line linef b color = 
    let cmp x = x = color in
    let check k = check cmp linef b k in
    check 0 || check 1 || check 2 || check 3

let has_ldiag b color = has_line ldiag b color
let has_rdiag b color = has_line rdiag b color

let has_red_diagonal b = has_ldiag b Red | has_rdiag b Red