Zum Inhalt springen
Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

Forth

Aus FreitagsrundenWiki
Version vom 6. September 2011, 17:34 Uhr von Loofmann (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Wunderschöne Programmiersprache! :-)

Hier mal als Beispiel ein in Forth programmiertes Pong für das Open Firmare von Apple Macintosh-Rechnern].

\ \ http://members.aol.com/plforth/ofpong/20020313/ofpong.txt
\ \
\ \ Wednesday, March 13, 2002
\ \ See also http://members.aol.com/plforth/ofpong/index.html
\ \
\ \
\ \ Hello, this is the game of Pong.
\ \
\ \ To play, store this file in the root folder of your Macintosh
\ \ HD, boot with Command+Option+O+F held down, and then enter
\ \ the command `boot hd:\ofpong.txt` but without the quotes.
\ \
\ \ While playing, hold down the A and Z keys to move the left 
\ \ paddle up and down, hold down the ' and / keys to move the
\ \ right paddle up and down, press Esc to start a new game,
\ \ press Delete to quit.
\ \
\ \ After playing, enter the command `pong` to play some more,
\ \ or enter the command `bye` to get back to MacOS.
\ \
\ \
\ \ This code has been seen to work on a classic iMac, on an iBook,
\ \ and on a flat-planel iMac.  Please write to tell us if it
\ \ doesn't work on your Mac.  (Our web pages suggest addresses.)
\ \
\ \ Before modifying this code, you probably want to comment
\ \ out (or delete) the line at the end that says `pong`.  That
\ \ way when you `boot` this code you can look at it and modify
\ \ it before running it.
\ \
\ \
\ \ To construct this file, we modified a copy of the
\ \ 1.0d1 MacHack '98 release of OFPong.of found in OFPONG.SIT.
\ \
\ \ 1) We copied the text into a SimpleText file, so that `boot`
\ \ knows it can read the text. (The original was a BBEdit file.)
\ \ To let us edit this in Mac OS X, we had to tell TextEdit to
\ \ make this a plain text file, not an Rtf text file.
\ \
\ \ 2) We commented out the source code below that begins with \.
\ \
\ \ 3) We added the source below that ends with \.
\ \
\ \ 4) We added the comments you see here that begin with \ \.
\ \
\ \
\ \ Technically speaking, our modifications included:
\ \
\ \ 1) Begin with a \ comment, like `boot` wants.
\ \
\ \ 2) Comment out the `dl` command, guessing that has something
\ \ to do with running this game over a serial or Usb connection,
\ \ as opposed to using `boot` to run this from a file system.
\ \
\ \ 3) End with a `pong` command so that `boot` runs the game.
\ \
\ \ 4) Use `dev keyboard` where `dev kbd` is unavailable, and
\ \ accordingly adjust which bits of the key-map to poll to see
\ \ the keys A Z ' / Esc Delete held down.
\ \
\ \ 5) Use [ s" dev keyboard get-key-map 0 to active-package"
\ \ evaluate ] in place of [ " get-key-map" ... $call-method ]
\ \ because [ s" keyboard" open-dev ] crashes a classic iMac hard.
\ \
\ \ 6) Draw with the background-color and erase with the
\ \ foreground-color, rather than with colors -1 and 0, because
\ \ on a flat-panel iMac the color -1 is black or transparent, not
\ \ visibly different from the black background color 0.
\ \
\ \
\ \ If you display this source code in a fixed width font like
\ \ Courier or Monaco, then the column ruler here might help you
\ \ keep your lines of source code short:
\ \
\ \ 0000011111111111222222222223333333333344444444444555555555556666
\ \ 56789_0123456789_0123456789_0123456789_0123456789_0123456789_123

\ dl

decimal

0 value gscreen
" screen" open-dev to gscreen

0 value gkbd
" kbd" open-dev to gkbd

\ 0 value gkeyboard \
\ " keyboard" open-dev to gkeyboard \

0 value erasecol
-1 value drawcol
foreground-color to erasecol \
background-color to drawcol \

0 value key_left_up
0 value key_left_down
0 value key_right_up
0 value key_right_down
0 value key_esc
0 value key_off

get-msecs value grandseed
0 value glastupdate
0 value loopcount
0 value totalupdate

0 value ballstop

0 value ballx
0 value bally

0 value balldx
0 value balldy

0 value leftbaty
0 value rightbaty
0 value batdy

0 value leftscore
0 value rightscore

640 value screenx
480 value screeny

: screen-prop@ ( prop-name prop-len -- value )
  gscreen ihandle>phandle get-package-property
  0= if
    decode-int -rot 2drop
  else
    256
  then
