如何返回参数作为联合用例值? [英] How can I return a parameter as a union case value?

查看:78
本文介绍了如何返回参数作为联合用例值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何返回参数作为联合用例值?

How can I return a parameter as a union case value?

我具有以下功能:

let jumpBlack ((blackChecker:BlackChecker),(blackCheckers:BlackChecker list))  (redPiece:RedPiece) =

    let yIncrementValue = -1
    let minY = 0

    match redPiece with
    | RedPiece.RedChecker rc -> 
       let position = rc.Position |> jump blackChecker.Position yIncrementValue
       match position with
       | pos when pos = rc.Position -> RedPiece.RedChecker { rc with Position= position }, blackCheckers
       | pos when pos.Y = minY      -> RedPiece.RedKing    { RedKing.Position=position },  blackCheckers |> remove blackChecker
       | _ ->                          RedPiece.RedChecker { rc with Position= position }, blackCheckers |> remove blackChecker

    | RedPiece.RedKing rk -> 
       let position = rk.Position |> jump blackChecker.Position yIncrementValue
       match position with
       | pos when pos = rk.Position -> RedPiece.RedKing { rk with Position= position }, blackCheckers
       | pos when pos.Y = minY      -> RedPiece.RedKing { Position=position }, blackCheckers |> remove blackChecker
       | _                          -> RedPiece.RedKing { rk with Position= position }, blackCheckers |> remove blackChecker

具体来说,我想将上述功能的这一部分重构为一个功能:

match redPiece with
| RedPiece.RedChecker rc -> 
   let position = rc.Position |> jump blackChecker.Position yIncrementValue
   match position with
   | pos when pos = rc.Position -> RedPiece.RedChecker { rc with Position= position }, blackCheckers
   | pos when pos.Y = minY      -> RedPiece.RedKing    { RedKing.Position=position },  blackCheckers |> remove blackChecker
   | _ ->                          RedPiece.RedChecker { rc with Position= position }, blackCheckers |> remove blackChecker

| RedPiece.RedKing rk -> 
   let position = rk.Position |> jump blackChecker.Position yIncrementValue
   match position with
   | pos when pos = rk.Position -> RedPiece.RedKing { rk with Position= position }, blackCheckers
   | pos when pos.Y = minY      -> RedPiece.RedKing { Position=position }, blackCheckers |> remove blackChecker
   | _                          -> RedPiece.RedKing { rk with Position= position }, blackCheckers |> remove blackChecker

如何重构上面重复的代码?

我坚持如何删除重复项,并且仍然返回两种不同的联合类型(即红色检查器和红色国王)

I'm stuck on how to remove the duplication and still return the two different union types (i.e. red checker and red king)

域:

(* Types *)
type North = NorthEast | NorthWest
type South = SouthEast | SouthWest

type Direction = 
    | NorthEast 
    | NorthWest
    | SouthEast 
    | SouthWest

type Position =     { X:int; Y:int }

type BlackChecker = { Position:Position }
type RedChecker =   { Position:Position }
type BlackKing =    { Position:Position }
type RedKing =      { Position:Position }

type Checker =
    | BlackChecker of BlackChecker
    | RedChecker   of RedChecker
    | BlackKing    of BlackKing
    | RedKing      of RedKing

type King = 
    | BlackKing of BlackKing
    | RedKing of RedKing

type RedPiece = 
    | RedChecker of RedChecker 
    | RedKing of RedKing

(* Functions *)
let rec remove item list = list |> List.filter (fun x -> x <> item)

let setRowPosition y1 y2 y3 index =
    match index with 
    | x when x < 4 -> { X=x; Y=y1 }
    | x when x < 8 -> { X=x-4; Y=y2 }
    | _            -> { X=index-8; Y=y3 }

let initializeBlack () =
    let setPosition index =
        index |> setRowPosition 7 6 5

    let blackCheckers = List.init 12 setPosition |> List.map (fun pos -> { BlackChecker.Position= { X=pos.X; Y=pos.Y } })
    blackCheckers

