Add ghost CPUs with original Pac-Man AI targeting
Implement four ghosts (Blinky, Pinky, Inky, Clyde) with authentic Pac-Man AI: Blinky chases directly, Pinky targets 2 tiles ahead (with original up-direction bug), Inky uses vector doubling from Blinky, Clyde switches to scatter within 8-tile radius. Includes chase/scatter mode cycling, ghost house exit with staggered delays, directional sprite rendering with animation, and ghost-pacman collision detection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
(prefix (pacman-project tests test-position) position:)
|
||||
(prefix (pacman-project tests test-maze) maze:)
|
||||
(prefix (pacman-project tests test-pacman) pacman:)
|
||||
(prefix (pacman-project tests test-ghost) ghost:)
|
||||
(prefix (pacman-project tests test-score) score:)
|
||||
(prefix (pacman-project tests test-timer) timer:))
|
||||
|
||||
@@ -18,6 +19,7 @@
|
||||
(position:test)
|
||||
(maze:test)
|
||||
(pacman:test)
|
||||
(ghost:test)
|
||||
(score:test)
|
||||
(timer:test))
|
||||
|
||||
|
||||
97
pacman-project/tests/test-ghost.rkt
Normal file
97
pacman-project/tests/test-ghost.rkt
Normal file
@@ -0,0 +1,97 @@
|
||||
#lang r7rs
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Tests: Ghost ADT ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define-library (pacman-project tests test-ghost)
|
||||
(import (scheme base)
|
||||
(pp1 tests)
|
||||
(pacman-project adt ghost))
|
||||
(export test)
|
||||
|
||||
(begin
|
||||
|
||||
;; Test creation and initial state
|
||||
(define (test-creation)
|
||||
(define g (make-ghost 'blinky 11 14 0 27 0))
|
||||
(define pos (g 'position))
|
||||
(check-eq? (pos 'row) 11 "Start row should be 11")
|
||||
(check-eq? (pos 'col) 14 "Start col should be 14")
|
||||
(check-eq? (g 'type) 'blinky "Type should be blinky")
|
||||
(check-eq? (g 'direction) 'left "Default direction should be left"))
|
||||
|
||||
;; Test that exit-delay 0 means ghost starts outside (scatter mode)
|
||||
(define (test-blinky-starts-active)
|
||||
(define g (make-ghost 'blinky 11 14 0 27 0))
|
||||
(check-eq? (g 'in-house?) #f "Blinky should start outside")
|
||||
(check-eq? (g 'mode) 'scatter "Blinky should start in scatter"))
|
||||
|
||||
;; Test that non-zero exit-delay means ghost starts in house
|
||||
(define (test-pinky-starts-in-house)
|
||||
(define g (make-ghost 'pinky 14 13 0 0 2000))
|
||||
(check-eq? (g 'in-house?) #t "Pinky should start in house")
|
||||
(check-eq? (g 'mode) 'in-house "Pinky mode should be in-house"))
|
||||
|
||||
;; Test direction change
|
||||
(define (test-direction)
|
||||
(define g (make-ghost 'blinky 11 14 0 27 0))
|
||||
((g 'direction!) 'right)
|
||||
(check-eq? (g 'direction) 'right "Direction should be right"))
|
||||
|
||||
;; Test mode change and reverse queuing
|
||||
(define (test-mode-change-queues-reverse)
|
||||
(define g (make-ghost 'blinky 11 14 0 27 0))
|
||||
((g 'mode!) 'chase)
|
||||
(check-eq? (g 'mode) 'chase "Mode should be chase")
|
||||
(check-eq? ((g 'consume-reverse!)) #t "Reverse should be queued after mode change"))
|
||||
|
||||
;; Test reverse consumed only once
|
||||
(define (test-consume-reverse-once)
|
||||
(define g (make-ghost 'blinky 11 14 0 27 0))
|
||||
((g 'mode!) 'chase)
|
||||
((g 'consume-reverse!))
|
||||
(check-eq? ((g 'consume-reverse!)) #f "Reverse should be consumed after first call"))
|
||||
|
||||
;; Test move
|
||||
(define (test-move)
|
||||
(define g (make-ghost 'blinky 11 14 0 27 0))
|
||||
((g 'move!) 0 -1)
|
||||
(define pos (g 'position))
|
||||
(check-eq? (pos 'col) 13 "Col should be 13 after move left"))
|
||||
|
||||
;; Test scatter target
|
||||
(define (test-scatter-target)
|
||||
(define g (make-ghost 'blinky 11 14 0 27 0))
|
||||
(define st (g 'scatter-target))
|
||||
(check-eq? (st 'row) 0 "Scatter target row should be 0")
|
||||
(check-eq? (st 'col) 27 "Scatter target col should be 27"))
|
||||
|
||||
;; Test house timer expiry
|
||||
(define (test-house-exit)
|
||||
(define g (make-ghost 'pinky 14 13 0 0 2000))
|
||||
((g 'update-house-timer!) 1000)
|
||||
(check-eq? (g 'in-house?) #t "Still in house after 1000ms")
|
||||
((g 'update-house-timer!) 1000)
|
||||
(check-eq? (g 'in-house?) #f "Should exit house after 2000ms")
|
||||
(check-eq? (g 'mode) 'scatter "Should be in scatter after exiting"))
|
||||
|
||||
;; Test movement timer
|
||||
(define (test-movement-timer)
|
||||
(define g (make-ghost 'blinky 11 14 0 27 0))
|
||||
(check-eq? ((g 'advance-movement-timer!) 100) 100 "Timer should be 100")
|
||||
(check-eq? ((g 'advance-movement-timer!) 120) 220 "Timer should be 220")
|
||||
((g 'reset-movement-timer!))
|
||||
(check-eq? (g 'movement-timer) 0 "Timer should reset to 0"))
|
||||
|
||||
(define (test)
|
||||
(run-test test-creation "Ghost: creation and initial state")
|
||||
(run-test test-blinky-starts-active "Ghost: Blinky starts active")
|
||||
(run-test test-pinky-starts-in-house "Ghost: Pinky starts in house")
|
||||
(run-test test-direction "Ghost: direction change")
|
||||
(run-test test-mode-change-queues-reverse "Ghost: mode change queues reverse")
|
||||
(run-test test-consume-reverse-once "Ghost: consume reverse only once")
|
||||
(run-test test-move "Ghost: move")
|
||||
(run-test test-scatter-target "Ghost: scatter target")
|
||||
(run-test test-house-exit "Ghost: house timer exit")
|
||||
(run-test test-movement-timer "Ghost: movement timer"))))
|
||||
Reference in New Issue
Block a user