feat: capturing cannot break a mill
refactors the way mill? is written to make it a little more versatile
Tento commit je obsažen v:
		
							rodič
							
								
									7c07d6e6ec
								
							
						
					
					
						revize
						7776b2011a
					
				| @ -2,7 +2,7 @@ | ||||
| (local {: flip} (require :lib.flip)) | ||||
| (local {: head} (require :lib.head)) | ||||
| (local {: keys} (require :lib.keys)) | ||||
| (local {: mill?} (require :lib.mill)) | ||||
| (local {: mill-at?} (require :lib.mill)) | ||||
| (local {: pprint} (require :lib.tableprint)) | ||||
| (local {: slice} (require :lib.slice)) | ||||
| (local {: tail} (require :lib.tail)) | ||||
| @ -12,7 +12,7 @@ | ||||
|  : flip | ||||
|  : head | ||||
|  : keys | ||||
|  : mill? | ||||
|  : mill-at? | ||||
|  : pprint | ||||
|  : slice | ||||
|  : tail | ||||
|  | ||||
							
								
								
									
										53
									
								
								lib/mill.fnl
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								lib/mill.fnl
									
									
									
									
									
								
							| @ -1,45 +1,42 @@ | ||||
| (local {: contains} (require :lib.contains)) | ||||
| 
 | ||||
| 
 | ||||
| (fn get-candidates [all-mills next-move] | ||||
|   "a list of mills that contain next-move" | ||||
|   (icollect [_ mill (ipairs all-mills)] (if (contains mill next-move) mill))) | ||||
| 
 | ||||
| (fn candidates->moves [candidates current-moves move player] | ||||
|   "a list of the candidate mills expressed as current moves" | ||||
|   (icollect [_ spaces (ipairs candidates)] | ||||
|     (icollect [_ space (ipairs spaces)]  | ||||
|               (if (= space move) :x (. current-moves space))))) | ||||
| 
 | ||||
| (fn moves->mills [spaces player] | ||||
|   "a list of bools if the candidate moves + player are all the same" | ||||
|   (let [next-move (icollect [_ y (ipairs spaces)] | ||||
|                             (icollect [_ x (ipairs y)] | ||||
|                                       (if (= x :x) player x))) ] | ||||
|     (icollect [_ move (ipairs next-move)] | ||||
|       (accumulate [acc true | ||||
|                    idx m (ipairs move)] | ||||
|         (and acc (= player m)))))) | ||||
| 
 | ||||
