首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >轻量级TicTacToe在F#中的应用

轻量级TicTacToe在F#中的应用
EN

Code Review用户
提问于 2015-02-02 08:55:15
回答 1查看 579关注 0票数 5

这更像是TicTacToe的一个‘模型’,因为您将看到它不是“游戏化”,因为它将允许输入和输出,也不会记录游戏中的任何“活动”状态,但这些都是微不足道的实现。

我在我的函数的函数范型上欺骗了一点来旋转网格,但这是有意的,通过突变来旋转网格比采用纯函数的方式更容易,最后,状态只在局部函数中被操纵,所以我认为它是否定的。

还有很多时候,我忽略了对简洁性的优化。人们可能会认为,这并不是最优性能是关键的领域,所以我已经将获取尽可能简洁和可读的代码列为优先事项。

代码语言:javascript
运行
复制
module TicTacToe

type Mark = None | Cross | Nought 
type Outcome = None | NoughtWon | CrossWon | Draw

let emptyGrid = (None, Array2D.init 3 3 (fun _ _ -> Mark.None))

let flatten (x: 'a [,]) = x |> Seq.cast<'a>

let rotateCw (grid: 'a [,]) =
    let out = Array2D.zeroCreate 3 3
    for y in 0..2 do
        for x in 0..2 do
            out.[x,y] <- grid.[0 + y, 2 - x]
    out

let checkOutcome grid = 
    let checkSeg seg =
        seq { for i in 0..2 do
                let count = 
                    seg i |> Array.sumBy 
                        (function Cross -> 1 | Nought -> 2 | _ -> 0)
                if count = 6 || count = 3 then 
                    yield (if count = 6 then NoughtWon else CrossWon) }
        |> Seq.tryFind ((<>)None)
    let vertical =
        let rot = grid |> rotateCw
        (fun x -> rot.[x, 0..2])
    let horizontal = (fun y -> grid.[0..2, y])
    let diagonal (m:_[,]) = (fun _ -> [| for i in 0..2 -> m.[i,i] |])
    let diagonal2 = grid |> rotateCw |> diagonal
    let checks = 
        [checkSeg vertical; checkSeg horizontal; 
         checkSeg (diagonal grid); checkSeg diagonal2]
    if checks |> List.exists (Option.isSome) then
        checks |> List.find (Option.isSome) |> Option.get
    elif grid |> flatten |> Seq.forall ((<>)Mark.None) then Draw
    else None

let placeMark pos mark (_, grid: Mark [,]) = 
    let res = 
        Array2D.init 3 3 (fun x y -> 
            if (x,y) = pos then mark else grid.[x,y])
    (checkOutcome res, res)
EN

回答 1

Code Review用户

回答已采纳

发布于 2015-02-03 03:32:48

设emptyGrid =(无,Array2D.init 3 3 (fun __ -> Mark.None))

这可以使用Array2D.create进行简化:

代码语言:javascript
运行
复制
let emptyGrid = None, Array2D.create 3 3 Mark.None

rotateCwplaceMark中,x作为第一个索引,y作为第二个索引。这是令人困惑的,因为通常的顺序是行然后列。例如,

代码语言:javascript
运行
复制
let test = Array2D.create 3 3 Mark.None
test.[2, 1] <- Cross
printfn "%A" test

[[None; None; None]
 [None; None; None]
 [None; Cross; None]]

rotateCw可以简化(假设上一段中的索引更改)

代码语言:javascript
运行
复制
let rotateCw (grid : 'a[,]) = Array2D.init 3 3 (fun y x -> grid.[2 - x, y])

我觉得这个版本的placeMark更易读

代码语言:javascript
运行
复制
let placeMark (x, y) mark (_, grid : Mark[,]) =
    let res = Array2D.copy grid
    res.[y, x] <- mark
    (checkOutcome res, res)
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/79326

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档