Move error handling to front-end
game.validate-move will now return an error code is the move is invalid. default error messages are found in lib/constants.fnl. error handling is now handled on the front end.main
parent
c7b2c98200
commit
9bf31e86ce
|
@ -272,5 +272,44 @@ and will be spending a lot of time on my back.
|
||||||
So I'm either going to get a lot on 9mm,
|
So I'm either going to get a lot on 9mm,
|
||||||
or nothing at all.
|
or nothing at all.
|
||||||
We'll see!
|
We'll see!
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.IP "20 - 21"
|
||||||
|
I was having back surgery!
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.IP "WEEK THREE REVIEW"
|
||||||
|
Finished the game, and then had a major surgery.
|
||||||
|
Doing some tidying up and housekeeping now.
|
||||||
|
Organzing tests,
|
||||||
|
breaking stuff out into modules.
|
||||||
|
Rewriting and refactoring a couple of functions.
|
||||||
|
Generally getting ready to start thinking
|
||||||
|
about Stretch Goal 1: Story Mode.
|
||||||
|
I have a vague inkling of an idea about
|
||||||
|
doing some kind of generative story / narration
|
||||||
|
based on each move of the game.
|
||||||
|
Assign symbolic meaning to the outer, middle, and inner rings of the board.
|
||||||
|
Add a little twist based on whether the move is a capture, a slide, a placement.
|
||||||
|
That kind of thing.
|
||||||
|
Not sure how I want to do it exactly yet.
|
||||||
|
I'd like to be able to show the story progress as you play.
|
||||||
|
But updating the story every move seems like kind of a lot.
|
||||||
|
Maybe just at every game phase.
|
||||||
|
So three installments.
|
||||||
|
One at the end of Placement,
|
||||||
|
the second at the end of Movement,
|
||||||
|
and the third at the end of the game?
|
||||||
|
Anyway.
|
||||||
|
|
||||||
|
Up next: big refactor of the validation logic.
|
||||||
|
I don't want it to just print to console
|
||||||
|
if I'm going to eventually support multiple frontends.
|
||||||
|
I need to return an error code or something
|
||||||
|
for the client to interpret.
|
||||||
|
I'm still interested in the Result / Either monad option
|
||||||
|
but I think I'm doing to first try the conventional lua way
|
||||||
|
and throw an error, and then 'pcall' the function and handle the error politely.
|
||||||
|
|
||||||
|
|
||||||
.pl \n[nl]u
|
.pl \n[nl]u
|
||||||
|
|
|
@ -97,9 +97,33 @@
|
||||||
:complete 5 ;; no more cows! jk the cows are fine. the game's just over okay
|
:complete 5 ;; no more cows! jk the cows are fine. the game's just over okay
|
||||||
})
|
})
|
||||||
|
|
||||||
{: board
|
|
||||||
|
;; errror codes
|
||||||
|
(local errors {
|
||||||
|
:not-a-space "That space does not exist!\nHint: 1a 1A A1 a1 are all the same move."
|
||||||
|
:occupied "That space is occupied!"
|
||||||
|
:not-an-opponent "Choose an opponent's piece to remove."
|
||||||
|
:is-mill "Ma'am, it is ILLEGAL to break up a mill."
|
||||||
|
:bad-move-format "Try a move like B2B4 or A7 D7"
|
||||||
|
:not-yours "That's not yours, don't touch it."
|
||||||
|
:not-neighbor "That ain't your neighbor, Johnny"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
;; if you like it then you shoulda put a ...
|
||||||
|
(local rings {
|
||||||
|
:outer [ 1 2 3 15 24 23 22 10 ]
|
||||||
|
:middle [ 4 5 6 14 21 20 19 11 ]
|
||||||
|
:inner [ 7 8 9 13 18 17 16 12 ]
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
: board
|
||||||
|
: errors
|
||||||
: mills
|
: mills
|
||||||
: neighbors
|
: neighbors
|
||||||
|
: rings
|
||||||
|
: spaces
|
||||||
: stages
|
: stages
|
||||||
: spaces}
|
}
|
||||||
|
|
||||||
|
|
20
main.fnl
20
main.fnl
|
@ -34,17 +34,23 @@
|
||||||
;; game loop
|
;; game loop
|
||||||
(while (not (= game.stage const.stages.complete))
|
(while (not (= game.stage const.stages.complete))
|
||||||
(with-board game.moves)
|
(with-board game.moves)
|
||||||
;; validation loop
|
|
||||||
(var is-valid false)
|
(var is-valid false)
|
||||||
(var move "")
|
(var move "")
|
||||||
|
;; validation loop
|
||||||
(while (not is-valid)
|
(while (not is-valid)
|
||||||
(set move (get-move))
|
(set move (get-move))
|
||||||
(set is-valid (game.validate-move move))
|
(case (pcall game.validate-move move)
|
||||||
(if (not is-valid)
|
(false msg)
|
||||||
(print "Try again.")
|
(do
|
||||||
(do
|
(let [(i j) (string.find msg ": ")
|
||||||
(print (string.format "Turn %d: You chose %s" game.turns move))
|
key (string.sub msg (+ 1 j))]
|
||||||
(game:update move)))))
|
(print (. const.errors key)))
|
||||||
|
(print "Try again."))
|
||||||
|
ok
|
||||||
|
(do
|
||||||
|
(set is-valid true)
|
||||||
|
(print (string.format "Turn %d: You chose %s" game.turns move))
|
||||||
|
(game:update move)))))
|
||||||
;; game is complete
|
;; game is complete
|
||||||
(print "Congratulations!")
|
(print "Congratulations!")
|
||||||
(print (string.format "Player %d is the winner!" game.player)))
|
(print (string.format "Player %d is the winner!" game.player)))
|
||||||
|
|
53
src/game.fnl
53
src/game.fnl
|
@ -4,15 +4,15 @@
|
||||||
} (require :lib.index))
|
} (require :lib.index))
|
||||||
(local {
|
(local {
|
||||||
: all-mills?
|
: all-mills?
|
||||||
:mill-at? mill-at-maker
|
:mill-at? full-mill-at ;; stay with me...
|
||||||
:no-moves? no-moves-maker
|
:no-moves? full-no-moves
|
||||||
:space-is-neighbor? space-is-neighbor-maker
|
:space-is-neighbor? full-space-is-neighbor
|
||||||
} (require :lib.game.index))
|
} (require :lib.game.index))
|
||||||
(local const (require :lib.constants))
|
(local const (require :lib.constants))
|
||||||
;; front-loading with some partials
|
;; front-loading the "fulls" with some partials
|
||||||
(local mill-at? (partial mill-at-maker const.mills))
|
(local mill-at? (partial full-mill-at const.mills))
|
||||||
(local space-is-neighbor? (partial space-is-neighbor-maker const.neighbors))
|
(local space-is-neighbor? (partial full-space-is-neighbor const.neighbors))
|
||||||
(local no-moves? (partial no-moves-maker const.neighbors))
|
(local no-moves? (partial full-no-moves const.neighbors))
|
||||||
|
|
||||||
|
|
||||||
;; story mode:
|
;; story mode:
|
||||||
|
@ -124,8 +124,7 @@
|
||||||
; 2 = Player 2
|
; 2 = Player 2
|
||||||
; NOTE: I think it might be a good idea to make moves
|
; NOTE: I think it might be a good idea to make moves
|
||||||
; a list of moves. so that there can be undo and history
|
; a list of moves. so that there can be undo and history
|
||||||
(set self.moves (fcollect [i 1 24] 0))
|
(set self.moves (fcollect [i 1 24] 0)))
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,40 +163,28 @@
|
||||||
|
|
||||||
|
|
||||||
; is this a legal move?
|
; is this a legal move?
|
||||||
|
; note: string argument to assert funs are defined in /lib/constants
|
||||||
(fn valid-move? [move]
|
(fn valid-move? [move]
|
||||||
(or
|
(or
|
||||||
(and
|
(and
|
||||||
(= const.stages.placing game.stage)
|
(= const.stages.placing game.stage)
|
||||||
(or (space-exists? move)
|
(assert (space-exists? move) :not-a-space)
|
||||||
(print "That space does not exist!\nHint: 1a 1A A1 a1 are all the same move."))
|
(assert (space-is-unoccupied? move) :occupied))
|
||||||
(or (space-is-unoccupied? move)
|
|
||||||
(print "That space is occupied!")))
|
|
||||||
(and
|
(and
|
||||||
(= const.stages.capture game.stage)
|
(= const.stages.capture game.stage)
|
||||||
(or (space-is-occupied-by-opponent? move)
|
(assert (space-is-occupied-by-opponent? move) :not-an-opponent)
|
||||||
(print "Choose an opponent's piece to remove."))
|
(assert (or (all-mills? game.moves game.player) (not (mill-at? game.moves (index-of-move move)))) :is-mill))
|
||||||
(or (or (all-mills? game.moves game.player)
|
|
||||||
(not (mill-at? game.moves (index-of-move move))))
|
|
||||||
(print "Ma'am, it is ILLEGAL to break up a mill.")
|
|
||||||
))
|
|
||||||
(and
|
(and
|
||||||
(= const.stages.moving game.stage)
|
(= const.stages.moving game.stage)
|
||||||
(or (moving-format? move)
|
(assert (moving-format? move) :bad-move-format)
|
||||||
(print "Try a move like A1A2 or A7 D7"))
|
(assert (not (space-is-occupied-by-opponent? (string.sub move 1 2))) :not-yours)
|
||||||
(or (not (space-is-occupied-by-opponent? (string.sub move 1 2)))
|
(assert (space-is-unoccupied? (string.sub move -2 -1)) :occupied)
|
||||||
(print "That's not yours, don't touch it."))
|
(assert (space-is-neighbor? (index-of-move (string.sub move 1 2)) (index-of-move (string.sub move -2 -1))) :not-neighbor) )
|
||||||
(or (space-is-unoccupied? (string.sub move -2 -1))
|
|
||||||
(print "That space is occupied!"))
|
|
||||||
(or (space-is-neighbor? (index-of-move (string.sub move 1 2)) (index-of-move (string.sub move -2 -1)))
|
|
||||||
(print "That ain't your neighbor, Johnny")) )
|
|
||||||
(and
|
(and
|
||||||
(= const.stages.flying game.stage)
|
(= const.stages.flying game.stage)
|
||||||
(or (moving-format? move)
|
(assert (moving-format? move) :bad-move-format)
|
||||||
(print "Try a move like A1A2 or A7 D7"))
|
(assert (not (space-is-occupied-by-opponent? (string.sub move 1 2))) :not-yours)
|
||||||
(or (not (space-is-occupied-by-opponent? (string.sub move 1 2)))
|
(assert (space-is-unoccupied? (string.sub move -2 -1)) :occupied))))
|
||||||
(print "That's not yours, don't touch it."))
|
|
||||||
(or (space-is-unoccupied? (string.sub move -2 -1))
|
|
||||||
(print "That space is occupied!")))))
|
|
||||||
|
|
||||||
(tset game :validate-move valid-move?)
|
(tset game :validate-move valid-move?)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue