home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / mbug / mbug121.arc / LOTTO.ARK / LOTTO.MAC < prev   
Text File  |  1988-08-07  |  15KB  |  490 lines

  1. ;                 LOTTO.MAC
  2. ;
  3. ;*************************************************
  4. ;**                        **
  5. ;**    A RANDOM NUMBER GENERATOR TO SIMULATE    **
  6. ;**           LOTTERY DRAWINGS, ETC.            **
  7. ;**                                             **
  8. ;**                   by                        **
  9. ;**                John Fox                     **
  10. ;**                             (c) l986        **
  11. ;*************************************************
  12. ;
  13. ;    THIS PROGRAM MAKES USE OF SYSLIB 
  14. ;    FUNCTIONS AND A RANDOM NUMBER 
  15. ;       GENERATOR THAT USES THE Z-80 REFRESH
  16. ;       REGISTER.
  17. ;
  18. .Z80    ;IT IS IN Z80 CODE
  19. ;
  20. ;--------------------------------
  21. ;EXTERNAL REFERENCES FOR SYSLIB
  22. ;--------------------------------
  23. ;
  24.     EXT    MULHD        ;16 bit multiply
  25.     EXT    PRINT        ;console display routine
  26.     EXT    MA3DC        ;routine to store acc. as 3 dec. digits
  27.     EXT    CIN        ;routine to get chr from console
  28.     EXT    COUT        ;routine to output chr to console
  29.     EXT     PADC        ;routine to output acc. as dec. #
  30. ;
  31. ;--------------------------------
  32. ;    ABSOLUTE EQUATES
  33. ;--------------------------------
  34. ;
  35. BDOS    EQU    05H    ;BDOS base-page entry point 
  36. FCB    EQU    5CH
  37. CR    EQU    0DH
  38. LF    EQU    0AH
  39. BS    EQU    08H
  40. ;
  41. ;
  42. ;--------------------------------------------------------
  43. ;    START OF PROGRAM
  44. ;--------------------------------------------------------    
  45. LOTTO:    JP    LOTTO1        ;jump over the following subroutine
  46. ;---------------
  47. ; FIRST A LITTLE ROUTINE TO CLEAR THE SCREEN
  48. ; It is used throughout the entire program
  49. ;
  50. CLRSTG:    DB    1AH,00,00,00,00,00    ;put here whatever will clear the screen
  51. CLSCRN:    PUSH    HL        ;save registers    
  52.     PUSH    PSW
  53.     LD    HL,CLRSTG    ;point to DB's 
  54. MRSTRG:    LD    A,(HL)        ;get one
  55.     CP    00        ;is it zero
  56.     JR    Z,CLRDN        ;then we're done
  57.     CALL    COUT        ;otherwise display it
  58.     INC    HL        ;and point to next one  
  59.     JR    MRSTRG        ;and go back to display it    
  60. ;
  61. CLRDN:    POP    PSW        ;restore registers
  62.     POP    HL        
  63.     RET             ;and exit
  64. ;---------------
  65. ;
  66. ; NOW THE REAL PROGRAM
  67. ;
  68. LOTTO1:    CALL    CLSCRN        ;clear the screen
  69.     LD    HL,STORE    ;make sure storage counter is reset
  70.     LD    A,00
  71.     LD    (HL),A
  72.     CALL    PRINT        ;call syslib print routine
  73.                 ;which prints following dbs
  74.     DB      '                              LOTTO  ',lf,lf,cr 
  75.     DB        '                    A Random Number Program',LF,CR
  76.     DB      '        To Simulate Lottery Drawings, etc.',lf,lf,cr
  77.     DB      '                           (c) J. Fox'
  78.     DB    CR,LF,LF,LF,LF
  79.     DB      '              How many numbers do you want chosen?',CR,LF
  80.     DB      '              (Please, no more than 12).......  ',00
  81.     LD    HL,HOW$MANY    ;point to current value
  82.     LD    A,(HL)        ;get it
  83.     CALL    PADC        ;display it
  84.     CALL    PRINT        ;erase trailing #'s if any
  85.     DB    BS,BS,00
  86.     CALL    INSTRG        ;get string input from console
  87.     LD    DE,HOW$MANY
  88.     CALL    FIXINP        ;put new numbers into storage 
  89.     CALL    PRINT    
  90.     DB      CR,LF,LF,LF,LF
  91.     DB      '              What is the greatest value any one can have?',CR,LF
  92.     DB      '              (Please, no greater than 99).........  ',BS,BS,00
  93.     LD    HL,MAXVAL    ;point to current value
  94.     LD    A,(HL)        ;get it
  95.     CALL    PADC        ;display it
  96.     CALL    PRINT        ;clean up trailing #'s
  97.     DB    BS,BS,00
  98.     CALL    INSTRG        ;get new #'s
  99.     LD    DE,MAXVAL
  100.     CALL    FIXINP
  101. TYPE:    CALL    PRINT
  102.     DB    CR,LF,LF,LF,LF
  103.     DB      '              Hit <RETURN> for LOTTO  (unique #''s)',CR,LF
  104.     DB      '              Hit <ESCAPE> for non-unique #''s (including 0)'
  105.     DB    CR,LF,00
  106.     LD    B,0FFH        ;load B with flag value for LOTTO-type selection 
  107.     CALL    CIN        ;get input
  108.     CP    CR        ;is it LOTTO?
  109.     JR    Z,LDIT        ;if so, go load flag value
  110.     CP    1BH        ;if not, was it an ESC? 
  111.     JP    NZ,TYPE        ;if not, illegal input, wait for CR or ESC
  112.     INC    B        ;otherwise adjust flag value
  113. LDIT:    LD    HL,FLAG        ;point to flag storage location
  114.     LD    A,B        ;get flag value
  115.     LD    (HL),A        ;store it
  116. ;
  117. SETUP:    LD    HL,HOW$MANY    ;point to # of selections requested
  118.     LD    A,(HL)        ;get it
  119.     CP    00H        ;is it a positive #
  120.     JP    NZ,NXTCK    ;if so check some more
  121.     CALL    PRINT        ;if not, comment
  122.     DB    CR,LF,LF,'  Ahah!  Let me get this right.  You want me to choose no numbers from among a'
  123.     DB    CR,LF,'  bunch of numbers?  That''s more like a Zen exercise.'
  124.     DB    CR,LF,'  Now the way I see it I could either go off to a circuit monastery for a few hours'
  125.     DB    CR,LF,'  to meditate on the task or we could start over fresh.'
  126.     DB    CR,LF,'  Let''s do that.....'
  127.     DB    CR,LF,LF,LF,'     Hit any key.',00 
  128.     CALL    CIN
  129.     JP    LOTTO
  130. NXTCK:    CP    0DH        ;is it greater than 12?
  131.     JP    C,HMOK        ;if not, OK
  132.     CALL    PRINT        ;otherwise, complain
  133.     DB    CR,LF,LF,'     Hold on now.....'
  134.     DB    CR,LF,'     I thought I said I couldn''t deal with more than twelve selections.'
  135.     DB    CR,LF,'     Now we''ll have to start all over again........'
  136.     DB    CR,LF,LF,LF,'     Hit any key.',00
  137.     CALL    CIN        ;wait for input
  138.     JP    LOTTO
  139. HMOK:    LD    B,A        ;set it aside
  140.     DEC    HL        ;point to MAXVAL    
  141.     LD    A,(HL)        ;get largest number allowed    
  142.     PUSH    PSW        ;save it
  143.     LD    HL,MVOK1    ;set up return address if non-unique # drawing
  144.     PUSH    HL
  145.     LD    HL,LKJ        ;and return address if unique # drawing
  146.     JP    WHTFLG        ;and go check LOTTO flag
  147. ;
  148. ;    
  149. LKJ:    POP    PSW        ;get max value back in A for unique drawings
  150.     CP    B        ;is it smaller than # of selections
  151.     JP    NC,MVOK        ;if not, fine
  152.     CALL    PRINT        ;otherwise complain
  153.     DB    CR,LF,LF
  154.     DB    '      This must be some kind of a trick, right?'
  155.     DB    CR,LF,'      You want me to choose',00
  156.     LD    C,A        ;put MAXVAL aside for a moment
  157.     LD    A,B        ;and get HOW$MANY
  158.     CALL    PADC        ;print HOW$MANY on screen
  159.     CALL    PRINT
  160.     DB    ' numbers from among',00
  161.     LD    A,C        ;then display MAXVAL
  162.     CALL    PADC
  163.     CALL    PRINT    
  164.     DB    ' numbers?'        
  165.     DB    CR,LF,'      I''d love to be able to do that, but I''m not a magician.' 
  166.     DB    CR,LF,'      Let''s go back and start over....'
  167.     DB    CR,LF,LF,LF,'      Hit any key.',00
  168.     CALL     CIN        ;wait for input
  169.     JP    LOTTO
  170. MVOK1:    POP    PSW        ;if we're coming from flag check get MAXVAL back
  171. MVOK:    LD    HL,MASK        ;Point to storage space for max mask
  172.     LD    B,A        ;put MAXVAL into B 
  173.     LD    A,0FH        ;load up with smallest possible mask
  174. DIFF:    LD    D,A        ;put it in a safe place
  175.     SUB    B        ;is it big enough?
  176.     JR    NC,SAV        ;it is big enough, use it
  177.     LD    A,D        ;otherwise get mask back
  178.     RLA            ;double it plus one 
  179.     JP    DIFF        ;and loop back to see if it is big enough    
  180. SAV:    LD    BC,VALDIFF
  181.     LD    (BC),A        ;store value difference
  182.     LD    (HL),D        ;and store mask
  183. ;
  184. BEGIN:    CALL    CLSCRN
  185.     CALL    PRINT
  186.     DB      CR,LF,LF,LF,LF,LF,LF,LF
  187.     DB      '          Give me just a half second while I try to concentrate.',cr,lf
  188.       DB      '          Then hit the key marked "esc".',cr,lf,lf
  189.     DB      '          I will tell you what numbers I can see.',cr,lf,lf
  190.     DB        '          Here goes...................',cr,lf,lf,00
  191. ;
  192. START:    CALL    CIN        ;wait for go-ahead
  193.     CP    1BH
  194.     JR    NZ,START
  195. RNDLP:    CALL    RANFUN        ;get first 16-bit random number on stack
  196.     POP    DE        ;pop it into DE register
  197.     LD    HL,HOW$MANY    ;point to # of selections needed
  198.     LD    E,(HL)        ;get #
  199.     LD    HL,MASK        ;point to mask
  200.     LD    B,(HL)        ;put it in B
  201.     LD    A,D        ;get half of random number in accumulator
  202.     AND    B        ;mask to eliminate unneeded binary digits
  203.     LD    HL,VALDIFF
  204.     LD    B,(HL)
  205.     SUB     B         ;subtract to shift #s down from max of 63 decimal 
  206.                 ;to max of 44 decimal
  207.     JR    C,RNDLP        ;if result is negative get new random #
  208.     LD    HL,RNDLP    ;if not point to beginning of routine and
  209.     LD    D,A        ;save number just in case
  210.     CALL    Z,WHTFLG    ;if result is zero go see if legal or not
  211. NMSTR:    LD    HL,STORE    ;point to storage for resultant numbers
  212.     LD    A,(HL)        ;get # of times we have already stored #'s
  213.     CP    E        ;compare to max # allowed
  214. EXIT:    JP    Z,DONE        ;if max, we are done        
  215.     INC    HL        ;move over one to first storage position
  216.     LD    C,A        ;put counter value in C
  217.     LD    B,00        ;zero B
  218.     CP    00        ;if # of chrs stored is zero
  219.     LD    A,D        ;get rnd # back
  220.     JR    Z,STORIT    ;and start storing in first position
  221.     PUSH    BC        ;save BC counter
  222.     PUSH    HL        ;save pointer to buffer
  223.     LD    HL,UNIQ        ;point to uniqueness test
  224.     CALL    WHTFLG        ;and go see if we need it
  225.     POP    HL        ;if not restore buffer pointer
  226.     POP    BC        ;restore counter
  227.     ADD    HL,BC        ;adjust pointer to first free position
  228.     LD    A,D        ;get random # back
  229.     JR    STORIT        ;and go store it
  230. UNIQ:    POP    HL        ;here's where we come back if uniqueness needed
  231.     POP    BC
  232.     LD    A,D        ;get random # back
  233.     CPIR            ;and compare to #'s stored already
  234.     JR    Z,RNDLP        ;if it is duplicate get another one
  235.                 ;we should now be pointing to first empty
  236.                 ;position so...        
  237. STORIT:    LD    (HL),A        ;put rnd # into memory
  238.     LD    HL,STORE    ;point to memory counter
  239.     LD    A,(HL)        ;get it
  240.     INC    A        ;update it
  241.     LD    (HL),A        ;put it back
  242.     JR    RNDLP        ;and go back for next random #
  243.  
  244. ;----------------
  245. ; A SMALL ROUTINE TO ALTER FLOW IF LOTTO FLAG IS SET
  246. ;  (accumulator is affected, HL contains return address for unique
  247. ;   drawings, stack contains it for non-unique.)
  248. ;
  249. WHTFLG:    PUSH    HL        ;save pointer
  250.     LD    HL,FLAG        ;point to LOTTO flag
  251.     LD    A,(HL)         ;get it
  252.     POP    HL        ;restore pointer
  253.     RLC    A        ;shift flag over one place
  254.     RET    NC        ;continue if zero & duplicates allowed
  255.     INC    SP        ;otherwise lose RET address
  256.     INC    SP
  257.     JP    (HL)        ;and jump to predetermined location
  258. ;
  259. ;-----------------------------------------------------------------
  260. ;END PRINT OUT ROUTINE
  261. ;-----------------------------------------------------------------
  262. ;
  263. ;This routine takes the binary numbers stored in the buffer and
  264. ;prints them out to the screen as decimal #s in the following 
  265. ;format:   
  266. ;           ## ## ## ## ## ## (ETC.)
  267. ;
  268. ;Three subroutines follow, then the control program.
  269. ;
  270. ;---------------
  271. ; THIS ONE CALCULATES SPACES NEEDED TO MATCH #'S
  272. ; AND OUTPUTS THE ACCUMULATOR TO THE SCREEN TO FILL
  273. ;
  274. FILLIN:    PUSH    PSW        ;save fill character
  275.     LD    HL,HOW$MANY    ;point to number of selections
  276.     LD    A,(HL)        ;get it and multiply # by 4 
  277.     RLA            ;to get space we need to fill
  278.     RLA    
  279.     LD    B,A
  280.     POP    PSW        ;get fill character
  281. NXT:    CALL    COUT        ;output it
  282.     DEC    B
  283.     JR    NZ,NXT
  284.     RET
  285. ;---------------
  286. ; THIS TYPES A LINE OF ASTERISKS 
  287. ;
  288. ASTXLN:    LD    A,2AH
  289.     CALL    FILLIN
  290.     CALL    PRINT
  291.     DB    '****************************'
  292.     DB    CR,LF,00
  293.     RET
  294. ;---------------
  295. ;  THIS TYPES A LINE OF SPACES WITH AN ASTERISK AT BOTH ENDS
  296. ;
  297. BLNKLN:    CALL    PRINT
  298.     DB    '*                          ',00
  299.     LD    A,20H
  300.     CALL    FILLIN
  301.     CALL    PRINT
  302.     DB    '*',CR,LF,00
  303.     RET
  304. ;---------------
  305. ;  HERE IS THE CONTROL ROUTINE
  306. ;
  307. DONE:    CALL    CLSCRN
  308.     CALL    PRINT        ;print following message    
  309.     DB    LF,LF
  310.     DB    '    These are the numbers in my circuits right now...',cr,lf,lf,lf
  311.     DB    lf,lf,lf,lf,00
  312.     CALL    ASTXLN
  313.     CALL    BLNKLN
  314.     CALL    PRINT
  315.     DB    '*            ',00  
  316.     LD    HL,HOW$MANY    ;point to total number of selections
  317.     LD    B,(HL)        ;put total number in B
  318.     LD    HL,STORE+1    ;point to first number 
  319. GO:    LD    A,20h        ;output a space to console
  320.     CALL    COUT
  321.     LD    A,(HL)
  322.     CALL    PADC        ;output number to console as decimal 
  323.     INC    HL        ;point to next number 
  324.     DEC    B        ;another down
  325.     JR    NZ,GO        ;anymore to go?
  326.     CALL    PRINT    
  327.     DB    '              *',CR,LF,00
  328.     CALL    BLNKLN
  329.     CALL    ASTXLN
  330.     LD    A,2AH
  331. ;
  332. ;Now we have finished our output.  
  333. ;We need only give someone the choice of repeating the whole procedure
  334. ;
  335. RPT:    CALL    PRINT
  336.     DB    CR,LF,LF,LF,LF,LF,LF,LF
  337.     DB    '           If you want another set, hit <ESCAPE>.',cr,lf
  338.     DB    '           Hit <RETURN> to terminate this program.',CR
  339.     DB    LF,00
  340. WHT:    CALL    CIN        ;get character entered at console
  341.     CP    0DH        ;is it a CR?
  342.     JP    Z,stop        ;if so, we are done
  343.     CP    1BH        ;is it ESC?
  344.     JP    NZ,WHT        ;if not keeping waiting
  345.     CALL    CLSCRN        ;if so clear the screen
  346.     LD    HL,STORE    ;point to storage counter
  347.     LD    (HL),00        ;zero it    
  348.     JP    BEGIN        ;and start over
  349. ;
  350. STOP:    JP    00        ;GOODBYE
  351. ;
  352. ;------------------------------------
  353. ; SUBROUTINES HANDLING CONSOLE INPUT
  354. ;------------------------------------
  355. ;
  356. ; GET CONSOLE INPUT AS 2-CHARACTER STRING FOLLOWED BY <CR>
  357. ; IN CONSOLE BUFFER.   ALLOW ONLY ASCII #'S 
  358. ;
  359. INSTRG:    LD    A,00    
  360.     LD    HL,CNBUFF    ;point to buffer
  361.     LD    (HL),A        ;zero buffer counter
  362. GETCHR:    CALL    CIN        ;get input
  363.     CP    CR        ;if carriage return, we're done
  364.     RET    Z
  365.     CP    BS        ;is it backspace?
  366.     LD    D,A        ;save it anyway
  367.     LD    HL,CNBUFF    ;point to buffer counter
  368.     JR    NZ,CHKCHR    ;and go on to further check if not BS
  369.     LD    A,(HL)        ;if BS get counter
  370.     CP    00
  371.     JR    Z,GETCHR    ;if empty ignore backspace
  372.     DEC    A        ;otherwise decrement counter
  373.     LD    (HL),A
  374.     LD    A,D        ;get character back
  375.     CALL     COUT        ;and output it to screen
  376.     JP    GETCHR        ;and go back for input 
  377. ;    
  378. CHKCHR:    CP    30H        ;check that we have a number
  379.     JR    C,GETCHR    ;no, too small
  380.     CP    40H        
  381.     JR    NC,GETCHR    ;no, too big 
  382.     LD    A,(HL)        ;yes, get counter 
  383.     CP    2
  384.     JR    Z,GETCHR    ;if already full keep waiting for CR or BS
  385.     INC    A        ;otherwise increment counter
  386.     LD    (HL),A
  387.     ADD    A,L        ;adjust the pointer
  388.     LD    L,A
  389.     LD    A,D        ;get character back
  390.     LD    (HL),A        ;put it in buffer
  391.     CALL    COUT        ;and display it
  392.     CALL    PRINT        ;and clean up trailing space
  393.     DB    ' ',BS,00    ;just in case
  394.     JR    GETCHR        ;and go back for more
  395. ;
  396. ; TAKE ASCII STRING IN CONSOLE BUFFER AND REDUCE TO A SINGLE
  397. ; NUMBER AND STORE IT AT LOCATION POINTED TO BY REGISTERS DE
  398. ;
  399. FIXINP:    LD    HL,CNBUFF    ;point to buffer counter
  400.     LD    A,(HL)        ;get it
  401.     CP    00        ;anything entered?
  402.     RET    Z        ;no, go with default value
  403.     LD    C,A        ;yes, save buffer counter
  404.     INC    HL
  405.     LD    A,(HL)        ;and get first character
  406.     SUB    30H        ;normalize it
  407.     LD    B,A        ;set it aside
  408.     LD    A,C        ;get counter
  409.     CP    01        ;was this the only character?
  410.     LD    A,B
  411.     JR    Z,FIXDN        ;yes, then we're done
  412.     RLA            ;if not multiply by 10
  413.     RLA
  414.     RLA
  415.     ADD    A,B
  416.     ADD    A,B
  417.     LD    B,A        ;set it aside
  418.     INC    HL
  419.     LD    A,(HL)        ;get next number
  420.     SUB    30H        ;normalize it
  421.     ADD    A,B        ;add them
  422. FIXDN:    LD     H,D        ;get back original pointer
  423.     LD    L,E
  424.     LD    (HL),A        ;and save result there
  425.     RET
  426. ;
  427. ;
  428. ;-------------------------------
  429. ;      RANDOM NUMBER GENERATOR
  430. ;-------------------------------      
  431. ;
  432. ;      Based on a routine by Robert Zimmerer in
  433. ;      Microsystems, October '83.
  434. ;
  435. ;      Returns a random 16 bit number on top of 
  436. ;      stack. Using the Z80 refresh register R for a
  437. ;      random number seed.
  438. ;      This routine calls an external routine
  439. ;      MULHD that multiplies the HL and DE
  440. ;      registers.  
  441. ;
  442. RANFUN:    LD    A,R        ; get a random byte
  443.     LD    E,A
  444.     LD    D,0        ; make a 16 bit number
  445.     RRCA            ; scramble and set carry
  446.                 ; randomly
  447.     JR    C,RAN1        ; use random number A if 
  448.                 ; carry = 1
  449.     LD    E,A        ; else use scrambled value
  450.     LD    BC,RANB        ; pint at random number B
  451.     JR    RAN2
  452. RAN1:    LD    BC,RANA        ; point at random number A
  453. RAN2:    LD    A,(BC)        ; move previous random 
  454.                 ; number into HL
  455.     LD    L,A    
  456.     INC    BC
  457.     LD    A,(BC)
  458.     LD    H,A
  459.     ADD    HL,DE        ; mix it up
  460.     CALL    MULHD         ; scramble bits again
  461.                 ; HL = (HL+DE)*DE, BC=BC
  462.     LD    A,H        ; and replace the previous
  463.                 ; random number with this new one
  464.     LD    (BC),A
  465.     DEC    BC
  466.     LD    A,L
  467.     LD    (BC),A
  468.     EX    (SP),HL        ; swap random number with RET
  469.     PUSH     HL        ; push back RET address
  470.     RET            ; return to calling routine
  471.                 ;with random number on stack
  472. RANB:    DEFW    1936H        ; initial random numbers
  473. RANA:    DEFW    1936H        ; just to get started
  474.     RET
  475.  
  476. ;****************************************************
  477. ;*  STORAGE SPACE
  478. ;****************************************************
  479. CNBUFF:        DS    05        ;console buffer for input
  480. STORE:        DB    00        ;storage counter
  481.         DS    12h         ;storage space               
  482. MAXVAL:        DB    31H        ;default highest number
  483. HOW$MANY:    DB    06H        ;default number of selections
  484. MASK:        DB    00
  485. VALDIFF:    DB    00    
  486. FLAG:        DB    0FFH        ;FF= unique/non-zero selections
  487.                     ;00= non-unique with 00 legal selection
  488. END    LOTTO
  489. _______________________________________________________________tions
  490.                     ;00= non-unique with 00 legal selection