trip logs / gnuvola


Trip Log 2022-01-23 h07 -- Hooray! Part 4

Welcome back to the Hooray! series — in this episode, which is right on the heels of the previous one, we actually cover three patches: numbers 5, 6, and 7.  Up until now, the patches have had a uniform additive flavor — lots of adjacent “+” in the left-hand column — that indicate self-contained subsections not requiring much integration w/ the rest of the code.  Today, we venture into new territory:  (a) Patch 5, in addition to adding functionality, modifies functionality of existing code as well.  (b) Patches 6 and 7 do the same, but with even more vigor and purpose!  All in all, this should be a fun 10 minutes.  Let's get started... 

patch 5

     1  commit 08d8fe55c21d7db8e2f4491970f682fb8d2fe805
     2  Author: Thien-Thi Nguyen <ttn@gnuvola.org>
     3  Date:   2022-01-23 01:12:34 -0500
     4
     5      Add scenery
     6
     7      * hooray.scm (FAR): New data structure.
     8      (refresh-scenery!): New proc.
     9      (smokin): Call ‘refresh-scenery!’.
    10  ---
    11   hooray.scm | 31 +++++++++++++++++++++++++++++++
    12   1 file changed, 31 insertions(+)
    13
    14  diff --git a/hooray.scm b/hooray.scm
    15  index 0f8f0bd..b10c834 100644
    16  --- a/hooray.scm
    17  +++ b/hooray.scm
    18  @@ -73,6 +73,35 @@ (SDL:set-video-mode (* 5 TILE-EDGE-LENGTH)
    19                       (* 5 TILE-EDGE-LENGTH)
    20                       32)
    21
    22  +(define FAR #2((window window window window window)
    23  +               (window cell   cell   cell   window)
    24  +               (window cell   cell   cell   window)
    25  +               (window cell   cell   cell   window)
    26  +               (window window window window window)))
    27  +
    28  +(define refresh-scenery!
    29  +  (let ((rect (apply make-array #f (array-shape FAR))))
    30  +
    31  +    (define (place-tile! name rect)
    32  +      (SDL:blit-surface (hashq-ref HT name) #f #f rect)
    33  +      rect)
    34  +
    35  +    ;; initialize ‘rect’
    36  +    (array-index-map! rect (lambda (r c)
    37  +                             ;; note order change: r c => c r => x y
    38  +                             (SDL:make-rect
    39  +                              (* TILE-EDGE-LENGTH c)
    40  +                              (* TILE-EDGE-LENGTH r)
    41  +                              TILE-EDGE-LENGTH
    42  +                              TILE-EDGE-LENGTH)))
    43  +
    44  +    ;; refresh-scenery!
    45  +    (lambda ()
    46  +      ;; far ground
    47  +      (array-map! rect place-tile! FAR rect)
    48  +      ;; mid ground
    49  +      (place-tile! 'rec-1 (array-ref rect 2 2)))))
    50  +
    51   (define smokin
    52     (let ((keys (list->vector (hash-fold (lambda (k v acc)
    53                                            (cons k acc))
    54  @@ -94,6 +123,8 @@ (define smokin
    55       (lambda (millisecs)
    56         (do ((i 0 (1+ i)))
    57             ((= 420 i))
    58  +        (and (zero? (modulo i 42))
    59  +             (refresh-scenery!))
    60           (let ((tile (random-tile)))
    61             (SDL:rect:set-x! rect (random-coord))
    62             (SDL:rect:set-y! rect (random-coord))

For this project, we define “scenery” as “stuff that goes behind the animation”, and divide it into the far ground and the mid ground.  Patch 5 starts by laying out, quite graphically, the far ground (lines 22-26).  That ‘#2(...)’ is syntax for a two-dimensional array, in this case, of symbols.  The symbols are the names of tiles (see ‘load-theme’).  We only use ‘window’ and ‘cell’ for now. 

The main new stuff is procedure ‘refresh-scenery!’ (starts at line 28).  It has internal procedure ‘place-tile!’ (lines 31-33) which is responsible for blitting one tile.  Lines 29 and 36-42 set up an array (of the same shape as ‘FAR’) of rectangles for the blit, to be configured once and then never changed again.  The body of ‘refresh-scenery!’ is line 47, which handles the far ground, and line 49, which handles the mid ground (currently, just one tile — ‘rec-1’ — in the center). 

Remember “modifies functionality of existing code” in the lead paragraph?  Well, that's what the second hunk of patch 5 (lines 54-62) does.  It adds a call to ‘refresh-scenery!’ to ‘smokin’.  The effect is to periodically (every 42 iterations) refresh the scenery.  Here's what I see when I run “guile -s hooray.scm Linux.png”:

patch 6

     1  commit 6b4537afb60b479b7b91f5bb306f92d474591656
     2  Author: Thien-Thi Nguyen <ttn@gnuvola.org>
     3  Date:   2022-01-23 01:21:51 -0500
     4
     5      Add abstraction: surf
     6
     7      * hooray.scm (surf): New proc.
     8      (refresh-scenery! place-tile!): Use ‘surf’.
     9      (smokin random-tile): Likewise.
    10  ---
    11   hooray.scm | 7 +++++--
    12   1 file changed, 5 insertions(+), 2 deletions(-)
    13
    14  diff --git a/hooray.scm b/hooray.scm
    15  index b10c834..7b7c24f 100644
    16  --- a/hooray.scm
    17  +++ b/hooray.scm
    18  @@ -69,6 +69,9 @@ (define (load-theme filename)           ; => hash table
    19
    20   (define HT (load-theme (cadr (command-line))))
    21
    22  +(define (surf name)
    23  +  (hashq-ref HT name))
    24  +
    25   (SDL:set-video-mode (* 5 TILE-EDGE-LENGTH)
    26                       (* 5 TILE-EDGE-LENGTH)
    27                       32)
    28  @@ -83,7 +86,7 @@ (define refresh-scenery!
    29     (let ((rect (apply make-array #f (array-shape FAR))))
    30
    31       (define (place-tile! name rect)
    32  -      (SDL:blit-surface (hashq-ref HT name) #f #f rect)
    33  +      (SDL:blit-surface (surf name) #f #f rect)
    34         rect)
    35
    36       ;; initialize ‘rect’
    37  @@ -117,7 +120,7 @@ (define smokin
    38         (let ((name (vector-ref keys (random (vector-length keys)))))
    39           (display " ")
    40           (display name)
    41  -        (hashq-ref HT name)))
    42  +        (surf name)))
    43
    44       ;; smokin
    45       (lambda (millisecs)

In contrast to previous patches, patch 6 has very little additive nature, and what it does add is not a user-visible feature, but an “abstraction”.  In fact, the only real addition is procedure ‘surf’ (lines 22-23) in hunk 1.  Hunks 2 and 3 simply show ‘surf’ being used to replace existing code in two other places.  This is the first time we see “-” in the left-hand column, but it won't be the last. 

patch 7

     1  commit a2dd73f5ab85c7de1b60d1d95549d66785ddeef1
     2  Author: Thien-Thi Nguyen <ttn@gnuvola.org>
     3  Date:   2022-01-23 01:29:31 -0500
     4
     5      Add abstraction: make-tile-rect
     6
     7      * hooray.scm (make-tile-rect): New proc.
     8      (load-theme): Use ‘make-tile-rect’.
     9      (refresh-scenery!): Likewise.
    10      (smokin): Likewise.
    11  ---
    12   hooray.scm | 23 ++++++++++-------------
    13   1 file changed, 10 insertions(+), 13 deletions(-)
    14
    15  diff --git a/hooray.scm b/hooray.scm
    16  index 7b7c24f..ef226b2 100644
    17  --- a/hooray.scm
    18  +++ b/hooray.scm
    19  @@ -37,6 +37,13 @@ (let-values (((cap mem fmt) (SDL:video-cmf)))
    20
    21   (define TILE-EDGE-LENGTH 64)
    22
    23  +(define (make-tile-rect r c)
    24  +  ;; note order change: r c => c r => x y
    25  +  (SDL:make-rect (* TILE-EDGE-LENGTH c)
    26  +                 (* TILE-EDGE-LENGTH r)
    27  +                 TILE-EDGE-LENGTH
    28  +                 TILE-EDGE-LENGTH))
    29  +
    30   (define (load-theme filename)           ; => hash table
    31
    32     (define (proper surface)
    33  @@ -47,9 +54,7 @@ (define (load-theme filename)           ; => hash table
    34
    35     (let* ((theme (proper (SDL:load-image filename)))
    36            (ht (make-hash-table))
    37  -         (rect (SDL:make-rect 0 0
    38  -                              TILE-EDGE-LENGTH
    39  -                              TILE-EDGE-LENGTH)))
    40  +         (rect (make-tile-rect 0 0)))
    41
    42       (define (read-row! row tile-names)
    43         (SDL:rect:set-y! rect (* TILE-EDGE-LENGTH row))
    44  @@ -90,13 +95,7 @@ (define refresh-scenery!
    45         rect)
    46
    47       ;; initialize ‘rect’
    48  -    (array-index-map! rect (lambda (r c)
    49  -                             ;; note order change: r c => c r => x y
    50  -                             (SDL:make-rect
    51  -                              (* TILE-EDGE-LENGTH c)
    52  -                              (* TILE-EDGE-LENGTH r)
    53  -                              TILE-EDGE-LENGTH
    54  -                              TILE-EDGE-LENGTH)))
    55  +    (array-index-map! rect make-tile-rect)
    56
    57       ;; refresh-scenery!
    58       (lambda ()
    59  @@ -109,9 +108,7 @@ (define smokin
    60     (let ((keys (list->vector (hash-fold (lambda (k v acc)
    61                                            (cons k acc))
    62                                          '() HT)))
    63  -        (rect (SDL:make-rect 0 0
    64  -                             TILE-EDGE-LENGTH
    65  -                             TILE-EDGE-LENGTH)))
    66  +        (rect (make-tile-rect 0 0)))
    67
    68       (define (random-coord)
    69         (* TILE-EDGE-LENGTH (random 5)))

Like patch 6, patch 7 adds an abstraction.  This time, it's the procedure ‘make-tile-rect’ (lines 23-28), which is then used in three other places (hunks 2, 3, 4).  The result is a very satisfying negative delta — 10 insertions and 13 deletions (line 13) means the net change is 3 deletions — the code is smaller!  OK, see you next time. 


Copyright (C) 2022 Thien-Thi Nguyen