From 0d34e294488ea3cfea2a882a9b0a53a0e741c8b6 Mon Sep 17 00:00:00 2001 From: Macoy Madson Date: Sat, 6 Mar 2021 12:41:48 -0800 Subject: [PATCH] Got board loading working --- src/Main.cake | 172 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 153 insertions(+), 19 deletions(-) diff --git a/src/Main.cake b/src/Main.cake index bd8ec43..40954f5 100644 --- a/src/Main.cake +++ b/src/Main.cake @@ -16,6 +16,10 @@ ;; ;; Constants ;; + +(var debug-log-enabled bool true) +;; (var debug-log-enabled bool false) + (define-constant DATA_DIR "data/") (defmacro in-data-dir (path-in-data string) @@ -76,7 +80,11 @@ ;; 36 squares / 2 (min piece size) = 13; if two walls, need 14 (var g-game-board-pieces ([] 14 board-piece) (array 0)) -(defmacro on-each-existing-board-piece (piece-pointer-name symbol piece-index-name symbol &rest body any) +(defun-local game-board-reset-pieces () + (memset g-game-board-pieces 0 (sizeof g-game-board-pieces))) + +(defmacro on-each-board-piece (piece-pointer-name symbol piece-index-name symbol + &rest body any) (tokenize-push output (var next-piece-index int 0) @@ -86,10 +94,35 @@ (addr (at next-piece-index g-game-board-pieces))) (set (token-splice piece-index-name) next-piece-index) (incr next-piece-index) ;; In case expansions include (continue), we've already incremented - (when (path (token-splice piece-pointer-name) > num-cells) - (token-splice-rest body tokens)))) + (token-splice-rest body tokens))) + (return true)) + +(defmacro on-each-existing-board-piece (piece-pointer-name symbol piece-index-name symbol + &rest body any) + (tokenize-push + output + (on-each-board-piece + (token-splice piece-pointer-name) (token-splice piece-index-name) + (when (path (token-splice piece-pointer-name) > num-cells) + (token-splice-rest body tokens)))) (return true)) +(defun-local game-board-print () + (var row int 0) + (while (< row g-game-board-grid-size) + (var column int 0) + (while (< column g-game-board-grid-size) + (var index BoardPieceIndex (at row column g-game-board-occupied-state)) + (if (and (>= index 0) (field (at index g-game-board-pieces) num-cells)) + (scope + (var piece-in-cell (* board-piece) (addr (at index g-game-board-pieces))) + (var label char (path piece-in-cell > label)) + (printf "%c " (? label label '#'))) + (printf ". ")) + (incr column)) + (printf "\n") + (incr row))) + (defun-local print-board-piece (piece (* (const board-piece)) index int) (printf "Piece %c ([%d] %p ) \n\tgrid-position %d %d @@ -112,7 +145,8 @@ (sizeof g-game-board-occupied-state)) (on-each-existing-board-piece piece piece-index - (print-board-piece piece piece-index) + (when debug-log-enabled + (print-board-piece piece piece-index)) (var num-cells int (path piece > num-cells)) @@ -154,22 +188,100 @@ (set (deref occupy-space-pointer) piece-index) (incr cell-offset))) - ;; Print board - (var row int 0) - (while (< row g-game-board-grid-size) - (var column int 0) - (while (< column g-game-board-grid-size) - (var index BoardPieceIndex (at row column g-game-board-occupied-state)) - (if (and (>= index 0) (field (at index g-game-board-pieces) num-cells)) - (scope - (var piece-in-cell (* board-piece) (addr (at index g-game-board-pieces))) - (var label char (path piece-in-cell > label)) - (printf "%c " (? label label '#'))) - (printf ". ")) - (incr column)) - (printf "\n") - (incr row)) + (when debug-log-enabled + (game-board-print)) + + (return true)) +(defun-local game-board-piece-from-char (board-char char piece-cell-position grid-vec2) + (when (= board-char 'x') ;; Handle walls specially + (on-each-board-piece + piece piece-index + (unless (= 0 (field (deref piece) label)) + (continue)) + (set (field (deref piece) label) board-char) + (set (field (deref piece) grid-position) piece-cell-position) + (set (field (deref piece) is-wall) true) + (incr (field (deref piece) num-cells)) + (break)) + (return)) + + (on-each-board-piece + piece piece-index + (cond + ((= board-char (field (deref piece) label)) ;; Existing piece + (cond ;; Determine direction + ((> (vec-x piece-cell-position) (vec-x (field (deref piece) grid-position))) + (set (field (deref piece) is-vertical) false)) + ((> (vec-y piece-cell-position) (vec-y (field (deref piece) grid-position))) + (set (field (deref piece) is-vertical) true))) + (incr (field (deref piece) num-cells)) + (break)) + ((= 0 (field (deref piece) label)) ;; New piece + (set (field (deref piece) label) board-char) + (set (field (deref piece) grid-position) piece-cell-position) + (set (field (deref piece) is-primary-piece) (= board-char 'A')) + (incr (field (deref piece) num-cells)) + (break))))) + +;; (The following text is copied from [[https://www.michaelfogleman.com/rush/][Michael Fogleman's Rush Hour database]] +;; ([[https://web.archive.org/web/20201101044241/https://www.michaelfogleman.com/rush/][archive.org]]), +;; for easier reference) +;; The database is a simple text file with just a few columns. There is one row for every valid +;; (solvable, minimal) cluster. The columns are: number of moves, board description, and cluster +;; size (number of reachable states). +;; The board description is a 36-character string representing the state of the unsolved board. It +;; is a 6x6 2D array in row-major order. The characters in the description follow these simple rules: +;; - o empty cell +;; - x wall (fixed obstacle) +;; - A primary piece (red car) +;; - B - Z all other pieces +;; I used lowercase ~o~ instead of periods ~.~ for the empty cells in the database so that the entire board description can be selected with a double-click. +;; Example format: +;; 60 IBBxooIooLDDJAALooJoKEEMFFKooMGGHHHM 2332 +(defun-local game-board-load (fogleman-board-string (* (const char)) &return bool) + (game-board-reset-pieces) + + (var num-moves int 0) + (var num-states int 0) + (var pieces-read bool false) + (var buffer ([] 37 char) (array 0)) + (var write-char (* char) buffer) + (var current-char (* (const char)) fogleman-board-string) + (while (deref current-char) + (cond + ;; Space field delimiter + ((= (deref current-char) (space-hack)) + (cond + ((not num-moves) + (set num-moves (atoi buffer))) + (true ;; Reading pieces + (var board-char (* (const char)) buffer) + (while (deref board-char) + (cond + ((= (deref board-char) 'o') + (debug-log "empty\n")) ;; Empty space + (true ;; Wall or piece + (var char-index int (- board-char buffer)) + (var piece-cell-position grid-vec2 (array (% char-index g-game-board-grid-size) + (/ char-index g-game-board-grid-size))) + (debug-log "[%d] '%c' = (%d %d)\n" char-index (deref board-char) (vec-xy piece-cell-position)) + (game-board-piece-from-char (deref board-char) piece-cell-position))) + (incr board-char)))) + ;; Reset buffer + (memset buffer 0 (sizeof buffer)) + (set write-char buffer)) + (true + (set (deref write-char) (deref current-char)) + (incr write-char))) + (incr current-char)) + + (set num-states (atoi buffer)) + + (game-board-sync-occupied-state) + + (printf "Board loaded. %d moves, %d states.\n" num-moves num-states) + (printf "%s\n" fogleman-board-string) (return true)) ;; @@ -278,6 +390,8 @@ Rush Hour database from Michael Fogleman.\n\n") (unless (game-board-sync-occupied-state) (return 1)) + (game-board-load "60 IBBxooIooLDDJAALooJoKEEMFFKooMGGHHHM 2332") + ;; ;; Game loop ;; @@ -308,6 +422,17 @@ Rush Hour database from Michael Fogleman.\n\n") (sdl-shutdown window) (return 0)) +;; +;; Macros and generators +;; + +(defmacro debug-log (&rest arguments any) + (tokenize-push + output + (when debug-log-enabled + (printf (token-splice-rest arguments tokens)))) + (return true)) + (defgenerator define-constant (define-name symbol value any) (var define-statement (const ([] CStatementOperation)) (array @@ -331,6 +456,15 @@ Rush Hour database from Michael Fogleman.\n\n") statement (array-size statement) output))) +;; cakelisp's tokenizer doesn't properly parse ' ' +(defgenerator space-hack () + (var statement (const ([] CStatementOperation)) + (array + (array Keyword "' '" -1))) + (return (CStatementOutput environment context tokens startTokenIndex + statement (array-size statement) + output))) + ;; ;; Building ;;