;

" width" screen-prop@ to screenx
" height" screen-prop@ to screeny

20 value ballsize
ballsize 2 / value scoresize
ballsize 5 * value batsize
1000 value pscale

screenx ballsize - pscale * value ball_limit_x
ballsize pscale * value ball_limit_lo_y
screeny ballsize 2 * - pscale * value ball_limit_hi_y

ballsize pscale * value bat_limit_lo_y
screeny ballsize batsize + - pscale * value bat_limit_hi_y

0 value hit_limit_left_lo_x
ballsize 2 * pscale * value hit_limit_left_hi_x
screenx ballsize 3 * - pscale * value hit_limit_right_lo_x
screenx ballsize - pscale * value hit_limit_right_hi_x

ballsize pscale * value reflect_left_x
screenx ballsize 2 * - pscale * value reflect_right_x

: random ( -- n ) grandseed 16807 * 17 + abs to grandseed grandseed 1000 mod ;
: unscale ( n -- n ) pscale 2 / + pscale / ;
: calcbatx ( n -- x ) screenx ballsize 3 * - * ballsize + ;
: paintrect ( c pixx pixy pixw pixh -- ) " fill-rectangle" gscreen $call-method ;

: rectcol ( startx starty x1 y1 x2 y2 c -- startx starty )
  { startx starty x1 y1 x2 y2 c }
  
  c
  x1 scoresize * startx +
  y1 scoresize * starty +
  x2 x1 - scoresize *
  y2 y1 - scoresize *
  paintrect
  
  startx starty
;

: blackrect ( startx starty x1 y1 x2 y2 -- ) drawcol rectcol ;
: whiterect ( startx starty x1 y1 x2 y2 -- ) erasecol rectcol ;

: drawblank ( startx starty -- startx starty )
  0 0 4 7 whiterect
;

: drawzero ( startx starty -- startx starty )
  0 0 1 7 blackrect
  1 0 3 1 blackrect
  1 6 3 7 blackrect
  3 0 4 7 blackrect
  1 3 3 4 whiterect
;

: drawone ( startx starty -- startx starty )
  3 0 4 7 blackrect
  0 0 3 7 whiterect
;

: drawtwo ( startx starty -- )
  0 0 4 1 blackrect
  3 1 4 3 blackrect
  0 3 4 4 blackrect
  0 4 1 6 blackrect
  0 6 4 7 blackrect
  0 1 1 3 whiterect
  3 4 4 6 whiterect
;

: drawthree ( startx starty -- startx starty )
  0 0 4 1 blackrect
  3 1 4 3 blackrect
  0 3 4 4 blackrect
  3 4 4 6 blackrect
  0 6 4 7 blackrect
  0 1 1 3 whiterect
  0 4 1 6 whiterect
;

: drawfour ( startx starty -- startx starty )
  0 0 1 3 blackrect
  0 3 3 4 blackrect
  3 0 4 7 blackrect
  1 0 3 1 whiterect
  0 4 3 7 whiterect
;

: drawfive ( startx starty -- startx starty )
  0 0 4 1 blackrect
  0 1 1 3 blackrect
  0 3 4 4 blackrect
  3 4 4 6 blackrect
  0 6 4 7 blackrect
  3 1 4 3 whiterect
  0 4 1 6 whiterect
;

: drawsix ( startx starty -- startx starty )
  0 0 1 7 blackrect
  1 3 3 4 blackrect
  1 6 3 7 blackrect
  3 3 4 7 blackrect
  1 0 4 3 whiterect
;

: drawseven ( startx starty -- startx starty )
  0 0 3 1 blackrect
  3 0 4 7 blackrect
  0 1 3 7 whiterect
;

: draweight ( startx starty -- startx starty )
  0 0 4 1 blackrect
  0 1 1 3 blackrect
  3 1 4 3 blackrect
  0 3 4 4 blackrect
  0 4 1 6 blackrect
  3 4 4 6 blackrect
  0 6 4 7 blackrect
;

: drawnine ( startx starty -- startx starty )
  0 0 1 4 blackrect
  1 0 3 1 blackrect
  1 3 3 4 blackrect
  3 0 4 7 blackrect
  0 4 3 7 whiterect
;

: drawdigit ( startx starty n -- )
  { n }
  n 0 = if drawzero then
  n 1 = if drawone then
  n 2 = if drawtwo then
  n 3 = if drawthree then
  n 4 = if drawfour then
  n 5 = if drawfive then
  n 6 = if drawsix then
  n 7 = if drawseven then
  n 8 = if draweight then
  n 9 = if drawnine then
  2drop
