6
\$\begingroup\$

The program starts at the center of the screen and starts drawing a line in 50ms steps. When the line hits the edge of the terminal it will be reflected and continue drawing. steps takes the number of drawing steps to perform before finishing while until-key finishes on a key press.

Apart from the lack of comments, what would I need to do to make this "good" Forth and how would I change it to fit in one screen (16 lines of 64 chars)?

variable h variable w : height h @ ; : width w @ ; variable point-var cell allot : point ( offset -- addr ) cells point-var + ; variable direction-var cell allot : dir ( offset -- addr ) cells direction-var + ; : init ( -- ) rows h ! cols w ! width 2 / 0 point ! height 2 / 1 point ! 1 0 dir ! 1 1 dir ! ; : reflect-top ( -- t/f ) 1 point @ 0= dup if 1 1 dir ! then invert ; : reflect-bot ( -- t/f ) 1 point @ height 1 - = if -1 1 dir ! then ; : reflect-left ( -- t/f ) 0 point @ width 1 - = if -1 0 dir ! then ; : reflect-right ( -- t/f ) 0 point @ 0= dup if 1 0 dir ! then invert ; : reflect ( -- ) reflect-top if reflect-bot then reflect-right if reflect-left then ; : draw-point ( -- ) [char] # emit ; : move-x ( -- n ) 0 point @ 0 dir @ + dup 0 point ! ; : move-y ( -- n ) 1 point @ 1 dir @ + dup 1 point ! ; : move-xy ( -- ) move-x move-y at-xy ; : try ; : step ( -- ) try reflect move-xy draw-point ; : steps ( n -- ) init page 0 do step 50 ms loop ; : until-key ( n -- ) init page begin step 50 ms key? until ; 
\$\endgroup\$
3
  • \$\begingroup\$ Good material for the review. However some parts seem missing (at-xy, invert). \$\endgroup\$ Commented Apr 5, 2016 at 0:10
  • \$\begingroup\$ invert (used as logical not) and at-xy are provided by gforth in the base dictionary. at-xy ( posX posY -- ) just prints the "\x1b[y;xH" escape sequence to move the cursor. \$\endgroup\$ Commented Apr 5, 2016 at 0:21
  • \$\begingroup\$ I have rolled back Rev 5 → 4. Please see What to do when someone answers. You may wish to post it as a self-answer instead. \$\endgroup\$ Commented Apr 6, 2016 at 20:58

2 Answers 2

3
\$\begingroup\$
  • Magic numbers

     0 constant X 1 constant Y 

    looks more attractive than naked 0 and 1. I suppose (sorry can't test it right now) it may let you unify move-x with move-y, as well as reflects.

  • Height and width

     : height= h @ 1 - = ; : width= w @ 1 - = ; 

    allow more symmetric definition of reflects:

     : reflect-top Y point @ 0= dup if 1 1 dir ! then invert ; : reflect-bot Y point @ height= if -1 1 dir ! then ; 

    Now it looks like they have different stack effects, which is strange. Are you sure reflect-bot doesn't miss dup?

  • move-*

    I'd rearrange pushes, e.g.

     : move-x 0 0 0 point @ dir @ + dup point ! ; : move-y 1 1 1 point @ dir @ + dup point ! ; 

    which really prompts for a point @ dir @ + dup point ! word. move-in-dir perhaps?

  • One screen

    Do modern Forthers still care about screens?

\$\endgroup\$
5
  • \$\begingroup\$ Ah reflect-bot should have ( -- ) as the diagram. I missed that when fixing a problem I had with it earlier. Also I wanted to see how it would look if it was done in one screen (currently trying) to help avoid variables as they are a lot slower than pure stack operations. \$\endgroup\$ Commented Apr 5, 2016 at 4:17
  • \$\begingroup\$ @SANK Yes variables are generally frowned upon. I am still trying to see a way to avoid them here. \$\endgroup\$ Commented Apr 5, 2016 at 4:34
  • \$\begingroup\$ wouldn't the pushes in move-* will cause undefined behaviour (segfault) if rearranged as dir would be using the value from point @ instead of x/y? \$\endgroup\$ Commented Apr 5, 2016 at 4:43
  • \$\begingroup\$ @SANK I don't think so. My suggestion is a literal rewrite (as far as I understand); it shown;t change the behaviour. \$\endgroup\$ Commented Apr 5, 2016 at 4:49
  • \$\begingroup\$ Since both point and dir consume a stack item, 0 0 point @ will leave the stack with [point value, 0] which dir then consumes causing a segfault when point @ returns greater than 1. 0 0 0 point @ swap dir @ + dup rot point ! works as each must consume a 0 from the stack (currently testing it in gforth). \$\endgroup\$ Commented Apr 5, 2016 at 5:01
1
\$\begingroup\$

Almost complete solution to the screen improvement with the bulk taking 15 lines.

  • All variables have been removed along with most of the words to define reflect.
  • The position, direction and bounds are now stored in 6 cells allocated on the heap.
  • "Half" words only used to define others are now replaced by the words they are used to define.

There should also be a slight speedup due to avoiding variables and lower word count per definition.

: bound ( a -- a ) 4 cells + ; : dir ( a -- a ) 2 cells + ; : init ( n n a -- a ) rot tuck ! cell + tuck ! cell + ; : init ( -- a ) 6 cells allocate throw dup rows 2 / cols 2 / init 1 1 init rows 1- cols 1- init drop ; : reflect ( a -- ) dup @ 0= if 1 swap dir ! else dup dup bound @ swap @ = if -1 swap dir ! else drop then then ; : reflect ( a -- ) dup cell + reflect reflect ; : move-xy ( a -- ) dup @ over dir @ + over ! cell + dup @ over dir @ + swap ! ; : step ( a -- ) dup dup dup reflect cell + @ swap @ swap at-xy move-xy [char] # emit ; : steps ( n -- ) page init swap 0 do dup step 10 ms loop dup 6 erase free throw ; : until-key ( -- ) page init begin dup step key? 10 ms until dup 6 erase free throw ; 
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.