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