;

: drawnumber ( startx starty num -- )
  { startx starty num }
  startx starty num abs 100 mod 10 / drawdigit
  startx scoresize 5 * + starty num abs 10 mod drawdigit
;

: plotball ( x y -- ) { x y } drawcol x unscale y unscale ballsize ballsize paintrect ;
: eraseball ( x y -- ) { x y } erasecol x unscale y unscale ballsize ballsize paintrect ;
: plotbat ( n y -- ) { n y } drawcol n calcbatx y unscale ballsize batsize paintrect ;
: erasebat ( n y -- ) { n y } erasecol n calcbatx y unscale ballsize batsize paintrect ;

: redraw ( -- )
  drawcol 0 0 screenx ballsize paintrect
  drawcol 0 screeny ballsize - screenx ballsize paintrect

  drawcol screenx scoresize - 2 / ballsize 2 * scoresize screeny ballsize 4 * - paintrect
  
  ballsize 7 * ballsize 2 * leftscore drawnumber
  screenx ballsize 7 * 9 scoresize * + - ballsize 2 * rightscore drawnumber
  0 leftbaty plotbat
  1 rightbaty plotbat
  ballx bally plotball
;

: drawboard ( -- )
  drawcol 0 0 screenx screeny paintrect
  erasecol 0 0 screenx screeny paintrect
  redraw
;

: resetball ( -- )
  500 to ballstop
  screenx ballsize - 2 / pscale * ballx pscale mod + random + to ballx
  screeny ballsize - 2 / pscale * bally pscale mod + random + to bally
  
  random screenx pscale * * 2000000 / to balldx
  random screeny pscale * * 2000000 / to balldy
  balldx screenx pscale * 3000 / + to balldx
  balldy screeny pscale * 6000 / + to balldy
  
  random 500 < if
    balldx negate to balldx
  then
  random 500 < if
    balldy negate to balldy
  then
;

: initvalues ( -- )
  ballsize 2 * pscale * to leftbaty
  screeny ballsize 2 * - batsize - pscale * to rightbaty
  
  screeny pscale * 1000 / to batdy
;

: doreset ( -- )
  resetball
  0 to leftscore
  0 to rightscore
  drawboard
;

: testkey ( map index mask -- bool )
  { map index mask } map index ca+ c@ mask and 0<>
;

\ : scankeys ( -- )
: gkbd-scankeys ( -- )
  " get-key-map" gkbd $call-method
  drop
  dup 0 128 testkey to key_left_up
  dup 0 2 testkey to key_left_down
  dup 4 1 testkey to key_right_up
  dup 5 8 testkey to key_right_down
  dup 6 4 testkey to key_esc
  dup 6 16 testkey to key_off
  drop
;

: gkeyboard-scankeys ( -- ) \
  s" dev keyboard get-key-map 0 to active-package" evaluate \
  dup 0 8 testkey to key_left_up \ the A key
  dup 3 4 testkey to key_left_down \ the Z key
  dup 6 8 testkey to key_right_up \ the ' key
  dup 7 128 testkey to key_right_down \ the / key
  dup 5 64 testkey to key_esc \ the Esc key
  dup 5 32 testkey to key_off \ the Delete key
  drop \
; \

: forth-scankeys \
  0 to key_esc
  key? if \
    key
    dup 64 or [char] a = to key_left_up \
    dup 64 or [char] z = to key_left_down \
    dup [char] ' = to key_right_up \
    dup [char] / = to key_right_down \
    dup 27 = to key_esc \
    dup 8 = to key_off \
    drop \
  then \
; \

: roelf-scankeys \
  key? if key case \
    [char] a of true to key_left_up endof \
    [char] z of true to key_left_down endof \
    [char] ' of true to key_right_up endof \
    [char] / of true to key_right_down endof \
    [char] q of true to key_esc endof \
    true to key_off endof \
  endcase then \
; \

: scankeys ( -- ) \
    \ forth-scankeys \
    \ roelf-scankeys \
    gkbd if gkbd-scankeys else gkeyboard-scankeys then \
; \

: moveball ( oldx oldy newx newy -- )
  { oldx oldy newx newy }
  oldx oldy eraseball
  newx newy plotball
;

