典当在控制台上的排列错误

时间:2019-06-25 10:57:52

标签: f# console-application

我想在F#控制台应用程序中创建游戏Stratego。当前的显示(参见图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) [])))

图1

enter image description here

图2

enter image description here

实际上,将字符从蓝色的一侧移到灰色的区域后,它们在显示器上变成红色。但是,典当并没有改变先验条件。

代码如下:

    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

请原谅使用可变性或异常的几种用法,我只是想暂时解决此问题,等待使程序变得更好。

你能帮我吗?

0 个答案:

没有答案