RPG   =   Role Playing Game.



You're running a tabletop RPG, and your players are creating characters.

Each character has six core attributes: strength, dexterity, constitution, intelligence, wisdom, and charisma.

One way of generating values for these attributes is to roll four, 6-sided dice (d6) and sum the three highest rolls, discarding the lowest roll.

Some players like to assign values to their attributes in the order they're rolled.

To ensure generated characters don't put players at a disadvantage, the following requirements must be satisfied:

 The total of all character attributes must be at least 75.
 At least two of the attributes must be at least 15.

However, this can require a lot of manual dice rolling. A programatic solution would be much faster.



Task

Write a program that:

 Generates 4 random, whole values between 1 and 6.
 Saves the sum of the 3 largest values.
 Generates a total of 6 values this way.
 Displays the total, and all 6 values once finished.

 The order in which each value was generated must be preserved.
 The total of all 6 values must be at least 75.
 At least 2 of the values must be 15 or more.

	bits	16
	cpu	8086
putch:	equ	2h
time:	equ	2ch
	org	100h
section	.text
	mov	ah,time		; Retrieve system time from MS-DOS
	int	21h
	call	rseed		; Seed the RNG
rolls:	xor	ah,ah		; AH=0 (running total)
	mov	dx,6		; DH=0 (amount >=15), DL=6 (counter)
	mov	di,attrs
attr:	call	roll4		; Roll an attribute
	mov	al,14
	cmp	al,bh		; Set carry if BH=15 or more
	mov	al,bh		; AL = roll
	sbb	bh,bh		; BH=0 if no carry, -1 if carry
	sub	dh,bh		; DH+=1 if >=15
	add	ah,al		; Add to running total
	mov	[di],al		; Save roll
	inc	di		; Next memory address
	dec	dl		; One fewer roll left
	jnz	attr
	cmp	ah,75		; Rolling total < 75?
	jb	rolls		; Then roll again.
	cmp	dh,2		; Fewer than 2 attrs < 15?
	jb	rolls		; Then roll again.
	;;;	Print the attributes
	mov	cx,6		; 6 attributes
p2:	mov	bl,10		; divide by 10 to get digits
	mov	di,attrs
print:	xor	ah,ah		; AX = attribute
	mov	al,[di] 
	div	bl		; divide by 10
	add	ax,3030h	; add '0' to quotient (AH) and remainder (AL)
	mov	dx,ax
	mov	ah,putch	
	int	21h		; print quotient first
	mov	dl,dh		; then remainder
	int	21h
	mov	dl,' '		; then a space
	int	21h
	inc	di		; Next attribute
	loop	print
	ret			; Back to DOS 	
	;;;	Do 4 rolls, and get result of max 3
roll4:	xor	bx,bx		; BH = running total
	dec	bl		; BL = lowest value
	mov	cx,4		; Four times
.roll:	call	d6		; Roll D6
	cmp 	al,bl		; Lower than current lowest value?
	jnb	.high		; If so,
	mov	bl,al		; Set new lowest value
.high:	add	bh,al		; Add to running total
	loop	.roll		; If not 4 rolls yet, loop back
	sub	bh,bl		; Subtract lowest value (giving sum of high 3)
	ret
	;;;	Roll a D6
d6:	call	rand		; Get random number
	and	al,7		; Between 0 and 7
	cmp	al,6		; If 6 or higher,
	jae	d6		; Then get new random number
	inc	al		; [1..6] instead of [0..5]
	ret
	;;;	Seed the random number generator with 4 bytes
rseed:	xor	[rnddat],cx
	xor	[rnddat+2],dx
	;;;	"X ABC" random number generator
	;;;	Generates 8-bit random number in AL
rand:	push	cx		; Keep registers
	push	dx
	mov	cx,[rnddat]	; CL=X CH=A
	mov	dx,[rnddat+2]	; DL=B DH=C
	xor	ch,dh		; A ^= C
	xor	ch,cl		; A ^= X
	add	dl,ch		; B += A
	mov	al,dl		; R = B
	shr	al,1		; R >>= 1
	xor	al,ch		; R ^= A
	add	al,dh		; R += C
	mov	dh,al		; C = R
	mov	[rnddat],cx	; Store new state
	mov	[rnddat+2],dx
	pop	dx		; Restore registers
	pop	cx
	ret
section	.bss
rnddat:	resb	4		; RNG state
attrs:	resb	6		; Rolled attributes