F# 控制台板上的棋子排列错误

F# 控制台板上的棋子排列错误,f#,console-application,F#,Console Application,我想在F#控制台应用程序中创建游戏。当前显示(参见图1)没有显示任何错误的棋子位置,但是它们的位置似乎不同(参见图2,在一些移动之后)。该程序可以很好地检测障碍物和糟糕的动作,但我不明白为什么棋子没有正确地放置在“内存”中,这是相当令人恼火的。。。 我怀疑问题直接来自此函数,但我无法解决: let isWater ((x, y) : Coordinate) = ((x = 2 || x = 3) || (x = 6 || x = 7)) && (y = 4 || y =

我想在F#控制台应用程序中创建游戏。当前显示(参见图1)没有显示任何错误的棋子位置,但是它们的位置似乎不同(参见图2,在一些移动之后)。该程序可以很好地检测障碍物和糟糕的动作,但我不明白为什么棋子没有正确地放置在“内存”中,这是相当令人恼火的。。。 我怀疑问题直接来自此函数,但我无法解决:

let isWater ((x, y) : Coordinate) =
    ((x = 2 || x = 3) || (x = 6 || x = 7)) && (y = 4 || y = 5)

let defaultBoardGame =
    Array2D.init 10 10
        (fun y x ->
            if y <= 3 then Occuped (unknownPawn (x, y))
            elif isWater (x, y) then Water
            elif y = 4 || y = 5 then Free
            else (Occuped (pawn Allied Kind.Marshal (x, y) [])))