let initializeRed () =
    let setPosition index =
        index |> setRowPosition 0 1 2

    let redCheckers =   List.init 12 setPosition |> List.map (fun pos -> { RedChecker.Position= { X=pos.X; Y=pos.Y } })
    redCheckers

let set (x, y) positions (position:Position) =
    match not (positions |> List.exists (fun pos -> pos = { X=x; Y=y })) with
    | true -> { X=x; Y=y }
    | false -> position

let moveBlack direction positions (checker:BlackChecker) =
    let position = checker.Position

    match direction with
    | North.NorthEast -> { BlackChecker.Position= (positions, position) ||> set ((position.X + 1), (position.Y + 1 )) } 
    | North.NorthWest -> { BlackChecker.Position= (positions, position) ||> set ((position.X - 1), (position.Y + 1 )) }

let moveRed direction positions (checker:RedChecker) =
    let position = checker.Position

    match direction with
    | South.SouthEast -> { RedChecker.Position= (positions, position) ||> set ((position.X + 1), (position.Y - 1 )) }
    | South.SouthWest -> { RedChecker.Position= (positions, position) ||> set ((position.X - 1), (position.Y - 1 )) }

let moveKing direction positions (king:King) =

    let position = match king with
                   | King.BlackKing bk -> bk.Position
                   | King.RedKing   rk -> rk.Position

    let result = match direction with
                 | NorthEast -> (positions, position) ||> set ((position.X + 1), (position.Y + 1 ))
                 | NorthWest -> (positions, position) ||> set ((position.X - 1), (position.Y + 1 ))
                 | SouthEast -> (positions, position) ||> set ((position.X + 1), (position.Y - 1 ))
                 | SouthWest -> (positions, position) ||> set ((position.X - 1), (position.Y - 1 ))

    match king with
    | King.BlackKing _ -> King.BlackKing { BlackKing.Position= result }
    | King.RedKing   _ -> King.RedKing   { RedKing.Position=   result }

let jump target yDirection source =
    let updateX value = { X=target.X + value
                          Y=target.Y + yDirection }
    match source with
    | position when position.Y + yDirection = target.Y &&
                    position.X + 1 = target.X -> updateX 1

    | position when position.Y + yDirection = target.Y &&
                    position.X - 1 = target.X -> updateX -1
    | _ -> source

let jumpRed ((redChecker:RedChecker), (redCheckers:RedChecker list)) (blackChecker:BlackChecker) =

    let yIncrementValue = 1
    let maxY = 7
    let position = blackChecker.Position |> jump redChecker.Position yIncrementValue

    match position with
    | pos when pos = blackChecker.Position -> BlackChecker { blackChecker with Position= position }, redCheckers
    | pos when pos.Y = maxY                -> Checker.BlackKing { BlackKing.Position=position }, redCheckers |> remove redChecker
    | _ -> BlackChecker { blackChecker with Position= position }, redCheckers |> remove redChecker

let jumpBlack ((blackChecker:BlackChecker),(blackCheckers:BlackChecker list))  (redPiece:RedPiece) =

    let yIncrementValue = -1
    let minY = 0

    match redPiece with
    | RedPiece.RedChecker rc -> 
       let position = rc.Position |> jump blackChecker.Position yIncrementValue
       match position with
       | pos when pos = rc.Position -> RedPiece.RedChecker { rc with Position= position }, blackCheckers
       | pos when pos.Y = minY      -> RedPiece.RedKing    { RedKing.Position=position },  blackCheckers |> remove blackChecker
       | _ ->                          RedPiece.RedChecker { rc with Position= position }, blackCheckers |> remove blackChecker

    | RedPiece.RedKing rk -> 
       let position = rk.Position |> jump blackChecker.Position yIncrementValue
       match position with
       | pos when pos = rk.Position -> RedPiece.RedKing { rk with Position= position }, blackCheckers
       | pos when pos.Y = minY      -> RedPiece.RedKing { Position=position }, blackCheckers |> remove blackChecker
       | _                          -> RedPiece.RedKing { rk with Position= position }, blackCheckers |> remove blackChecker

