home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug121.arc
/
LOTTO.ARK
/
LOTTO.MAC
< prev
Wrap
Text File
|
1988-08-07
|
15KB
|
490 lines
; LOTTO.MAC
;
;*************************************************
;** **
;** A RANDOM NUMBER GENERATOR TO SIMULATE **
;** LOTTERY DRAWINGS, ETC. **
;** **
;** by **
;** John Fox **
;** (c) l986 **
;*************************************************
;
; THIS PROGRAM MAKES USE OF SYSLIB
; FUNCTIONS AND A RANDOM NUMBER
; GENERATOR THAT USES THE Z-80 REFRESH
; REGISTER.
;
.Z80 ;IT IS IN Z80 CODE
;
;--------------------------------
;EXTERNAL REFERENCES FOR SYSLIB
;--------------------------------
;
EXT MULHD ;16 bit multiply
EXT PRINT ;console display routine
EXT MA3DC ;routine to store acc. as 3 dec. digits
EXT CIN ;routine to get chr from console
EXT COUT ;routine to output chr to console
EXT PADC ;routine to output acc. as dec. #
;
;--------------------------------
; ABSOLUTE EQUATES
;--------------------------------
;
BDOS EQU 05H ;BDOS base-page entry point
FCB EQU 5CH
CR EQU 0DH
LF EQU 0AH
BS EQU 08H
;
;
;--------------------------------------------------------
; START OF PROGRAM
;--------------------------------------------------------
LOTTO: JP LOTTO1 ;jump over the following subroutine
;---------------
; FIRST A LITTLE ROUTINE TO CLEAR THE SCREEN
; It is used throughout the entire program
;
CLRSTG: DB 1AH,00,00,00,00,00 ;put here whatever will clear the screen
CLSCRN: PUSH HL ;save registers
PUSH PSW
LD HL,CLRSTG ;point to DB's
MRSTRG: LD A,(HL) ;get one
CP 00 ;is it zero
JR Z,CLRDN ;then we're done
CALL COUT ;otherwise display it
INC HL ;and point to next one
JR MRSTRG ;and go back to display it
;
CLRDN: POP PSW ;restore registers
POP HL
RET ;and exit
;---------------
;
; NOW THE REAL PROGRAM
;
LOTTO1: CALL CLSCRN ;clear the screen
LD HL,STORE ;make sure storage counter is reset
LD A,00
LD (HL),A
CALL PRINT ;call syslib print routine
;which prints following dbs
DB ' LOTTO ',lf,lf,cr
DB ' A Random Number Program',LF,CR
DB ' To Simulate Lottery Drawings, etc.',lf,lf,cr
DB ' (c) J. Fox'
DB CR,LF,LF,LF,LF
DB ' How many numbers do you want chosen?',CR,LF
DB ' (Please, no more than 12)....... ',00
LD HL,HOW$MANY ;point to current value
LD A,(HL) ;get it
CALL PADC ;display it
CALL PRINT ;erase trailing #'s if any
DB BS,BS,00
CALL INSTRG ;get string input from console
LD DE,HOW$MANY
CALL FIXINP ;put new numbers into storage
CALL PRINT
DB CR,LF,LF,LF,LF
DB ' What is the greatest value any one can have?',CR,LF
DB ' (Please, no greater than 99)......... ',BS,BS,00
LD HL,MAXVAL ;point to current value
LD A,(HL) ;get it
CALL PADC ;display it
CALL PRINT ;clean up trailing #'s
DB BS,BS,00
CALL INSTRG ;get new #'s
LD DE,MAXVAL
CALL FIXINP
TYPE: CALL PRINT
DB CR,LF,LF,LF,LF
DB ' Hit <RETURN> for LOTTO (unique #''s)',CR,LF
DB ' Hit <ESCAPE> for non-unique #''s (including 0)'
DB CR,LF,00
LD B,0FFH ;load B with flag value for LOTTO-type selection
CALL CIN ;get input
CP CR ;is it LOTTO?
JR Z,LDIT ;if so, go load flag value
CP 1BH ;if not, was it an ESC?
JP NZ,TYPE ;if not, illegal input, wait for CR or ESC
INC B ;otherwise adjust flag value
LDIT: LD HL,FLAG ;point to flag storage location
LD A,B ;get flag value
LD (HL),A ;store it
;
SETUP: LD HL,HOW$MANY ;point to # of selections requested
LD A,(HL) ;get it
CP 00H ;is it a positive #
JP NZ,NXTCK ;if so check some more
CALL PRINT ;if not, comment
DB CR,LF,LF,' Ahah! Let me get this right. You want me to choose no numbers from among a'
DB CR,LF,' bunch of numbers? That''s more like a Zen exercise.'
DB CR,LF,' Now the way I see it I could either go off to a circuit monastery for a few hours'
DB CR,LF,' to meditate on the task or we could start over fresh.'
DB CR,LF,' Let''s do that.....'
DB CR,LF,LF,LF,' Hit any key.',00
CALL CIN
JP LOTTO
NXTCK: CP 0DH ;is it greater than 12?
JP C,HMOK ;if not, OK
CALL PRINT ;otherwise, complain
DB CR,LF,LF,' Hold on now.....'
DB CR,LF,' I thought I said I couldn''t deal with more than twelve selections.'
DB CR,LF,' Now we''ll have to start all over again........'
DB CR,LF,LF,LF,' Hit any key.',00
CALL CIN ;wait for input
JP LOTTO
HMOK: LD B,A ;set it aside
DEC HL ;point to MAXVAL
LD A,(HL) ;get largest number allowed
PUSH PSW ;save it
LD HL,MVOK1 ;set up return address if non-unique # drawing
PUSH HL
LD HL,LKJ ;and return address if unique # drawing
JP WHTFLG ;and go check LOTTO flag
;
;
LKJ: POP PSW ;get max value back in A for unique drawings
CP B ;is it smaller than # of selections
JP NC,MVOK ;if not, fine
CALL PRINT ;otherwise complain
DB CR,LF,LF
DB ' This must be some kind of a trick, right?'
DB CR,LF,' You want me to choose',00
LD C,A ;put MAXVAL aside for a moment
LD A,B ;and get HOW$MANY
CALL PADC ;print HOW$MANY on screen
CALL PRINT
DB ' numbers from among',00
LD A,C ;then display MAXVAL
CALL PADC
CALL PRINT
DB ' numbers?'
DB CR,LF,' I''d love to be able to do that, but I''m not a magician.'
DB CR,LF,' Let''s go back and start over....'
DB CR,LF,LF,LF,' Hit any key.',00
CALL CIN ;wait for input
JP LOTTO
MVOK1: POP PSW ;if we're coming from flag check get MAXVAL back
MVOK: LD HL,MASK ;Point to storage space for max mask
LD B,A ;put MAXVAL into B
LD A,0FH ;load up with smallest possible mask
DIFF: LD D,A ;put it in a safe place
SUB B ;is it big enough?
JR NC,SAV ;it is big enough, use it
LD A,D ;otherwise get mask back
RLA ;double it plus one
JP DIFF ;and loop back to see if it is big enough
SAV: LD BC,VALDIFF
LD (BC),A ;store value difference
LD (HL),D ;and store mask
;
BEGIN: CALL CLSCRN
CALL PRINT
DB CR,LF,LF,LF,LF,LF,LF,LF
DB ' Give me just a half second while I try to concentrate.',cr,lf
DB ' Then hit the key marked "esc".',cr,lf,lf
DB ' I will tell you what numbers I can see.',cr,lf,lf
DB ' Here goes...................',cr,lf,lf,00
;
START: CALL CIN ;wait for go-ahead
CP 1BH
JR NZ,START
RNDLP: CALL RANFUN ;get first 16-bit random number on stack
POP DE ;pop it into DE register
LD HL,HOW$MANY ;point to # of selections needed
LD E,(HL) ;get #
LD HL,MASK ;point to mask
LD B,(HL) ;put it in B
LD A,D ;get half of random number in accumulator
AND B ;mask to eliminate unneeded binary digits
LD HL,VALDIFF
LD B,(HL)
SUB B ;subtract to shift #s down from max of 63 decimal
;to max of 44 decimal
JR C,RNDLP ;if result is negative get new random #
LD HL,RNDLP ;if not point to beginning of routine and
LD D,A ;save number just in case
CALL Z,WHTFLG ;if result is zero go see if legal or not
NMSTR: LD HL,STORE ;point to storage for resultant numbers
LD A,(HL) ;get # of times we have already stored #'s
CP E ;compare to max # allowed
EXIT: JP Z,DONE ;if max, we are done
INC HL ;move over one to first storage position
LD C,A ;put counter value in C
LD B,00 ;zero B
CP 00 ;if # of chrs stored is zero
LD A,D ;get rnd # back
JR Z,STORIT ;and start storing in first position
PUSH BC ;save BC counter
PUSH HL ;save pointer to buffer
LD HL,UNIQ ;point to uniqueness test
CALL WHTFLG ;and go see if we need it
POP HL ;if not restore buffer pointer
POP BC ;restore counter
ADD HL,BC ;adjust pointer to first free position
LD A,D ;get random # back
JR STORIT ;and go store it
UNIQ: POP HL ;here's where we come back if uniqueness needed
POP BC
LD A,D ;get random # back
CPIR ;and compare to #'s stored already
JR Z,RNDLP ;if it is duplicate get another one
;we should now be pointing to first empty
;position so...
STORIT: LD (HL),A ;put rnd # into memory
LD HL,STORE ;point to memory counter
LD A,(HL) ;get it
INC A ;update it
LD (HL),A ;put it back
JR RNDLP ;and go back for next random #
;----------------
; A SMALL ROUTINE TO ALTER FLOW IF LOTTO FLAG IS SET
; (accumulator is affected, HL contains return address for unique
; drawings, stack contains it for non-unique.)
;
WHTFLG: PUSH HL ;save pointer
LD HL,FLAG ;point to LOTTO flag
LD A,(HL) ;get it
POP HL ;restore pointer
RLC A ;shift flag over one place
RET NC ;continue if zero & duplicates allowed
INC SP ;otherwise lose RET address
INC SP
JP (HL) ;and jump to predetermined location
;
;-----------------------------------------------------------------
;END PRINT OUT ROUTINE
;-----------------------------------------------------------------
;
;This routine takes the binary numbers stored in the buffer and
;prints them out to the screen as decimal #s in the following
;format:
; ## ## ## ## ## ## (ETC.)
;
;Three subroutines follow, then the control program.
;
;---------------
; THIS ONE CALCULATES SPACES NEEDED TO MATCH #'S
; AND OUTPUTS THE ACCUMULATOR TO THE SCREEN TO FILL
;
FILLIN: PUSH PSW ;save fill character
LD HL,HOW$MANY ;point to number of selections
LD A,(HL) ;get it and multiply # by 4
RLA ;to get space we need to fill
RLA
LD B,A
POP PSW ;get fill character
NXT: CALL COUT ;output it
DEC B
JR NZ,NXT
RET
;---------------
; THIS TYPES A LINE OF ASTERISKS
;
ASTXLN: LD A,2AH
CALL FILLIN
CALL PRINT
DB '****************************'
DB CR,LF,00
RET
;---------------
; THIS TYPES A LINE OF SPACES WITH AN ASTERISK AT BOTH ENDS
;
BLNKLN: CALL PRINT
DB '* ',00
LD A,20H
CALL FILLIN
CALL PRINT
DB '*',CR,LF,00
RET
;---------------
; HERE IS THE CONTROL ROUTINE
;
DONE: CALL CLSCRN
CALL PRINT ;print following message
DB LF,LF
DB ' These are the numbers in my circuits right now...',cr,lf,lf,lf
DB lf,lf,lf,lf,00
CALL ASTXLN
CALL BLNKLN
CALL PRINT
DB '* ',00
LD HL,HOW$MANY ;point to total number of selections
LD B,(HL) ;put total number in B
LD HL,STORE+1 ;point to first number
GO: LD A,20h ;output a space to console
CALL COUT
LD A,(HL)
CALL PADC ;output number to console as decimal
INC HL ;point to next number
DEC B ;another down
JR NZ,GO ;anymore to go?
CALL PRINT
DB ' *',CR,LF,00
CALL BLNKLN
CALL ASTXLN
LD A,2AH
;
;Now we have finished our output.
;We need only give someone the choice of repeating the whole procedure
;
RPT: CALL PRINT
DB CR,LF,LF,LF,LF,LF,LF,LF
DB ' If you want another set, hit <ESCAPE>.',cr,lf
DB ' Hit <RETURN> to terminate this program.',CR
DB LF,00
WHT: CALL CIN ;get character entered at console
CP 0DH ;is it a CR?
JP Z,stop ;if so, we are done
CP 1BH ;is it ESC?
JP NZ,WHT ;if not keeping waiting
CALL CLSCRN ;if so clear the screen
LD HL,STORE ;point to storage counter
LD (HL),00 ;zero it
JP BEGIN ;and start over
;
STOP: JP 00 ;GOODBYE
;
;------------------------------------
; SUBROUTINES HANDLING CONSOLE INPUT
;------------------------------------
;
; GET CONSOLE INPUT AS 2-CHARACTER STRING FOLLOWED BY <CR>
; IN CONSOLE BUFFER. ALLOW ONLY ASCII #'S
;
INSTRG: LD A,00
LD HL,CNBUFF ;point to buffer
LD (HL),A ;zero buffer counter
GETCHR: CALL CIN ;get input
CP CR ;if carriage return, we're done
RET Z
CP BS ;is it backspace?
LD D,A ;save it anyway
LD HL,CNBUFF ;point to buffer counter
JR NZ,CHKCHR ;and go on to further check if not BS
LD A,(HL) ;if BS get counter
CP 00
JR Z,GETCHR ;if empty ignore backspace
DEC A ;otherwise decrement counter
LD (HL),A
LD A,D ;get character back
CALL COUT ;and output it to screen
JP GETCHR ;and go back for input
;
CHKCHR: CP 30H ;check that we have a number
JR C,GETCHR ;no, too small
CP 40H
JR NC,GETCHR ;no, too big
LD A,(HL) ;yes, get counter
CP 2
JR Z,GETCHR ;if already full keep waiting for CR or BS
INC A ;otherwise increment counter
LD (HL),A
ADD A,L ;adjust the pointer
LD L,A
LD A,D ;get character back
LD (HL),A ;put it in buffer
CALL COUT ;and display it
CALL PRINT ;and clean up trailing space
DB ' ',BS,00 ;just in case
JR GETCHR ;and go back for more
;
; TAKE ASCII STRING IN CONSOLE BUFFER AND REDUCE TO A SINGLE
; NUMBER AND STORE IT AT LOCATION POINTED TO BY REGISTERS DE
;
FIXINP: LD HL,CNBUFF ;point to buffer counter
LD A,(HL) ;get it
CP 00 ;anything entered?
RET Z ;no, go with default value
LD C,A ;yes, save buffer counter
INC HL
LD A,(HL) ;and get first character
SUB 30H ;normalize it
LD B,A ;set it aside
LD A,C ;get counter
CP 01 ;was this the only character?
LD A,B
JR Z,FIXDN ;yes, then we're done
RLA ;if not multiply by 10
RLA
RLA
ADD A,B
ADD A,B
LD B,A ;set it aside
INC HL
LD A,(HL) ;get next number
SUB 30H ;normalize it
ADD A,B ;add them
FIXDN: LD H,D ;get back original pointer
LD L,E
LD (HL),A ;and save result there
RET
;
;
;-------------------------------
; RANDOM NUMBER GENERATOR
;-------------------------------
;
; Based on a routine by Robert Zimmerer in
; Microsystems, October '83.
;
; Returns a random 16 bit number on top of
; stack. Using the Z80 refresh register R for a
; random number seed.
; This routine calls an external routine
; MULHD that multiplies the HL and DE
; registers.
;
RANFUN: LD A,R ; get a random byte
LD E,A
LD D,0 ; make a 16 bit number
RRCA ; scramble and set carry
; randomly
JR C,RAN1 ; use random number A if
; carry = 1
LD E,A ; else use scrambled value
LD BC,RANB ; pint at random number B
JR RAN2
RAN1: LD BC,RANA ; point at random number A
RAN2: LD A,(BC) ; move previous random
; number into HL
LD L,A
INC BC
LD A,(BC)
LD H,A
ADD HL,DE ; mix it up
CALL MULHD ; scramble bits again
; HL = (HL+DE)*DE, BC=BC
LD A,H ; and replace the previous
; random number with this new one
LD (BC),A
DEC BC
LD A,L
LD (BC),A
EX (SP),HL ; swap random number with RET
PUSH HL ; push back RET address
RET ; return to calling routine
;with random number on stack
RANB: DEFW 1936H ; initial random numbers
RANA: DEFW 1936H ; just to get started
RET
;****************************************************
;* STORAGE SPACE
;****************************************************
CNBUFF: DS 05 ;console buffer for input
STORE: DB 00 ;storage counter
DS 12h ;storage space
MAXVAL: DB 31H ;default highest number
HOW$MANY: DB 06H ;default number of selections
MASK: DB 00
VALDIFF: DB 00
FLAG: DB 0FFH ;FF= unique/non-zero selections
;00= non-unique with 00 legal selection
END LOTTO
_______________________________________________________________tions
;00= non-unique with 00 legal selection