Как отобразить список графических объектов в коллекцию символов? Используя `(define-values)`? - PullRequest
0 голосов
/ 26 июня 2019

Я пытаюсь изучить Racket, следуя примерам кода из "Realm of Racket". В настоящее время в главе 8, и я решил провести рефакторинг некоторого повторяющегося кода, чтобы помочь себе быстрее учиться. В частности, я пытаюсь назначить список игровой графики для набора символов, но продолжаю сталкиваться с ошибками.

Это исходный orc-world.rkt исходный файл. Код работает нормально.

(require 2htdp/image)

;; compute constants for image frames 
(define ORC     (bitmap "graphics/orc.png"))
(define HYDRA   (bitmap "graphics/hydra.png"))
(define SLIME   (bitmap "graphics/slime.bmp"))
(define BRIGAND (bitmap "graphics/brigand.bmp"))

(define PIC-LIST (list ORC HYDRA SLIME BRIGAND))
(define w (apply max (map image-width PIC-LIST)))
(define h (apply max (map image-height PIC-LIST)))

(define PLAYER-IMAGE  (bitmap "graphics/player.bmp"))

(define FRAME (rectangle w h 'outline 'white))
(define TARGET (circle (- (/ w 2) 2) 'outline 'blue))

(define ORC-IMAGE     (overlay ORC FRAME))
(define HYDRA-IMAGE   (overlay HYDRA FRAME))
(define SLIME-IMAGE   (overlay SLIME FRAME))
(define BRIGAND-IMAGE (overlay BRIGAND FRAME))

По сути, он читает кучу растровых изображений с диска и присваивает их символам. Там много дублирования кода. Я пытаюсь изменить это так, чтобы дублирование кода было минимизировано, и в то же время узнал больше о том, как работают стандартные библиотеки Racket.

Моя версия, игнорируя код (overlay) на данный момент:

(require 2htdp/image)

(define BASEPATH "/Applications/Racket v7.3/share/pkgs/realm/chapter8/graphics/")
(define FILENAMES '("orc.png" "hydra.png" "slime.bmp" "brigand.bmp" "player.bmp"))
(define PATHS (map (lambda (x)(string-append BASEPATH x)) FILENAMES))
(define PICTURES (map (lambda (x)(bitmap/file x)) PATHS))
(define PIC-LIST '(ORC HYDRA SLIME BRIGAND PLAYER-IMAGE))

Я хочу перебрать список ИЗОБРАЖЕНИЙ и назначить каждое изображение для символа, который находится в списке. Я мог бы просто сделать (define ORC (first PICTURES)) (define HYDRA (second PICTURES)) и т. Д., Но это не так что хотел. Кажется, мы могли бы использовать (map), поскольку оба списка имеют одинаковую длину, но я получаю следующие ошибки.

(map (lambda x y)(define x y) PIC-LIST PICTURES) ; error. define: not allowed in an expression context in: define

(map (lambda x y (define-values (x) (values y)) PIC-LIST PICTURES)) ; error. define-values: not allowed in an expression position in: (define-values (x) (values y))

(map (lambda (x y)(define x y))PIC-LIST PICTURES) ; error. begin (possibly implicit): no expression after a sequence of internal definitions in:
;  (begin (define x y))
;  (define x y)

Использование (define-values) само по себе также не работает.

(define-values PIC-LIST (values PICTURES)) ; syntax error because PIC-LIST is a list

Надеялся, что кто-то будет достаточно любезен, чтобы указать мне правильный путь. Это должно быть что-то очень простое, что я пропускаю, так как это довольно распространенная задача.

Спасибо, что прочитали это далеко.

1 Ответ

1 голос
/ 26 июня 2019

Вы можете использовать match-define следующим образом:

 (match-define (list ORC HYDRA SLIME BRIGAND PLAYER-IMAGE) IMAGES)

Это будет работать до тех пор, пока количество изображений известно заранее, вы не можете передать списокимен переменных в качестве аргумента (мы делаем сопоставление с шаблоном здесь.)

Это нормально, я думаю - потому что в любом случае вы должны знать, как вы хотите назвать свои изображения, сколькоих у вас есть и в каком порядке они появляются перед присвоением имени каждому из них.Если бы мне пришлось провести рефакторинг исходного кода, он бы выглядел так:

#lang racket

(require 2htdp/image)

(define paths '("graphics/orc.png"
                "graphics/hydra.png"
                "graphics/slime.bmp"
                "graphics/brigand.bmp"
                "graphics/player.bmp"))

(match-define (list ORC HYDRA SLIME BRIGAND PLAYER-IMAGE)
  (map bitmap paths))
(define PIC-LIST (list ORC HYDRA SLIME BRIGAND))

(define w (apply max (map image-width PIC-LIST)))
(define h (apply max (map image-height PIC-LIST)))
(define FRAME (rectangle w h 'outline 'white))
(define TARGET (circle (- (/ w 2) 2) 'outline 'blue))

(match-define (list ORC-IMAGE HYDRA-IMAGE SLIME-IMAGE BRIGAND-IMAGE)
  (map (λ (img) (overlay img FRAME)) PIC-LIST))

Обратите внимание, что существует три разных списка переменных, и мы определяем каждый из них ровно один раз, поэтому дублирование кода сводится к минимуму..

...