summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/tilde30.t39
-rw-r--r--lib/constants.fnl30
-rw-r--r--main.fnl20
-rw-r--r--src/game.fnl53
4 files changed, 99 insertions, 43 deletions
diff --git a/doc/tilde30.t b/doc/tilde30.t
index c931c07..8a6911a 100644
--- a/doc/tilde30.t
+++ b/doc/tilde30.t
@@ -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,
 or nothing at all.
 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
diff --git a/lib/constants.fnl b/lib/constants.fnl
index be9a6be..996c11c 100644
--- a/lib/constants.fnl
+++ b/lib/constants.fnl
@@ -97,9 +97,33 @@
   :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
  : neighbors
+ : rings
+ : spaces
  : stages
- : spaces}
-
+ }
diff --git a/main.fnl b/main.fnl
index c205454..8144b11 100644
--- a/main.fnl
+++ b/main.fnl
@@ -34,17 +34,23 @@
   ;; game loop
   (while (not (= game.stage const.stages.complete))
     (with-board game.moves)
-    ;; validation loop
     (var is-valid false)
     (var move "")
+    ;; validation loop
     (while (not is-valid)
       (set move (get-move))
-      (set is-valid (game.validate-move move))
-      (if (not is-valid)
-        (print "Try again.")
-        (do
-          (print (string.format "Turn %d: You chose %s" game.turns move))
-          (game:update move)))))
+      (case (pcall game.validate-move move)
+        (false msg)
+          (do
+            (let [(i j) (string.find msg ": ")
+                  key (string.sub msg (+ 1 j))]
+              (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
   (print "Congratulations!")
   (print (string.format "Player %d is the winner!" game.player)))
diff --git a/src/game.fnl b/src/game.fnl
index b48a6ac..4a24ce2 100644
--- a/src/game.fnl
+++ b/src/game.fnl
@@ -4,15 +4,15 @@
   } (require :lib.index))
 (local {
   : all-mills?
-  :mill-at? mill-at-maker
-  :no-moves? no-moves-maker
-  :space-is-neighbor? space-is-neighbor-maker
+  :mill-at? full-mill-at ;; stay with me...
+  :no-moves? full-no-moves
+  :space-is-neighbor? full-space-is-neighbor
   } (require :lib.game.index))
 (local const (require :lib.constants))
-;; front-loading with some partials
-(local mill-at? (partial mill-at-maker const.mills))
-(local space-is-neighbor? (partial space-is-neighbor-maker const.neighbors))
-(local no-moves? (partial no-moves-maker const.neighbors))
+;; front-loading the "fulls" with some partials
+(local mill-at? (partial full-mill-at const.mills))
+(local space-is-neighbor? (partial full-space-is-neighbor const.neighbors))
+(local no-moves? (partial full-no-moves const.neighbors))
 
 
 ;; story mode:
@@ -124,8 +124,7 @@
     ; 2 = Player 2
     ; NOTE: I think it might be a good idea to make moves
     ;       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?
+; note: string argument to assert funs are defined in /lib/constants
 (fn valid-move? [move]
   (or
     (and
       (= const.stages.placing game.stage)
-      (or (space-exists? move)
-          (print "That space does not exist!\nHint: 1a 1A A1 a1 are all the same move."))
-      (or (space-is-unoccupied? move)
-          (print "That space is occupied!")))
+      (assert (space-exists? move) :not-a-space)
+      (assert (space-is-unoccupied? move) :occupied))
     (and
       (= const.stages.capture game.stage)
-      (or (space-is-occupied-by-opponent? move)
-          (print "Choose an opponent's piece to remove."))
-      (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.")
-          ))
+      (assert (space-is-occupied-by-opponent? move) :not-an-opponent)
+      (assert (or (all-mills? game.moves game.player) (not (mill-at? game.moves (index-of-move move)))) :is-mill))
     (and
       (= const.stages.moving game.stage)
-      (or (moving-format? move)
-          (print "Try a move like A1A2 or A7 D7")) 
-      (or (not (space-is-occupied-by-opponent? (string.sub move 1 2)))
-          (print "That's not yours, don't touch it."))
-      (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")) )
+      (assert (moving-format? move) :bad-move-format) 
+      (assert (not (space-is-occupied-by-opponent? (string.sub move 1 2))) :not-yours)
+      (assert (space-is-unoccupied? (string.sub move -2 -1)) :occupied) 
+      (assert (space-is-neighbor? (index-of-move (string.sub move 1 2)) (index-of-move (string.sub move -2 -1))) :not-neighbor) )
     (and
       (= const.stages.flying game.stage)
-      (or (moving-format? move)
-          (print "Try a move like A1A2 or A7 D7")) 
-      (or (not (space-is-occupied-by-opponent? (string.sub move 1 2)))
-          (print "That's not yours, don't touch it."))
-      (or (space-is-unoccupied? (string.sub move -2 -1))
-          (print "That space is occupied!")))))
+      (assert (moving-format? move) :bad-move-format) 
+      (assert (not (space-is-occupied-by-opponent? (string.sub move 1 2))) :not-yours)
+      (assert (space-is-unoccupied? (string.sub move -2 -1)) :occupied))))
 
 (tset game :validate-move valid-move?)