在两个列表上运行的功能

时间:2018-10-17 22:56:06

标签: scheme lisp racket racket-student-languages

我正在为一个班级的Racket程序工作,我完全不知所措 如何实现其中一项功能。

该程序使用Big-Bang,并应实现一个简单的Space Invaders游戏。

除了一件东西,我所有的东西都可以工作,那就是-如何处理案件 当导弹与入侵者碰撞时。我挣扎的原因是我没有 我知道如何编写一个函数,其中有两个任意大小的列表,并且我有 检查一个列表中每个对象的字段以及另一个列表中的每个对象的字段,然后 如果每个列表具有相同的值,则删除它们。

世界状态就是游戏:

(define-struct game (invaders missiles tank))
入侵者和导弹所在的地方 这两个列表。

要产生游戏的下一个状态,我实现了一个名为“ tock”的功能。

通常,我会这样做:

(define (tock s)
  (make-game (next-invaders (game-invaders s)) 
             (next-missiles (game-missiles s))
             (next-tank (game-tank s)))

但是由于入侵者和导弹清单的内容可能由于碰撞而相互影响,因此我不能简单地独立更新位置并继续前进,因此必须删除所有碰撞然后更新位置。

所以我尝试了:

(define (tock s)
  (make-game (check-collision (game-invaders s) 
                              (game-missiles s) 
                              (game-tank s))

但是,这使检查冲突成为了一个不需要的坦克。

(define (tock s)
  (make-game (next-invaders (game-invaders s) (game-missiles s)) 
             (next-missiles (game-missiles s) (game-invaders s)) 
             (next-tank (game-tank s))))

在此版本中,我有一个名为next-invaders的函数,该函数接收入侵者和导弹的列表,以及一个函数 称为next-missiles,其中包含导弹和入侵者的清单。第一个功能针对每个导弹检查每个侵略者,尝试清除所有冲突的侵略者并返回剩余的侵略者。第二个功能是对每个侵略者检查每枚导弹,并试图清除所有相撞的导弹,并返回剩余的导弹。答案应该是相同的,但是这是重复的工作,我担心可能出现的比赛情况。我不知道如何构造一个表达式,其中一个函数只需要两个字段,另一个函数需要三个字段 而且我仍然制作出游戏的下一个状态。

这里是next-invaders的示例。如果没有入侵者,它什么也不会做。如果有入侵者但没有导弹, 它只是移动每个入侵者(move-invader)并递归地调用自己以遍历所有入侵者。如果有 既是导弹又是入侵者,那么我检查列表中的第一个入侵者与每个 清单中的导弹;因此检查冲突是递归的。

(define (next-invaders loi lom)
  (cond [(empty? loi) empty]
        [(empty? lom) (move-invader (first loi) (next-invaders (rest loi) lom))]
        [(check_collision (first loi) lom) 
         (next-invaders (cons (rest loi) empty) lom)]
        [else
         (move-invader (first loi)
                       (next-invaders (rest loi) lom))]))

check-collision的“答案”是否是从入侵者列表中“删除”冲突入侵者的正确方法?

(define (check_collision i lom)
  (cond [(empty? lom) false]
        [(and (<= (- (missile-x (first lom)) (invader-x i)) HIT-RANGE)
              (<= (- (missile-y (first lom)) (invader-y i)) HIT-RANGE)) 
         true]
        [else (check_collision i (rest lom))]))

这是对每个列表的每个元素进行相互测试的正确方法吗?

更新:在这个问题上仍在盘旋。检查冲突和入侵者功能正常运行,但是当我返回导弹功能时,我不知道如何指示在入侵者功能中检测到碰撞时需要删除导弹。

(define-struct invader (x y dx))
;; Invader is (make-invader Number Number Number)
;; interp. the invader is at (x, y) in screen coordinates
;;         the invader along x by dx pixels per clock tick

(define-struct missile (x y))
;; Missile is (make-missile Number Number)
;; interp. the missile's location is x y in screen coordinates

(define-struct collision (invaders missiles))

(define (tock s)
  (make-game (handle-invaders (collision-invaders (next-invaders-and-missiles (make-collision (game-invaders s) (game-missiles s)))))
             (handle-missiles (collision-missiles (next-invaders-and-missiles (make-collision (game-invaders s) (game-missiles s)))))
             (handle-tank (game-tank s))))

(define (next-invaders-and-missiles c)
  (cond [(and (empty? (collision-invaders c)) (empty? (collision-missiles c))) (make-collision empty empty)]
    [(or (empty? (collision-invaders c)) (empty? (collision-missiles c))) (make-collision (collision-invaders c) (collision-missiles c))]
    [else
     (missile-function (make-collision (collision-invaders c) (collision-missiles c)))]))


;; Collision -> list Of Missiles
;; produce an updated listOf Missiles taking collisions into account
(define (missile-function c)
  (cond [(empty? (collision-missiles c)) (make-collision (collision-invaders c) empty)]
    [else
     (if (< (length (invader-function (first (collision-missiles c)) (collision-invaders c))) (length (collision-invaders c)))
         (make-collision (collision-invaders c) (remove (first (collision-missiles c)) (collision-missiles c)))
         (missile-function (make-collision (collision-invaders c) (rest (collision-missiles c)))))]))


;; Missile, listOf Invaders -> listOf Invaders
;; produce an updated listOf Invaders taking collisions into account
(define (invader-function m loi)
  (cond [(empty? loi) empty]
    [else
     (if (check-collision? (first loi) m)
         (remove (first loi) loi)
         (invader-function m (rest loi)))]))

;; Invader, Missile -> Boolean
;; produce true if the coordinates of a missile are within HIT-RANGE of     the coordinates of an invader
(define (check-collision? i m)
  (and (<= (- (missile-x m) (invader-x i)) HIT-RANGE) (<= (- (missile-y m) (invader-y i)) HIT-RANGE)))

1 个答案:

答案 0 :(得分:1)

我还没有审查所有代码,但是一般的解决方案是拥有一个功能,该功能可以接收导弹和入侵者的清单,检查所有碰撞,然后通过返回一对清单来返回两个更新的清单。像这样:

(define (tock s)
  (let* [(next (next-invaders-and-missiles (game-invaders s) (game-missiles s)))
         (next-invaders (first next))
         (next-missiles (rest next))]
    (make-game next-invaders next-missiles (game-tank s))))

(define (next-invaders-and-missiles loi lom)
  ... ;; code that finds collisions and removes them from both lists
  (cons new-loi new-lom))