		TTL	"Getting better lottery program"
;
; =========================
; Amiga Shopper Assembly Language Course: Part VIII
;
; Lottery-Mungus!
;
		section	PrintString,code
;
ENTRY_POINT:	bra.s	START			; Call start of program.
;
; ---- Embedded version string: ....
VERSION:	dc.b	0,"$VER: lottery.asm 1.04 (17.4.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"
		include	"intuition/intuition.i"
		include	"intuition/intuition_lib.i"	; THIS IS ON THE COVERDISK IF YOU DON'T HAVE IT
		include	"utility/tagitem.i"
;
; ---- System Equates ....
_EXECBASE:	equ	$04			; exec.library base.
TRUE:		equ	-1
FALSE:		equ	0			; TRUE/FALSE definitions
NULL:		equ	0			; Definition for NULL
;
; ---- Program equates ....
ADJUST_TOP:	equ	2			; Pixels down adjust
ADJUST_LEFT:	equ	2			; Pixels across adjust
FONT_HEIGHT:	equ	8			; Height of font we're using
FONT_WIDTH:	equ	8			; Width of each character
WINDOW_WIDTH:	equ	(FONT_WIDTH*17)+(ADJUST_LEFT*2)		; Window width (17 characters)
;
; ---- 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

INT:		macro
		move.l	IntBase,a6
		jsr	_LVO\1(a6)		; intuition.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.
;
; ---- Open intuition.library ....
		lea	IntName(pc),a1
		moveq	#$00,d0
		SYS	OpenLibrary
		move.l	d0,IntBase
		beq	ST_Failed_Int	; Quit if no INT.
;
; ---- Now open our window ....
		suba.l	a0,a0
		lea	WindowTags(pc),a1
		INT	OpenWindowTagList
		move.l	d0,WindowPtr
		beq	ST_Failed_Win	; Couldn't open window....
;
; ---- Find STDOUT: ....
		DOS	Output
		move.l	d0,STDOUT
;
; ---- Seed the random number generator ....
		bsr	Init_Seed
;
; ---- Initialise variables for our main loop ....
ST_Guess:	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 create the string for PrintIText ....
		moveq	#$05,d1
		lea	Lottery_Guesses(pc),a2
		lea	OurText(pc),a0	; Place we're creating our string
		moveq	#$00,d7
ST_Show_Loop:	moveq	#$00,d0
		move.b	(a2)+,d0
		bsr	ShowDecimal2
		move.b	#' ',(a0)+	; A space between each one...
		dbra	d1,ST_Show_Loop
		clr.b	-1(a0)		; A zero at the end.
;
; ---- Now show lottery guesses in our window ....		
		move.l	WindowPtr,a0
;
; ---- Work out X/Y position of text ....
		moveq	#$00,d0
		move.b	wd_BorderLeft(a0),d0	; Window border width: Left
		addq.w	#ADJUST_LEFT,d0		; Add adjuster to give X pixels
		moveq	#$00,d1
		move.b	wd_BorderTop(a0),d1	; Window border height: Top
		addq.w	#ADJUST_TOP,d1		; Add adjuster in to give Y pixels
;
; ---- Now show at this position ....
		lea	WindowText(pc),a1	; Filled in intuitext structure
		move.l	wd_RPort(a0),a0		; Rast-port
		INT	PrintIText
;
; ---- Finally wait for any messages to turn up ....
ST_Wait_Msg:	move.l	WindowPtr,a0
		move.l	wd_UserPort(a0),a0
		SYS	WaitPort	; Wait for message to arrive...
;
; ---- Loop through and process any messages present ....
ST_MoreMsgs:	move.l	WindowPtr,a0
		move.l	wd_UserPort(a0),a0
		SYS	GetMsg		; Get message
		tst.l	d0
		beq.s	ST_Wait_Msg	; Thats it, no more messages
;
; ---- Got one, process it ....
		move.l	d0,a1
		move.l	im_Class(a1),d0
		cmp.l	#IDCMP_CLOSEWINDOW,d0
		beq.s	ST_Quit		; Yes! The close gadget pressed
		cmp.l	#IDCMP_VANILLAKEY,d0
		beq.s	ST_KeyPress	; A key was pressed