| (fn any [t] | ||||
| 	(accumulate [acc false | ||||
|   "take a list of booleans, returns true if any of them are true" | ||||
|   (accumulate [acc false | ||||
|                i x (ipairs t)] | ||||
|                (or acc x))) | ||||
| 
 | ||||
| (fn move-mills [moves-list] | ||||
|   (icollect [_ moves (ipairs moves-list)] | ||||
|     (let [player (. moves 1)] | ||||
|       (accumulate [acc true | ||||
|                    _ m (ipairs moves)] | ||||
|                   (and acc (not= m 0) (= player m)))))) | ||||
| 
 | ||||
| (fn mill? [all-mills current-moves next-move player] | ||||
|   "Does the current move for the current player create a mill?" | ||||
|   (let [candidates (get-candidates all-mills next-move) | ||||
|         moves (candidates->moves candidates current-moves next-move player) | ||||
|         mills (moves->mills moves player) | ||||
|         result (any mills)] | ||||
| 		result)) | ||||
| (fn candidate-moves [candidates moves] | ||||
|   "Just turning board spaces into player moves" | ||||
|   (icollect [_ spaces (ipairs candidates)] | ||||
|             (icollect [_ space (ipairs spaces)] | ||||
|                       (. moves space)))) | ||||
| 
 | ||||
| {: mill? | ||||
| (fn mill-at? [all-mills current-moves move] | ||||
|   "Is there a mill at this move?" | ||||
|   (let [candidates (get-candidates all-mills move) | ||||
|         my-moves (candidate-moves candidates current-moves) | ||||
|         my-mills (move-mills my-moves) | ||||
|         result (any my-mills) | ||||
|         ] | ||||
|     result)) | ||||
| 
 | ||||
| {: mill-at? | ||||
|  ;; not for consumption, | ||||
|  ;; just for testing: | ||||
|  : get-candidates | ||||
|  : candidates->moves | ||||
|  : moves->mills | ||||
|  : candidate-moves | ||||
|  : move-mills | ||||
|  : any | ||||
|  } | ||||
|  | ||||
| @ -1,89 +1,48 @@ | ||||
| (let [{: describe | ||||
|        :end test-end} (require :lib.test) | ||||
|       {: mill? | ||||
|       {: mill-at? | ||||
|        : get-candidates | ||||
|        : candidates->moves | ||||
|        : moves->mills | ||||
|        : move-mills | ||||
|        : candidate-moves | ||||
|        : any | ||||
|        } (require :lib.mill) | ||||
|       {: mills } (require :lib.constants) | ||||
|       with-mills (partial mill? mills)] | ||||
| 
 | ||||
|       with-mills (partial mill-at? mills)] | ||||
| 
 | ||||
|   (describe "Mill" (fn [] | ||||
|     (describe "#get-candidates()" (fn [t] | ||||
|         (t | ||||
|          (let [move 3 | ||||
| 							 expected [[1 2 3] [3 15 24]] | ||||
|                moves [ 1 1 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] | ||||
| 							] | ||||
| 				 	{:given (string.format "a move of %d" move) | ||||
| 					 :should "return [[1 2 3] [3 15 24]]"  | ||||
|            : expected  | ||||
|            :actual (get-candidates mills move) | ||||
|            })) | ||||
|           (let [move 3 | ||||
|                 expected [[1 2 3] [3 15 24]] | ||||
|                 moves [ 1 1 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] | ||||
|                ] | ||||
|             {:given (string.format "a move of %d" move) | ||||
|             :should "return [[1 2 3] [3 15 24]]"  | ||||
|             : expected  | ||||
|             :actual (get-candidates mills move) | ||||
|             })) | ||||
|         (t | ||||
|          (let [move 1 | ||||
| 							 expected [[1 2 3] [1 10 22]] | ||||
|                moves [ 0 0 0 ] | ||||
| 							] | ||||
| 				 	{:given (string.format "a move of %d" move) | ||||
| 					 :should "return [[1 2 3] [1 10 22]]"  | ||||
|            : expected  | ||||
|            :actual (get-candidates mills move) | ||||
|            })))) | ||||
| 				 | ||||
| 
 | ||||
|     (describe "#candidates->moves()" (fn [t] | ||||
|           (t  | ||||
| 						(let [candidates [[1 2 3] [1 10 22]]  | ||||
| 								  moves [0 1 1 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 2] | ||||
| 								  expected [[:x 1 1] [:x 2 2]] | ||||
| 								  move 1 | ||||
| 								  player 2 | ||||
| 								  ] | ||||
| 							 {:given "a list of spaces and of current moves" | ||||
| 								:should "return a map of spaces to moves" | ||||
| 								: expected | ||||
| 								:actual (candidates->moves candidates moves move player) | ||||
| 								})) | ||||
|           (t  | ||||
| 						(let [candidates [[1 2 3] [3 15 24]] | ||||
| 								  moves [ 1 1 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] | ||||
| 							 		expected [[1 1 :x] [:x 0 0]] | ||||
| 									move 3 | ||||
| 									player 1 | ||||
| 									] | ||||
| 							 {:given "a list of candidates and of current moves" | ||||
| 								:should "return an x-map of spaces to moves" | ||||
| 								: expected | ||||
| 								:actual (candidates->moves candidates moves move player) | ||||
| 								})))) | ||||
| 
 | ||||
| 
 | ||||
|     (describe "#moves->mills()" (fn [t] | ||||
|           (t  | ||||
| 						(let [spaces [[:x 1 1] [:x 2 2]] | ||||
| 									moves [0 1 1 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 2] | ||||
| 									player 2 | ||||
| 									] | ||||
| 							 {:given "a list of spaces and of current moves" | ||||
| 								:should "return a map of spaces to moves" | ||||
| 								:expected [false true] | ||||
| 								:actual (moves->mills spaces player) | ||||
| 								})) | ||||
|           (t  | ||||
| 						(let [spaces [[1 1 :x] [:x 0 0]] | ||||
| 								  moves [ 1 1 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] | ||||
| 									player 1 | ||||
| 									] | ||||
| 							 {:given "a list of canditate-moves and of current moves" | ||||
| 								:should "return a map of spaces to moves" | ||||
| 								:expected [true false] | ||||
| 								:actual (moves->mills spaces player) | ||||
| 								})))) | ||||
| 
 | ||||
| 
 | ||||
|           (let [move 1 | ||||
|                 expected [[1 2 3] [1 10 22]] | ||||
|                 moves [ 0 0 0 ] | ||||
|                ] | ||||
|             {:given (string.format "a move of %d" move) | ||||
|             :should "return [[1 2 3] [1 10 22]]"  | ||||
|             : expected  | ||||
|             :actual (get-candidates mills move) | ||||
|             })) | ||||
|         (t | ||||
|           (let [move 1 | ||||
|                 moves [2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] | ||||
|                 expected [[1 2 3] [1 10 22]] | ||||
|                ] | ||||
|             {:given (string.format "a move of %d" move) | ||||
|             :should "still return [[1 2 3] [1 10 22]]"  | ||||
|             : expected  | ||||
|             :actual (get-candidates mills move) | ||||
|             })) | ||||
|         )) | ||||
|          | ||||
|     (describe "#any()" (fn [t] | ||||
|         (t {:given "a table of false false true" | ||||
|             :should "return true" | ||||
| @ -106,36 +65,86 @@ | ||||
|             :actual (any [true]) | ||||
|            }))) | ||||
| 
 | ||||
|     (describe "#move-mills()" (fn [t] | ||||
|       (t | ||||
|         (let [moves [[1 1 1] [0 2 2]] | ||||
|               ] | ||||
|           {:given "a list of moves" | ||||
|            :should "turn them into true/false if they are mills" | ||||
|            :expected [true false] | ||||
|            :actual (move-mills moves) | ||||
|            })) | ||||
|       (t | ||||
|         (let [moves [[0 1 1] [0 2 2]] | ||||
|               ] | ||||
|           {:given "no mills" | ||||
|            :should "should return false" | ||||
|            :expected [false false] | ||||
|            :actual (move-mills moves) | ||||
|            })) | ||||
|       (t | ||||
|         (let [moves [[2 2 2] [2 0 0]] | ||||
|               ] | ||||
|           {:given "mill, no mill" | ||||
|            :should "should return true false" | ||||
|            :expected [true false] | ||||
|            :actual (move-mills moves) | ||||
|            })) | ||||
|       )) | ||||
| 
 | ||||
|     (describe "#mill?()" (fn [t] | ||||
|     (describe "#candidate-moves()" (fn [t] | ||||
|       (t (let [spaces [[1 2 3] [1 10 22]] | ||||
|                moves [2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] | ||||
|                ] | ||||
|          {:given "spaces [[1 2 3] [1 10 22]]" | ||||
|           :should "map to moves" | ||||
|           :expected [[2 2 2] [2 0 0]] | ||||
|           :actual (candidate-moves spaces moves)  | ||||
|           } | ||||
|          ) | ||||
|        )   | ||||
|     )) | ||||
| 
 | ||||
|     (describe "#mill-at?()" (fn [t] | ||||
|         (t  | ||||
|           (let [move 1 | ||||
|                 player 1 | ||||
| 								moves [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] | ||||
|                 with-moves (partial with-mills moves)] | ||||
|             {:given (string.format "a move of P%d:%d with moves %s" player move (table.concat moves ",")) | ||||
|              :should "not be a mill" | ||||
|                 moves [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] | ||||
|                 ] | ||||
|             {:given "no mills" | ||||
|              :should "return false" | ||||
|              :expected false | ||||
|              :actual (with-moves move player) | ||||
|              :actual (mill-at? mills moves move) | ||||
|              })) | ||||
|         (t  | ||||
|           (let [move 3 | ||||
|                 player 1 | ||||
|                 moves [1 1 0] | ||||
|           (let [move 4 | ||||
|                 moves [1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] | ||||
|                 with-mills (partial mill-at? mills)  | ||||
|                 with-moves (partial with-mills moves)] | ||||
|             {:given (string.format "a move of P%d:%d with moves %s" player move (table.concat moves ",")) | ||||
|              :should "be a mill" | ||||
|              :expected true | ||||
|              :actual (with-moves move player) | ||||
|             {:given "a mill but not at Move" | ||||
|              :should "return false" | ||||
|              :expected false | ||||
|              :actual (with-moves move) | ||||
|              })) | ||||
|         (t  | ||||
|           (let [move 3 | ||||
|                 player 1 | ||||
|                 moves [ 1 1 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] | ||||
|           (let [move 1 | ||||
|                 moves [2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] | ||||
|                 with-mills (partial mill-at? mills)  | ||||
|                 with-moves (partial with-mills moves)] | ||||
|             {:given (string.format "a move of P%d:%d with moves %s" player move (table.concat moves ",")) | ||||
|              :should "be a mill" | ||||
|             {:given "a mill" | ||||
|              :should "return true" | ||||
|              :expected true | ||||
|              :actual (with-moves move player) | ||||
|              })))) | ||||
|              :actual (with-moves move) | ||||
|              })) | ||||
|         (t  | ||||
|           (let [move 1 | ||||
|                 moves [2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] | ||||
|                 with-mills (partial mill-at? mills)  | ||||
|                 with-moves (partial with-mills moves)] | ||||
|             {:given "a mill" | ||||
|              :should "return the opposite of false" | ||||
|              :expected false | ||||
|              :actual (not (with-moves move)) | ||||
|              })) | ||||
|         )) | ||||
| 
 | ||||
|     (test-end)))) | ||||
|  | ||||
							
								
								
									
										47
									
								
								main.fnl
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								main.fnl
									
									
									
									
									
								
							| @ -5,12 +5,12 @@ | ||||
|   : flip | ||||
|   : pprint | ||||
|   : slice | ||||
|   :mill? mill-maker | ||||
|   :mill-at? mill-at-maker | ||||
|   } (require :lib.index)) | ||||
| ;; constants...more like just strings | ||||
| (local const (require :lib.constants)) | ||||
| ;; front-loading mill with a partial | ||||
| (local mill? (partial mill-maker const.mills)) | ||||
| (local mill-at? (partial mill-at-maker const.mills)) | ||||
| 
 | ||||