测试:

[<Test>
let ``red king jumps checker``() =
    let blackChecker = { BlackChecker.Position= { X=1 ; Y=1 } }
    let target = (blackChecker, [blackChecker])

    RedKing { RedKing.Position= { X=0 ; Y=2 } } |> jumpBlack target
                                                |> fst
                                                |> should equal (RedPiece.RedKing { RedKing.Position= { X=2 ; Y=0 } })

[<Test>]
let ``black checker removed after being jumped``() =
    let target = { BlackChecker.Position= { X=1 ; Y=1 } }, []
    RedChecker { RedChecker.Position= { X=2 ; Y=2 } } |> jumpBlack target
                                                      |> snd
                                                      |> should equal []
[<Test>]
let ``red checker jumps black checker southeast``() =
    let blackChecker = { BlackChecker.Position= { X=3 ; Y=2 } }
    let target = blackChecker, [blackChecker]

    RedChecker { RedChecker.Position= { X=2 ; Y=3 } } |> jumpBlack target
                                                      |> fst
                                                      |> should equal (RedChecker { RedChecker.Position= { X=4 ; Y=1 } })

推荐答案

好吧,您的模型真的很复杂...我做了以下简化:

Alright your model is really complicated... I made the following simplification:

type Position = { X:int; Y:int }

type Color = 
    | Red
    | Black

type PieceType = 
    | King
    | Checker

type Piece = Color*PieceType*Position

然后翻译您得到的jumpBlack函数:

Then translating your jumpBlack function I get:

let jumpBlack ((blackChecker:Piece),(blackCheckers:Piece list))  (redPiece:Piece) =

    let yIncrementValue = -1
    let minY = 0

    match redPiece, blackChecker with
    | (Red, Checker, position), (_, _, blackCheckerPosition) -> 
       let newposition = position |> jump blackCheckerPosition yIncrementValue
       match newposition with
       | pos when pos = position ->    (Red, Checker, pos), blackCheckers
       | pos when pos.Y = minY      -> (Red, King, pos) ,  blackCheckers |> remove blackChecker
       | pos ->                          (Red, Checker, pos), blackCheckers |> remove blackChecker
    | (Red, King, position), (_, _, blackCheckerPosition) -> 
       let newposition = position |> jump blackCheckerPosition yIncrementValue
       match newposition with
       | pos when pos = position -> (Red, King, pos), blackCheckers
       | pos when pos.Y = minY      -> (Red, King, pos), blackCheckers |> remove blackChecker
       | pos                          -> (Red, King, pos), blackCheckers |> remove blackChecker
    | _ -> failwith "Invalid" //Deal with Black pieces here! 

但是现在,重构代码确实非常容易,因为我们看到,如果pos不等于minY值,它将保持相同的PieceType,但是如果达到minY,它将始终变为King.

But now, it's really easy to refactor the code since we see that if pos isn't equal to the minY value, it stays the same PieceType, but if it reaches minY it always becomes a King.

let jumpBlackNew ((blackChecker:Piece),(blackCheckers:Piece list))  (redPiece:Piece) =

    let yIncrementValue = -1
    let minY = 0

    match redPiece, blackChecker with
    | (Red, pieceType, position), (_, _, blackCheckerPosition) -> 
       let newposition = position |> jump blackCheckerPosition yIncrementValue
       match newposition with
       | pos when pos = position ->    (Red, pieceType, pos), blackCheckers
       | pos when pos.Y = minY      -> (Red, King, pos) ,  blackCheckers |> remove blackChecker
       | pos ->                        (Red, pieceType, pos), blackCheckers |> remove blackChecker
    | _ -> failwith "Invalid" //Deal with Black pieces here!

这也使您可以更轻松地同时进行黑色和红色方格跳线动作.

This also makes it much easier for you to make jump take in both black and red checkers.

这篇关于如何返回参数作为联合用例值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