;
; ---- Reply to it ....
ST_Back_In:	SYS	ReplyMsg
		bra.s	ST_Wait_Msg
;
; ===========================================================================
;
; ---- Deal with any key-presses ....
ST_KeyPress:	move.w	im_Code(a1),d0
		cmp.b	#" ",d0		; Was it a space?
		beq.s	ST_Space	; Yes - process it!
		cmp.b	#27,d0		; Was it the ESC key?
		beq.s	ST_Quit		; Yes - quit
		bra.s	ST_Back_In	; Unknown key, so continue waiting.
;
; ---- User pressed space, re-generate numbers ....
ST_Space:	SYS	ReplyMsg	; Don't forget to reply...
		bra	ST_Guess	; New guess
;
; ===========================================================================
;
; ---- Close librarys and exit: ....
ST_Quit:	SYS	ReplyMsg	; Ensure it is replied to
		move.l	WindowPtr,a0
		INT	CloseWindow	; Close window
;
ST_Failed_Win:	move.l	IntBase,a1
		SYS	CloseLibrary	; Close intuition
;
ST_Failed_Int:	move.l	DosBase,a1
		SYS	CloseLibrary	; Close dos
;
ST_Failed_Dos:	moveq	#$00,d0		; Return no error code.
		rts
;
IntName:	dc.b	"intuition.library",0
DosName:	dc.b	"dos.library",0	
IntBase:	dc.l	0		; Storage for intuition.library base
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
;
; ---- This is our openwindow taglist ....
WindowTags:	dc.l	WA_InnerWidth,WINDOW_WIDTH
		dc.l	WA_InnerHeight,FONT_HEIGHT+3
		dc.l	WA_CloseGadget,TRUE
		dc.l	WA_DepthGadget,TRUE
		dc.l	WA_DragBar,TRUE
		dc.l	WA_Activate,TRUE
		dc.l	WA_Title,wt_WindowTitle
		dc.l	WA_IDCMP,IDCMP_CLOSEWINDOW+IDCMP_VANILLAKEY
		dc.l	TAG_DONE
;
wt_WindowTitle:	dc.b	"Lottery Window!",0
;
WindowPtr:	dc.l	0		; struct Window *... Our window ID.
;
; ---- Our IntuiText structure ....
WindowText:	dc.b	1,0		; Pens to draw in, front and back
		dc.b	RP_JAM2
		dc.w	0,0
		dc.l	WindowTextFont
		dc.l	OurText
		dc.l	NULL
;
OurText:	ds.b	100		; Reserve 100 bytes of text
;
; ---- This is our TextAttr structure for the font we are using ....
WindowTextFont:	dc.l	wtf_Name
		dc.w	FONT_HEIGHT	; Height of font
		dc.b	0		; Font style (Bold, Italics etc...)
		dc.b	0		; Font Flags
;
wtf_Name:	dc.b	"topaz.font",0	; Font name
;
; .....................................
;
;	ShowDecimal2():
;
;	Converts decimal to ASCII. The ASCII is stored out at
;	whereever A0 points to. Leading zeros are supressed
;
ShowDecimal2:	movem.l	a1/d0-d2,-(sp)
		moveq	#$01,d1
		lea	SD2_Dividors(pc),a1
		moveq	#TRUE,d3	; Supress Zero flag
;
; ---- Create our number string ....
SD2_Loop:	move.l	(a1)+,d2
		divu	d2,d0		
		add.b	#$30,d0		; Turn result to ASCII number
;
		cmp.b	#$30,d0		; Is it a zero?
		bne.s	SD2_NotZero
		tst.w	d3
		beq.s	SD2_Continue
		move.b	#" ",(a0)+	; Leading zeros converted to spaces
		bra.s	SD2_Skip
;
SD2_NotZero:	moveq	#FALSE,d3	; No more zero supression
;
SD2_Continue:	move.b	d0,(a0)+	; Put character to output buffer
SD2_Skip:	swap	d0
		and.l	#$ffff,d0	; Get remainder.
;
		dbra	d1,SD2_Loop	; Loop round doing all digits.
		movem.l	(sp)+,d0-d2/a1
		rts
;
; ---- Dividor table & data for the decimal routine ....
SD2_Dividors:	dc.l	10,1
;
; .....................................
;
;	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