let is water((x,y):坐标)=
(x=2 | | x=3 | | |(x=6 | | x=7))和&(y=4 | | y=5)
让我们来做一个棋盘游戏=
Array2D.init 10
(有趣的y x->
如果y
如果y
//检查距离
((x+1=x'| | x-1=x'| | y+1=y'| | y-1=y')
&&(x=x’| | y=y’)&&(x为真)
//检查典当是否可以移动
让PawnCamove=not(pawn.kind=kind.Bomb | | pawn.kind=kind.Flag)
如果不正确,则移动,然后升高(BadMove newPos)
如果不稳定,则升高(不稳定新位置)
如果不是典当移动,则升高(典当移动新位置)
board Insert board pawn newPos
让我们来看看Gridbox=
System.Console.Clear()
Array2D.zeroCreate 11 11 |>Array2D.iteri
(乐趣y x->
如果x=0 | | y=0
然后
如果x=0,则System.Console.BackgroundColor
System.Console.SetCursorPosition(Console.CursorLeft+1,Console.CursorTop)
如果y>=6&&x.pint32
让我走=
管道2
(空间>>?坐标)
(空间1>>?坐标)
(乐趣p1 p2->(协调转换p1,协调转换p2)|>移动)
让帕斯克=
管道3
(空格>>?pstring“询问”)
(空间1>>?坐标)
(空间1>>?坐标)
(fun up1 p2->(coordinateConvert p1,coordinateConvert p2)|>提问)
让命令=
选择[pmove;pask]
让parse str=运行命令str
打开命令
打开FParsec.CharParsers
[]
让主=
让可变板=defaultBoardGame
尽管如此
显示板
假设(sprintf“转弯n°%d”(!gameTimeCounter+1))无
如果!游戏计时器%2=0
然后说“红色玩”(一些1)
或者说“蓝色游戏”(一些1)
printf“>”
让输入=System.Console.ReadLine()
如果!游戏计时器%2=0
然后尝试将解析输入与匹配
|成功(结果)——>
匹配结果
|移动(p1,p2)->线路板()//下一步要做
|失败(味精)——>说味精(大约10个)
具有
|BadMove p->say(sprintf“无法移动到%s”(corrdinateConvertToString p))(一些2)
|没有状态p->say(sprintf“在%s处有障碍物”(corrdinateConvertToString p))(大约2)
|典当移动p->say(sprintf“不允许%s处的典当移动”(corrdinateConvertToString p))(大约2)
gameTimeCounter:=!gameTimeCounter+1
0
请原谅对可变性或异常的一些使用,我只是暂时尝试解决这个问题,等待让程序变得更好


你能帮帮我吗?

在我看来,你与你是先按
x
还是先按
y
建立索引不一致(例如,你有一个
Array2D.set
先用
x
设置
Array2D.get
先用
y
建立索引,不同的
Array2D.get
先用
(fst newPos)
首先,它将是
x
).此外,坐标转换将字母视为x坐标,但这不是地图的外观…坐标的管理确实很有趣。为了方便起见,我偶尔交换参数x和y,而不是交换表达式的所有x和y。我正在修复,也许我会发现一些错误。
    module Game

        open System

        let gameTimeCounter = ref 0 

        type Camp = Allied | Ennemy

        type Kind
            = Bomb        = 0
            | Spy         = 1
            | Scout       = 2
            | Miner       = 3
            | Sergeant    = 4
            | Lieutenant  = 5
            | Captain     = 6
            | Major       = 7
            | Colonel     = 8
            | General     = 9
            | Marshal     = 10
            | Flag        = 11
            | Unknown     = 12

        type Coordinate = int * int

        exception ThereIsAnObstacle of Coordinate
        exception PawnCantMove of Coordinate
        exception BadMove of Coordinate

        [<StructuredFormatDisplay("{kind}")>]
        type Pawn =
            { camp  : Camp
            ; kind  : Kind
            ; pos   : Coordinate
            ; state : Coordinate list }

        let unknownPawn pos =
            { camp = Ennemy
            ; kind = Kind.Unknown
            ; pos  = pos
            ; state = [] }

        let pawn camp kind pos state =
            { camp  = camp
            ; kind  = kind
            ; pos   = pos
            ; state = state }

        type Case
            = Free
            | Water
            | Occuped of Pawn

        type Board = Case [,]

        let isWater ((x, y) : Coordinate) = ((x = 2 || x = 3) || (x = 6 || x = 7)) && (y = 4 || y = 5)

        let defaultBoardGame =
            Array2D.init 10 10
                (fun y x ->
                    if y <= 3 then Occuped (unknownPawn (x, y))
                    elif isWater (x, y) then Water
                    elif y = 4 || y = 5 then Free
                    else (Occuped (pawn Allied Kind.Marshal (x, y) [])))

        let boardInsert (board : Board) (pawn : Pawn) ((x, y) : Coordinate) =
            let mutable board = board
            Array2D.set board x y (Occuped {pawn with pos = (x, y); state = pawn.state @ [pawn.pos]})
            Array2D.set board (fst pawn.pos) (snd pawn.pos) Free
            board

        let boardRemove (board : Board) ((x, y) : Coordinate) =
            let mutable board = board
            Array2D.set board x y Free
            board

        let move (board : Board) (pawn : Pawn) (newPos : Coordinate) : Board =

            let envisagedCase = Array2D.get board (fst newPos) (snd newPos)

            // Check the simple move
            let isCorrectMove =
                match pawn.pos, newPos with
                    (x, y), (x', y') ->
                        // Check the proximity 
                        ((x + 1 = x' || x - 1 = x' || y + 1 = y' || y - 1 = y')
                        && (x = x'   || y = y'))   && (x <= 9    && y <= 9)

            // Check the obstacles
            let isObstacle =
                match envisagedCase with
                | Free -> false
                | Occuped _ | Water -> true

            // Check if the pawn can move
            let pawnCanMove = not (pawn.kind = Kind.Bomb || pawn.kind = Kind.Flag)

            if not isCorrectMove then raise (BadMove newPos)
            if isObstacle        then raise (ThereIsAnObstacle newPos)
            if not pawnCanMove   then raise (PawnCantMove newPos)

            boardInsert board pawn newPos

        let displayGridBox =
            System.Console.Clear ()
            Array2D.zeroCreate 11 11 |> Array2D.iteri
                (fun y x _ ->
                    if x = 0 || y = 0
                    then
                        if x = 0 then System.Console.BackgroundColor <- System.ConsoleColor.DarkYellow; System.Console.ForegroundColor <- System.ConsoleColor.White; printf "%c" (let c = (char (63 + y + x + 1)) in if c = '@' then ' ' else c)
                        elif y = 0 then System.Console.BackgroundColor <- System.ConsoleColor.DarkYellow; System.Console.ForegroundColor <- System.ConsoleColor.White; (if x = 10 then printf " %d" x else printf " %d " x)
                        else System.Console.ResetColor ()
                    else System.Console.ResetColor ()


 if x = 10 then printfn "")

    let pawnAtPos (board : Board) ((x, y) : Coordinate) : Pawn =
        let case = Array2D.get board y x
        match case with
        | Occuped pawn -> pawn
        | _ -> failwith "Nobody is at this position!"

    let displayBoard (board : Board) =
        displayGridBox
        System.Console.SetCursorPosition(0, 1)
        board |> Array2D.iteri
            (fun y x case ->
                System.Console.SetCursorPosition(Console.CursorLeft + 1, Console.CursorTop)
                if   y >= 6 && x <= 9 then System.Console.BackgroundColor <- System.ConsoleColor.DarkBlue
                elif isWater (x, y) then System.Console.BackgroundColor <- System.ConsoleColor.Cyan
                elif y >= 4 && x <= 9 then System.Console.BackgroundColor <- System.ConsoleColor.DarkGray
                elif y >= 0 && x <= 9 then System.Console.BackgroundColor <- System.ConsoleColor.DarkRed
                else System.Console.ResetColor ()
                match case with
                | Free | Water -> printf "   "
                | Occuped pawn ->
                    match pawn.camp with
                    | Allied -> System.Console.ForegroundColor <- System.ConsoleColor.Blue; printf " X "
                    | Ennemy -> System.Console.ForegroundColor <- System.ConsoleColor.Red; printf " X "
                System.Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop)
                if x = 9 then printfn "")
        System.Console.ResetColor ()

    let numberOfFlag = 1
    let numberOfMarshal = 1
    let numberOfGeneral = 1
    let numberOfColonel = 2
    let numberOfMajor = 3
    let numberOfCaptain = 4
    let numberOfLieutenant = 4
    let numberOfSergeant = 4
    let numberOfMiner = 5
    let numberOfScout = 8
    let numberOfSpy = 1
    let numberOfBomb = 6

    let say s = fun (second : int option) ->
        let second = if second.IsSome then second.Value else 0
        System.Console.SetCursorPosition(47, 7 + second)
        System.Console.ForegroundColor <- System.ConsoleColor.Yellow
        printfn "%s" s
        System.Console.ResetColor ()
        System.Console.SetCursorPosition(0, 11)

    let fight (board : Board) (pawn1 : Pawn) (pawn2 : Pawn) =
        say (sprintf "%A vs %A" pawn1.kind pawn2.kind) (Some -1)
        if pawn1.kind > pawn2.kind
        then say (sprintf "The %A %A win!" pawn1.camp pawn1.kind) None
             boardRemove board pawn2.pos
        elif pawn1.kind < pawn2.kind
        then say (sprintf "The %A %A win!" pawn2.camp pawn2.kind) None
             boardRemove board pawn1.pos
        else say "Fight equality!" None
             boardRemove (boardRemove board pawn1.pos) pawn2.pos

    let coordinateConvert ((x, y) : char * int) : Coordinate =
        let alphabet = "ABCDEFGHIJ"
        alphabet.IndexOf x, y - 1

    let corrdinateConvertToString ((x, y) : Coordinate) =
        sprintf "%c%d" (char (65 + x)) (y + 1)

    let tryGuessEnnemyBomb (board : Board) =

        0

    module Command =
        open FParsec

        type Command
            = Move of Coordinate * Coordinate
            | Ask  of Coordinate * Coordinate

        let coordinate = anyChar .>>. pint32

        let pmove =
            pipe2
                (spaces >>? coordinate)
                (spaces1 >>? coordinate)
                (fun p1 p2 -> (coordinateConvert p1, coordinateConvert p2) |> Move)

        let pask =
            pipe3
                (spaces >>? pstring "ask")
                (spaces1 >>? coordinate)
                (spaces1 >>? coordinate)
                (fun _ p1 p2 -> (coordinateConvert p1, coordinateConvert p2) |> Ask)

        let commands =
            choice [pmove; pask]

        let parse str = run commands str

    open Command
    open FParsec.CharParsers

    [<EntryPointAttribute>]
    let main _ =

        let mutable board = defaultBoardGame

        while true do
            displayBoard board
            say (sprintf "Turn n°%d" (!gameTimeCounter + 1)) None
            if !gameTimeCounter % 2 = 0
            then say "Red to play " (Some 1)
            else say "Blue to play" (Some 1)
            printf "> "
            let input = System.Console.ReadLine ()
            if !gameTimeCounter % 2 = 0
            then try match parse input with
                     | Success (result, _, _) ->
                         match result with
                         | Move (p1, p2) -> board <- move board (pawnAtPos board p1) p2
                         | Ask  (p1, p2) -> () // Next step to do
                     | Failure (msg, _, _) -> say msg (Some 10)
                 with
                    | BadMove p -> say (sprintf "Can't move to %s" (corrdinateConvertToString p)) (Some 2)
                    | ThereIsAnObstacle p -> say (sprintf "There is an obstacle at %s" (corrdinateConvertToString p)) (Some 2)
                    | PawnCantMove p -> say (sprintf "The pawn at %s is not allowed to move" (corrdinateConvertToString p)) (Some 2)
            gameTimeCounter := !gameTimeCounter + 1

        0