Функции, работающие в двух списках - PullRequest
0 голосов
/ 18 октября 2018

Я работаю над программой 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))]))

это правильный способ проверить каждый элемент каждого списка друг против друга?

Обновление: по-прежнему кругами по этой проблеме.check-collision работает и invader-function работает, но когда я возвращаюсь к функции missile, я не знаю, как указать, что ракета должна быть удалена в случае обнаружения столкновения в функции invader.

(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 голосов
/ 18 октября 2018

Я не просмотрел весь код, но общее решение состоит в том, чтобы иметь одну функцию, которая принимает списки ракет и захватчиков, проверяет все столкновения, а затем возвращает оба обновленных списка, возвращая пару списков.Вот как то так:

(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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...