我想在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
图2
实际上,将字符从蓝色的一侧移到灰色的区域后,它们在显示器上变成红色。但是,典当并没有改变先验条件。
代码如下:
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
请原谅使用可变性或异常的几种用法,我只是想暂时解决此问题,等待使程序变得更好。
你能帮我吗?