		TTL	"Getting better lottery program"
;
; =========================
; Amiga Shopper Assembly Language Course: Part VII
;
; Lottery-Mungus!
;
		section	PrintString,code
;
ENTRY_POINT:	bra.s	START			; Call start of program.
;
; ---- Embedded version string: ....
VERSION:	dc.b	0,"$VER: print_string.asm 1.02 (27.2.95)",0
;
; ---- Include files ....
; ** POINT THIS NEXT LINE (incdir) TO WHERE YOUR INCLUDE FILES
;	ARE STORED. (Normally 'include:' or 'inc:') ***
		incdir	"inc:"			
		include	"exec/exec.i"
		include	"exec/funcdef.i"	; You may not need this.
		include	"exec/exec_lib.i"
		include	"dos/dos.i"
		include	"dos/dos_lib.i"
;
; ---- Equates ....
_EXECBASE:	equ	$04			; exec.library base.
;
; ---- Macro Definitions ....
SYS:		macro
		move.l	_EXECBASE,a6
		jsr	_LVO\1(a6)		; exec.library access macro
		endm

DOS:		macro
		move.l	DosBase,a6
		jsr	_LVO\1(a6)		; dos.library access macro
		endm
;
; ---- Main Program: ....
START:		lea	DosName(pc),a1
		moveq	#$00,d0
		SYS	OpenLibrary
		move.l	d0,DosBase
		beq	ST_Failed_Dos	; Quit if no DOS.
;
; ---- Find STDOUT: ....
		DOS	Output
		move.l	d0,STDOUT
;
; ---- Seed the random number generator ....
		bsr	Init_Seed
;
; ---- Initialise variables for our main loop ....
		moveq	#$05,d1
		lea	Lottery_Guesses(pc),a0
;
; ===========================================================================
;
; ---- Pick 6 numbers with no duplicates ....
ST_Get49:	moveq	#49,d0
		bsr	Random_Number
		addq.w	#$01,d0		; Ensure the number is at least 1
		cmp.w	#49,d0
		bhi.s	ST_Get49	; Loop around if it is > 49
;
; ---- Check if we've already picked this number ....
		lea	Lottery_Guesses(pc),a1
		moveq	#$05,d2
ST_Check:	cmp.b	(a1)+,d0
		beq.s	ST_Get49
		dbra	d2,ST_Check
;
; ---- Store this number out in our list and continue till we're
;	done ....
		move.b	d0,(a0)+
		dbra	d1,ST_Get49
;
; ===========================================================================
;
; ---- Now sort the numbers into numerical order using a bubble
;	sort algorithm ....
;
; 1. Point to the first pair.
BS_Sort:	lea	Lottery_Guesses(pc),a0
		moveq	#$00,d2		; Our swap counter
		moveq	#$04,d3		; Our loop counter (Total swaps to do)
;
; 2. If the first number in the pair is the greater, swap:
BS_Bubble_Loop:	move.b	(a0),d0
		move.b	1(a0),d1	; Fetch both numbers
		cmp.b	d1,d0
		bls.s	BS_No_Swap	; No need to swap.
;
;    So swap them and count a swap:
		move.b	d0,1(a0)
		move.b	d1,(a0)
		addq.w	#$01,d2		; Increment swap counter
;
; 3 & 4. Point to the next pair:
BS_No_Swap:	addq.w	#$01,a0
		dbra	d3,BS_Bubble_Loop ; Swap all pairs
;
; 5. If we had any swaps, keep going:
		tst.w	d2
		bne.s	BS_Sort		; Keep sortin'
;
; ===========================================================================
;
; ---- Now show all of the 6 sorted chosen numbers ....
		moveq	#$05,d1
		lea	Lottery_Guesses(pc),a0
ST_Show_Loop:	moveq	#$00,d0
		move.b	(a0)+,d0
		bsr	ShowDecimal5
		dbra	d1,ST_Show_Loop
;
; ===========================================================================
;
; ---- Close dos library and exit: ....
		move.l	DosBase,a1
		SYS	CloseLibrary
;
ST_Failed_Dos:	moveq	#$00,d0		; Return no error code.
		rts
;
DosName:	dc.b	"dos.library",0	
DosBase:	dc.l	0		; Storage for dos.library base
STDOUT:		dc.l	0		; Storage for STDOUT file handle
;
Lottery_Guesses:dc.b	0,0,0,0,0,0
;
; .....................................
;
;	ShowDecimal5():
;
;	Shows the number in D0.l in Decimal on the screen, up to five
;	digits in length. Zeros are not supressed.
;
ShowDecimal5:	movem.l	d1/a0-a1,-(sp)
		moveq	#$04,d1
		lea	SD5_Dividors(pc),a1
		lea	SD5_Number(pc),a0