| 
 | ||||
| ; there are three phases of play: | ||||
| @ -40,6 +40,7 @@ | ||||
| ; 0 = unoccupied | ||||
| ; 1 = Player 1 | ||||
| ; 2 = Player 2 | ||||
| ;; TODO: move this to game.moves? | ||||
| (local moves (fcollect [i 1 24] 0)) | ||||
| 
 | ||||
| 
 | ||||
| @ -48,14 +49,21 @@ | ||||
|   :player player.one | ||||
|   :stage stages.placing | ||||
|   :update (fn [self move] | ||||
|              (if (mill? moves move self.player) | ||||
|                (do | ||||
|                  (print "Mooooooo") | ||||
|                  (tset self :stage stages.capture) | ||||
|                  ) | ||||
|                (tset self :player (if (= player.one self.player) player.two player.one)) | ||||
|                ) | ||||
|              ) | ||||
|     (case self.stage | ||||
|       4 ;; capture | ||||
|         (do | ||||
|           (tset moves move 0) | ||||
|           (tset self :player (self:next-player)) | ||||
|           (tset self :stage stages.placing) | ||||
|           ) | ||||
|       1 ;; placing | ||||
|         (if (mill-at? moves move) | ||||
|           (tset self :stage stages.capture) | ||||
|           (tset self :player (self:next-player)) | ||||
|           ) | ||||
|     ) | ||||
|   ) | ||||
|   :next-player (fn [self] (if (= player.one self.player) player.two player.one)) | ||||
| }) | ||||
| 
 | ||||
