summary refs log tree commit diff
path: root/main.fnl
diff options
context:
space:
mode:
Diffstat (limited to 'main.fnl')
-rw-r--r--main.fnl114
1 files changed, 75 insertions, 39 deletions
diff --git a/main.fnl b/main.fnl
index bf6933e..fae5445 100644
--- a/main.fnl
+++ b/main.fnl
@@ -5,6 +5,7 @@
   : kvflip
   : pprint
   : slice
+  : all-mills?
   :mill-at? mill-at-maker
   :space-is-neighbor? space-is-neighbor-maker
   } (require :lib.index))
@@ -28,21 +29,29 @@
 })
 
 
+;; story mode:
 ;; there are two players
-;; their names are LUIGI and MARIO
+;; their names are WIGI and MALO
 (local player {
-  :one 1 ;; luigi has light cows
-  :two 2 ;; mario has DARK cows >:)
+  :one 1 ;; wigi has light cows
+  :two 2 ;; malo has DARK cows >:)
 })
 
 
 ; return the numerical index (1-24) of a [A-Za-z0-9] formatted move
 (fn index-of-move [m]
-    (let [upper (string.upper m)
-          rev   (string.reverse upper)
-          idx   (head (icollect [i v (ipairs const.spaces)]
-                        (if (or (= v upper) (= v rev)) i)))]
-         idx))
+  (assert (= "string" (type m)) "index-of-move needs a string argument")
+  (let [upper (string.upper m)
+        rev   (string.reverse upper)
+        idx   (head (icollect [i v (ipairs const.spaces)]
+                      (if (or (= v upper) (= v rev)) i)))]
+       idx))
+
+
+(fn player-count [moves player]
+  (accumulate [count 0
+               _ x (ipairs moves)]
+              (if (= x player) (+ count 1) count)))
 
 
 ;; game state object
@@ -51,34 +60,57 @@
   :stage stages.placing
   :update (fn [self move]
     (case self.stage
-      4 ;; capture
+      4 ;; CAPTURE
         (do
-             ;; TODO: capturing during moving is not working?
           (tset self.moves (index-of-move move) 0)
           (tset self :player (self:next-player))
-          (tset self :stage (if (> self.pieces-placed 17) stages.moving stages.placing))
-          (tset self.moves (index-of-move move) self.player)
-          )
-      1 ;; placing
+          (let [flytime (and (> self.pieces-placed 17) (= 3 (player-count self.moves self.player)))
+                movetime (and (> self.pieces-placed 17) (> (player-count self.moves self.player) 3))]
+            (tset self :stage (if flytime stages.flying
+                                movetime stages.moving
+                                stages.placing))))
+      1 ;; PLACING
         (do
           (set self.pieces-placed (+ 1 self.pieces-placed))
           (tset self :stage (if (> self.pieces-placed 17) stages.moving stages.placing))
           (tset self.moves (index-of-move move) self.player)
-          (if (mill-at? self.moves (index-of-move move))
-              (tset self :stage stages.capture)
-              (tset self :player (self:next-player))
-              )
-          )
-      2 ;; moving
+          (let [flytime (and (> self.pieces-placed 17) (= 3 (player-count self.moves self.player)))
+                movetime (and (> self.pieces-placed 17) (> (player-count self.moves self.player) 3))
+                capturetime (mill-at? self.moves (index-of-move move))]
+            (tset self :stage (if
+                                capturetime stages.capture
+                                flytime stages.flying
+                                movetime stages.moving
+                                stages.placing))
+            (if (not capturetime) (tset self :player (self:next-player)))))
+      2 ;; MOVING
         (let [from (index-of-move (string.sub move 1 2))
               to  (index-of-move (string.sub move -2 -1))]
+          (tset self.moves from 0)
+          (tset self.moves to self.player)
+          (let [flytime (and (> self.pieces-placed 17) (= 3 (player-count self.moves (self:next-player))))
+                movetime (and (> self.pieces-placed 17) (> (player-count self.moves (self:next-player)) 3))
+                capturetime (mill-at? self.moves (index-of-move (string.sub move -2 -1)))]
+            (tset self :stage (if
+                                capturetime stages.capture
+                                flytime stages.flying
+                                movetime stages.moving
+                                stages.placing))
+            (if (not capturetime) (tset self :player (self:next-player)))))
+        3 ;; FLYING
+          (let [from (index-of-move (string.sub move 1 2))
+                to  (index-of-move (string.sub move -2 -1))]
             (tset self.moves from 0)
             (tset self.moves to self.player)
-            (if (mill-at? self.moves to)
-                (tset self :stage stages.capture)
-                (tset self :player (self:next-player))
-                )
-            )
+            (let [flytime (and (> self.pieces-placed 17) (= 3 (player-count self.moves (self:next-player))))
+                  movetime (and (> self.pieces-placed 17) (> (player-count self.moves (self:next-player)) 3))
+                  capturetime (mill-at? self.moves (index-of-move (string.sub move -2 -1)))]
+              (tset self :stage (if
+                                  capturetime stages.capture
+                                  flytime stages.flying
+                                  movetime stages.moving
+                                  stages.placing))
+              (if (not capturetime) (tset self :player (self:next-player)))))
     )
   )
   :next-player (fn [self] (if (= player.one self.player) player.two player.one))
@@ -98,6 +130,7 @@
 (game:init)
 
 
+; TODO: move to lib utility
 (fn string-upper [s]
   (.. (string.upper (string.sub s 1 1)) (string.sub s 2)))
 
@@ -136,27 +169,23 @@
   (let [unoccupied? 0] ; i.e. is move equal to 0
     (= unoccupied? (. game.moves (index-of-move m)))))
 
-
+; is the space m occupied by the player's opponent?
 (fn space-is-occupied-by-opponent? [m]
+  "is the space m occupied by the player's opponent?"
   (let [opponent (if (= game.player 1) 2 1)
         result (= opponent (. game.moves (index-of-move m))) ]
     result))
 
-
+; checks that the first 2 charcters and the last 2 characters
+; of a string are legal spaces
+; moving-format is the same as flying-format
 (fn moving-format? [m]
   (let [from (string.sub m 1 2)
         to (string.sub m -2 -1)]
-    (and (space-exists? from) (space-exists? to))))
+    (and (>= (length m) 4) (space-exists? from) (space-exists? to))))
+
 
 ; is this a legal move?
-; maybe some functional error handling here?
-;   https://mostly-adequate.gitbook.io/mostly-adequate-guide/ch08#pure-error-handling
-;   https://mostly-adequate.gitbook.io/mostly-adequate-guide/appendix_b#either
-; or maybe all i need is a case-try statement..
-;   https://fennel-lang.org/reference#case-try-for-matching-multiple-steps
-;   update: i didn't really like that
-; i think maybe i do want the monad after all..
-; i'll come back to it later
 (fn valid-move? [move]
   (or
     (and
@@ -169,8 +198,10 @@
       (= stages.capture game.stage)
       (or (space-is-occupied-by-opponent? move)
           (print "Choose an opponent's piece to remove."))
-      (or (not (mill-at? game.moves (index-of-move move)))
-          (print "Ma'am, it is ILLEGAL to break up a 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
       (= stages.moving game.stage)
@@ -184,8 +215,13 @@
           (print "That ain't your neighbor, Johnny")) 
       )
     (and
-      ;; TODO: add flying phase
       (= 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!")) 
       )
     )
   )