;
; ---- Create our number string ....
SD5_Loop:	move.l	(a1)+,d2
		divu	d2,d0		
		add.b	#$30,d0		; Turn result to ASCII number
		move.b	d0,(a0)+	; Put character to output buffer
;
		swap	d0
		and.l	#$ffff,d0	; Get remainder.
;
		dbra	d1,SD5_Loop	; Loop round doing all digits.
;
; ---- All done, show our number on screen ....
		lea	SD5_Number(pc),a0
		bsr	PrintString
		movem.l	(sp)+,d1/a0-a1
		rts
;
; ---- Dividor table & data for the decimal routine ....
SD5_Dividors:	dc.l	10000,1000,100,10,1
SD5_Number:	dc.b	"00000",10,0
;
; .....................................
;
;	PrintString():
;
;	Shows the string pointed to by A0 to STDOUT. This routine assumes
;	STDOUT has already been obtained and filled out. Registers on exit
;	are undefined.
;
PrintString:	move.l	a0,d2
		bsr	StringLength	; Get length of string
		move.l	d0,d3
		move.l	STDOUT,d1
		DOS	Write		; Show string on STDOUT
		rts
;
; .....................................
;
;	StringLength():
;
;	Returns the length of the string pointed to by A0 in D0. On exit,
;	A0 points to the end of the string.
;
StringLength:	moveq	#-1,d0
SL_Count:	addq.l	#$01,d0
		tst.b	(a0)+
		bne.s	SL_Count	; Count string till we reach the end
		rts
;
; ===========================================================================
;		Psuedo Random Number Generator
; ...........................................................................
;	%%%%
;	void Init_Seed(void)
;
;	This code was used in a similar form in the Aquatic Games.
;
;	No inputs, No outputs, Registers Preserved.
;	%%%%
;
IR_M:		equ	65535
IR_B:		equ	8821
;
Init_Seed:	movem.l	d0-d1/a0,-(sp)
		moveq	#$00,d0
IS_Re_Do:	move.w	$dff006,d0		; get random seed
		tst.w	d0
		beq.s	IS_Re_Do
		moveq	#64-1,d1
		lea	RandomBuffer,a0
IS_Loop:	mulu	#IR_B,d0
		addq.w	#1,d0
		divu	#IR_M,d0		;do seed=(seed*b+1) mod m
		swap	d0
		move.w	d0,(a0)+		;insert into array.
		dbra	d1,IS_Loop
		movem.l	(sp)+,d0-d1/a0
		rts
;
; ...........................................................................
;	%%%%
;	uword Random_Number(uword Max_Number)
;	 d0		     d0
;
;
;	This function returns a number between 0 and d0-1. It returns
;	the value in d0.	
;	This code was used in a similair form in the Aquatics.
;
;	Inputs:
;		Max_Number 	The maximum number to return + 1
;
;	Outputs:
;		random		The random number from 0 to Max_Number-1
;
;	Registers preserved.
;	%%%%
;
Random_Number:	movem.l	d1-d3/a0,-(sp)
		tst.w	d0
		bne.s	RN_Fine
		moveq	#$00,d0
		movem.l	(sp)+,d1-d3/a0
		rts
;
RN_Fine:	lea	RandomBuffer,a0
		addq.w	#2,RandomSeed
		moveq	#$00,d1
		move.w	RandomSeed,d1
		and.w	#63*2,d1
		moveq	#23*2,d3
		add.w	d1,d3
		and.w	#63*2,d3
		move.w	0(a0,d3.w),d2
		moveq	#54*2,d3
		add.w	d1,d3
		and.w	#63*2,d3
		move.w	0(a0,d3.w),d3
		eor.w	d3,d2			;could be add.w	d1,d2 also! (seems to work!)
		move.w	d2,0(a0,d1.w)		;insert back into table
		move.w	d2,d1			;return rand in d0.w
		divu.w	d0,d1
		swap	d1
		moveq	#$00,d0
		move.w	d1,d0
		movem.l	(sp)+,d1-d3/a0		
		rts
;
RandomBuffer:	dcb.w	64
RandomSeed:	dc.w	0			; Random # generator seed/bfr
		END
