#lang r7rs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Maze ADT ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The maze contains the logical grid with cells. Each cell has a type ;; (wall, coin, empty, key, door). This ADT contains NO graphics code. (define-library (pacman-project adt maze) (import (scheme base) (pacman-project constants)) (export make-maze) (begin ;; make-maze :: -> maze ;; Creates a new maze object with the full grid. (define (make-maze) ;; The maze grid: 31 rows x 28 columns. ;; vector is used because it is mutable (unlike #()). (define grid (vector (vector 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1) (vector 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1) (vector 1 0 1 1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1) (vector 1 0 1 0 0 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1) (vector 1 0 1 4 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1) (vector 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1) (vector 1 0 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 0 1) (vector 1 0 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 0 1) (vector 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 1) (vector 1 1 1 1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1) (vector 2 2 2 2 2 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 2 2 2 2 2) (vector 2 2 2 2 2 1 0 1 1 0 0 0 0 0 0 0 0 0 0 1 1 0 1 2 2 2 2 2) (vector 2 2 2 2 2 1 0 1 1 0 1 1 1 4 4 1 1 1 0 1 1 0 1 2 2 2 2 2) (vector 1 1 1 1 1 1 0 1 1 0 1 2 2 2 2 2 2 1 0 1 1 0 1 1 1 1 1 1) (vector 2 0 0 0 0 0 0 0 0 0 1 2 2 2 2 2 2 1 0 0 0 0 0 0 0 0 0 2) (vector 1 1 1 1 1 1 0 1 1 0 1 2 2 2 2 2 2 1 0 1 1 0 1 1 1 1 1 1) (vector 2 2 2 2 2 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 1 2 2 2 2 2) (vector 2 2 2 2 2 1 0 1 1 0 0 0 0 0 0 0 0 0 0 1 1 0 1 2 2 2 2 2) (vector 2 2 2 2 2 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 1 2 2 2 2 2) (vector 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1) (vector 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1) (vector 1 0 1 1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1) (vector 1 0 1 1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1) (vector 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1) (vector 1 1 1 0 1 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 1 1 0 1 1 1) (vector 1 1 1 0 1 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 1 1 0 1 1 1) (vector 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 4 1 0 0 0 0 0 0 1) (vector 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 0 0 1 1 1 1 1 0 1) (vector 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1) (vector 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1) (vector 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1))) (define num-rows (vector-length grid)) (define num-cols (vector-length (vector-ref grid 0))) ;; cell-ref :: number, number -> number ;; Returns the cell type at the given position. (define (cell-ref row col) (vector-ref (vector-ref grid row) col)) ;; cell-set! :: number, number, number -> / ;; Sets the cell type at the given position. (define (cell-set! row col value) (vector-set! (vector-ref grid row) col value)) ;; wall? :: number, number -> boolean (define (wall? row col) (= (cell-ref row col) cell-type-wall)) ;; coin? :: number, number -> boolean (define (coin? row col) (= (cell-ref row col) cell-type-coin)) ;; empty? :: number, number -> boolean (define (empty? row col) (= (cell-ref row col) cell-type-empty)) ;; key? :: number, number -> boolean (define (key? row col) (= (cell-ref row col) cell-type-key)) ;; door? :: number, number -> boolean (define (door? row col) (= (cell-ref row col) cell-type-door)) ;; remove-door! :: number, number -> / ;; Removes a door from the grid (makes the cell empty). (define (remove-door! row col) (cell-set! row col cell-type-empty)) ;; for-each-cell :: (number, number, number -> /) -> / ;; Iterates over all cells, calling callback with row, col, cell-type. (define (for-each-cell callback) (do ((row 0 (+ row 1))) ((= row num-rows)) (do ((col 0 (+ col 1))) ((= col num-cols)) (callback row col (cell-ref row col))))) ;; dispatch-maze :: symbol -> any (define (dispatch-maze msg) (cond ((eq? msg 'rows) num-rows) ((eq? msg 'cols) num-cols) ((eq? msg 'cell-ref) cell-ref) ((eq? msg 'cell-set!) cell-set!) ((eq? msg 'wall?) wall?) ((eq? msg 'coin?) coin?) ((eq? msg 'empty?) empty?) ((eq? msg 'key?) key?) ((eq? msg 'door?) door?) ((eq? msg 'remove-door!) remove-door!) ((eq? msg 'for-each-cell) for-each-cell) (else (error "Maze ADT -- Unknown message:" msg)))) dispatch-maze)))