| 
 | ||||
| @ -72,8 +80,8 @@ | ||||
|         (do | ||||
|           (let [offset (+ index slots) | ||||
|                 myslice (slice moves index offset)] | ||||
| 						(print (string.format row-template (table.unpack myslice))) | ||||
| 						(set index offset))) | ||||
|             (print (string.format row-template (table.unpack myslice))) | ||||
|             (set index offset))) | ||||
|         (print row)))) | ||||
|   (print (.. "Stage: " (string-upper (. (flip stages) game.stage)))) | ||||
|   (print (.. "Player " game.player "'s turn:"))) | ||||
| @ -107,8 +115,9 @@ | ||||
| 
 | ||||
| 
 | ||||
| (fn space-is-occupied-by-opponent? [m] | ||||
| 	(let [opponent (if (= game.player 1) 2 1)] | ||||
|     (= opponent (. moves (index-of-move m))))) | ||||
|   (let [opponent (if (= game.player 1) 2 1) | ||||
|         result (= opponent (. moves (index-of-move m))) ] | ||||
|     result)) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @ -126,14 +135,15 @@ | ||||
|     (and | ||||
|       (= stages.placing game.stage) | ||||
|       (or (space-exists? move) | ||||
|           (print "That space does not exist!\nHint: 1a 1A A1 a1 are all equal moves.")) | ||||
|           (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!"))) | ||||
|     (and | ||||
|       ;; TODO: add capturing phase | ||||
|       (= stages.capturing game.stage) | ||||
| 			(or (space-is-occupied-by-opponent? move) | ||||
|       (= stages.capture game.stage) | ||||
|       (or (space-is-occupied-by-opponent? move) | ||||
|           (print "Choose an opponent's piece to remove.")) | ||||
|       (or (not (mill-at? moves (index-of-move move))) | ||||
|           (print "Ma'am, it is ILLEGAL to break up a mill.")) | ||||
|       ) | ||||
|     (and | ||||
|       ;; TODO: add flying phase | ||||
| @ -143,7 +153,6 @@ | ||||
|   ) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ; get player input | ||||
| (fn get-move [] | ||||
|   (io.read)) | ||||
|  | ||||
		Načítá se…
	
	
			
			x
			
			
		
	
		Odkázat v novém úkolu
	
	Zablokovat Uživatele