: doupdateball ( delta -- )
  ballx swap bally swap
  
  dup
  
  balldx * ballx + to ballx
  balldy * bally + to bally

  ballx 0< if
    resetball
    balldx abs negate to balldx
    ballx ballsize 2 * pscale * + to ballx
    rightscore 1 + to rightscore
    rightscore 15 = if
      -1 to ballstop
    then
  then
  ballx ball_limit_x > if
    resetball
    balldx abs to balldx
    ballx ballsize 2 * pscale * - to ballx
    leftscore 1 + to leftscore
    leftscore 15 = if
      -1 to ballstop
    then
  then

  bally ball_limit_lo_y < if
    balldy negate to balldy
    ball_limit_lo_y 2 * bally - to bally
  then
  bally ball_limit_hi_y > if
    balldy negate to balldy
    ball_limit_hi_y 2 * bally - to bally
  then
  
  balldx 0< if
    ballx hit_limit_left_lo_x hit_limit_left_hi_x between if
      bally leftbaty ballsize pscale * - leftbaty batsize pscale * + between if
        
        bally leftbaty < if
          balldy abs negate to balldy
        then
        
        bally leftbaty batsize ballsize - pscale * + > if
          balldy abs to balldy
        then      

        ballx reflect_left_x > if
          balldx abs random 50 / + to balldx

          leftbaty bally - unscale
          dup 0 batsize between if
            batsize 2 / - random * 2 / batsize / 25 / balldy + to balldy
          else
            drop
          then
        then
      then
    then
  then
  
  balldx 0> if
    ballx hit_limit_right_lo_x hit_limit_right_hi_x between if
      bally rightbaty ballsize pscale * - rightbaty batsize pscale * + between if
      
        bally rightbaty < if
          balldy abs negate to balldy
        then
        
        bally rightbaty batsize ballsize - pscale * + > if
          balldy abs to balldy
        then      

        ballx reflect_right_x < if
          balldx abs random 50 / + negate to balldx

          rightbaty bally - unscale
          dup 0 batsize between if
            batsize 2 / - random * 2 / batsize / 25 / balldy + to balldy
          else
            drop
          then
        then
      then
    then
  then

  bally ball_limit_lo_y < if
    ball_limit_lo_y to bally
  then
  bally ball_limit_hi_y > if
    ball_limit_hi_y to bally
  then

  ballx bally moveball
;

: updateball ( delta -- )
  ballstop 0= if
    doupdateball
  else
    ballstop -1 = if
      drop
    else
      ballstop swap - to ballstop
      ballstop 0<= if
        0 to ballstop
      then
    then
  then
;

: movebatup ( n oldp delta -- )
  { n oldp delta }
  erasecol n calcbatx oldp batsize + delta + ballsize delta negate paintrect
  drawcol n calcbatx oldp delta + ballsize delta negate paintrect
;

: movebatdown ( n oldp delta -- )
  { n oldp delta }
  erasecol n calcbatx oldp ballsize delta paintrect
  drawcol n calcbatx oldp batsize + ballsize delta paintrect
;

: movebat ( n oldy newy -- )
  { n oldy newy }
  newy unscale oldy unscale -
  dup abs batsize < if
    dup 0<> if
      dup 0< if
        n swap oldy unscale swap movebatup
      else
        n swap oldy unscale swap movebatdown
      then
    else
      drop
    then
  else
    drop
    n oldy erasebat
    n newy plotbat
  then
;

: updatebats ( delta -- )
  { delta }
  0 leftbaty 0
  over bat_limit_lo_y > if
  key_left_up 0<> if
    batdy -
  then then
  over bat_limit_hi_y < if
  key_left_down 0<> if
    batdy +
  then then
  delta * over +
  dup to leftbaty
  movebat
  
  1 rightbaty 0
  over bat_limit_lo_y > if
  key_right_up 0<> if
    batdy -
  then then
  over bat_limit_hi_y < if
  key_right_down 0<> if
    batdy +
  then then
  delta * over +
  dup to rightbaty
  movebat
;

: initeverything ( -- )
  cr
  0 to loopcount
  0 to totalupdate
  initvalues
  10 0 do scankeys loop
  doreset
  get-msecs to glastupdate 
;

: doloop ( delta -- )
  loopcount 1 + to loopcount
  dup totalupdate + to totalupdate
  
  dup updatebats
  dup updateball
  redraw
  
  glastupdate + to glastupdate
;

: page 12 emit ; \

: runpong ( -- )
  initeverything
  begin
    get-msecs glastupdate -
      dup 0> if
        dup 250 > if
          drop
          get-msecs to glastupdate
          250
        then
        doloop
      else
        drop
      then
    scankeys
    key_esc 0<> if
      doreset
    then
  key_off 0<> until
  page base @ decimal \
  " Count:" type loopcount s. cr
  " Avg millisec:" type totalupdate loopcount / s. cr
  base ! \
;

: pong runpong ; \

hex \

pong \


\ \ (end of file) \ \