Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

1. Výpočet tabulky výher

Výhernost automatu VEGASLOT je řízena výherní tabulkou s nelineární výherností. Zde je popsán návrh výherního systému automatu.

Jako první je potřeba se rozhodnout, kolik bude použito symbolů na válcích a jaké budou výherní kombinace. U některých parametrů automatu přihlédneme k technickému řešení. Počet symbolů omezíme na 6 (počet symbolů zobrazitelných na obrázku grafiky), počet pozic válce použijeme 32 (pozici všech 3 válců je možné snadno vyjádřit 16-bitovým číslem). Pro výherní kombinace použijeme kombinace stejných symbolů. Podle předpisů v České republice bude maximální hodnota výhry 750, takže po rovnoměrném rozdělení použijeme výherní kombinace 10, 20, 50, 100, 200 a 750 (pro stejné symboly třešeň, jablko, švestka, hruška, hrozen a zvonek). Větší interval mezi 200 a 750 je zvolen záměrně pro zvýšení napětí hry (spojené se symbolem zvonku).

Dalším úkonem bude rozvržení symbolů na válcích. Při rozvržení symbolů je hlavním požadavkem, aby bylo dosaženo velké pestrosti kombinací výher (i na více liniích současně), aby byla hra co nejzajímavější a aby se neobjevovaly stále stejné kombinace symbolů. Toho dosáhneme nejlépe rovnoměrným rozmístěním symbolů od nejnižšího k nejvyššímu s lehkým zpřeházením blízkých symbolů. Doplňkovým kritériem je omezení výše výhry na 750, proto musíme zajistit, aby se v oblasti vysokých symbolů neobjevila kombinace poskytující vyšší výhru. Není velký problém vyšší výhru ošetřit programově (přeskočením nepovolené kombinace) nebo herně (bonusovou hrou), ale raději tuto situaci ošetříme již při projektování válců. Upřesnění rozmístění symbolů provedeme později podle tabulek výhernosti.

V dávných dobách (obzvláště u mechanických výherních automatů) byla výhernost automatu řešena rozmístěním symbolů na válcích a otáčením válců na náhodné pozice. V dnešní počítačové době nejsou válce otáčeny na náhodné pozice, ale jsou generovány výherní kombinace tak, aby bylo dosaženo požadované výhernosti. To umožňuje používat pestřejší a zajímavější výherní kombinace s plynulejším rozložením typů výher.

Při generování příští pozice válců používá automat výherní tabulku, ve které jsou uloženy předepsané výhernosti jednotlivých typů výher. Automat nejdříve vygeneruje náhodné číslo a poté prohledává tabulku výher, až nalezne typ výhry, do jehož intervalu výhernosti vygenerované číslo spadá. Následuje vyhledání kombinace válců s daným typem výhry (nebo naopak prohry) a natočení válců na nalezenou pozici.

Pro výpočet tabulky výhernosti si vytvoříme zdrojový soubor GAMETAB.ASM, který budeme překládat příkazem "NASM16.EXE -o GAMETAB.COM GAMETAB.ASM". Jedná se o DOS program, který vypisuje tabulky na konzolový výstup. Přesměrováním výstupu do souboru příkazem "GAMETAB.COM > GAMETAB.INC" se vygeneruje soubor zdrojového kódu, který použijeme v hlavním programu automatu.

Jako první si připravíme obsluhu konzolového výstupu a základní definice podle následujícího výpisu programu (pro přehlednost je program mírně zjednodušen, kód lze stáhnout jako předvariantu A).

SYMBOLS		equ	6		; number of types of symbols
C		equ	0		; shortcut of symbol "cherry"
A		equ	1		; shortcut of symbol "apple"
P		equ	2		; shortcut of symbol "plum"
E		equ	3		; shortcut of symbol "pear"
G		equ	4		; shortcut of symbol "grape"
B		equ	5		; shortcut of symbol "bell"
POS		equ	32		; number of positions on one reel

SECTION		.text
		org	100h		; start of COM program

; ------------- Print help 1

Start:		mov	ax,TextHelp1	; AX <- help 1
		call	PrintText	; print help 1

; ------------- Print symbols on reels

		mov	al,0		; AL <- 0 first reel
		call	PrintReel	; print symbols on reel 0
		mov	ax,TextHelp2	; AX <- help 2
		call	PrintText	; print help 2
		mov	al,1		; AL <- 1 second reel
		call	PrintReel	; print symbols on reel 1
		mov	ax,TextHelp2	; AX <- help 2
		call	PrintText	; print help 2
		mov	al,2		; AL <- 2 third reel
		call	PrintReel	; print symbols on reel 2

; ------------- Print help 3

		mov	ax,TextHelp3	; AX <- help 3
		call	PrintText	; print help 3

; ------------- Print winning values

		cld			; direction up
		mov	cx,SYMBOLS-1	; number of symbols - 1
		mov	si,WinVal	; table of winning values
Start1:		lodsw			; AX <- value of one symbol
		call	PrintNum	; print value of one symbol
		mov	al,","		; AL <- comma character
		call	PrintChar	; print comma character
		loop	Start1		; print next value
		lodsw			; AX <- value of last symbol
		call	PrintNum	; print value of last symbol
		int	20h		; end of program

; ----------------------------------------------------------------------------
;                            Print symbols on one reel
; ----------------------------------------------------------------------------
; INPUT:	AL = reel (0 to 2)
; ----------------------------------------------------------------------------

; ------------- Push registers

PrintReel:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	si		; push SI
		
; ------------- Prepare registers

		cld			; direction up
		mov	cx,POS		; CX <- positions on one reel
		mul	cl		; AX <- offset of reel tab
		add	ax,ReelTab	; AX <- addres of reel tab
		xchg	ax,si		; SI <- addres of reel tab

; ------------- Display one symbol

PrintReel2:	xor	ax,ax		; AX <- 0
		lodsb			; AL <- one symbol
		xchg	ax,bx		; BX <- symbol
		mov	al,[bx+TextSymb]; AL <- character of symbol
		call	PrintChar	; print symbol

; ------------- Print comma

		cmp	cl,1		; is it last symbol?
		je	PrintReel3	; it is last symbol
		mov	al,","		; comma character
		call	PrintChar	; print comma character
PrintReel3:	loop	PrintReel2	; print next symbol

; ------------- Pop registers

		pop	si		; pop SI
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                         Print number with comma
; ----------------------------------------------------------------------------
; INPUPT:	AX = number to print
; ----------------------------------------------------------------------------

PrintNumCom:	call	PrintNum	; print number
                push	ax		; push AX
		mov	ax,TextComma	; AX <- text ", "
		call	PrintText	; print text ", "
		pop	ax		; pop AX
		ret
		
; ----------------------------------------------------------------------------
;                             Print number
; ----------------------------------------------------------------------------
; INPUPT:	AX = number to print
; ----------------------------------------------------------------------------

; ------------- Push registers

PrintNum:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX

; ------------- Convert number do digits

		xor	cx,cx		; CX <- 0 character counter
		mov	bx,10		; BX <- 10 divisor
PrintNum2:	xor	dx,dx		; DX <- 0
		div	bx		; divide DX:AX with 10
		xchg	ax,dx		; AX <- remainder
		add	al,'0'		; convert to printable character
		push	ax		; push character to stack
		inc	cx		; increase character counter
		xchg	ax,dx		; AX <- quotient
		or	ax,ax		; is it zero?
		jnz	PrintNum2	; it is not zero yet

; ------------- Display digits

PrintNum3:	pop	ax		; pop character from stack
		call	PrintChar	; print character
		loop	PrintNum3	; print next character

; ------------- Pop registers

		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                             Print ASCIIZ text
; ----------------------------------------------------------------------------
; INPUPT:	AX = text to print
; ----------------------------------------------------------------------------

; ------------- Push registers

PrintText:	push	ax		; push AX 
		push	si		; push SI

; ------------- Print text

		cld			; direction up
		xchg	ax,si		; SI <- text to print
PrintText2:	lodsb			; AL <- character to print
		or	al,al		; is it end of text?
		jz	PrintText4	; it is end of text
		call	PrintChar	; print character
		jmp	short PrintText2 ; next character

; ------------- Pop registers

PrintText4:	pop	si		; pop SI
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                        Print tabulator to position
; ----------------------------------------------------------------------------
; INPUT:	AL = required position
; ----------------------------------------------------------------------------

PrintTabPos:	call	PrintTab	; print tabulator
		cmp	al,[CharPos]	; is it required position?
		ja	PrintTabPos	; print next tabulator
		ret
		
; ----------------------------------------------------------------------------
;                             Print tabulator
; ----------------------------------------------------------------------------

PrintTab:	push	ax		; push AX
		mov	al,9		; AL <- TAB character
		call	PrintChar	; print TAB character
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                            Print end of line
; ----------------------------------------------------------------------------

PrintCRLF:	push	ax		; push AX
		mov	al,13		; AL <- CR character
		call	PrintChar	; print CR character
		mov	al,10		; AL <- LF character
		call	PrintChar	; print LD character
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                             Print character
; ----------------------------------------------------------------------------
; INPUPT:	AL = character to print
; ----------------------------------------------------------------------------

; ------------- Push registers

PrintChar:	push	ax		; push AX
		push	dx		; push DX

; ------------- End of line (CR character)

		cmp	al,13		; is it CR character?
		jne	PrintChar2	; it is not CR character
		mov	byte [CharPos],0 ; reset character position
		jmp	short PrintChar6 ; print character

; ------------- Tabulator (TAB character)

PrintChar2:	cmp	al,9		; is it TAB character?
		jne	PrintChar4	; it is not TAB character
		add	byte [CharPos],8 ; round position up
		and	byte [CharPos],~7 ; tab position
		jmp	short PrintChar6 ; print character

; ------------- Other characters

PrintChar4:	inc	byte [CharPos]	; increase character position

; ------------- Print character

PrintChar6:	mov	dl,al		; DL <- character to print
		mov	ah,2		; AH <- function code
		int	21h		; print character

; ------------- Pop registers

		pop	dx		; pop DX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                                Data
; ----------------------------------------------------------------------------

CharPos:	db	0
TextHelp1:	db	"SECTION",9,9,".text",13,10
		db	"ReelTab: db ",0
TextHelp2:	db	13,10,9," db ",0

TextHelp3:	db	13,10
		db	"WinVal:",9,9,"dw",9,0

TextDW:		db	9,9,"dw",9,0
TextDW2:	db	":",9,"dw",9,0
TextComma:	db	",",9,0
TextSymb:	db	"CAPEGB"

ReelTab:
Reel0:	db  C,C,C,C,C,A,A,P,P,E,P,A,C,P,A,C,G,E,A,E,G,C,A,G,E,G,A,P,P,B,C,A
Reel1:	db  C,C,C,A,C,A,A,P,E,P,A,E,P,A,C,G,E,G,E,P,C,P,A,G,E,G,C,A,E,B,A,C
Reel2:	db  C,C,C,G,C,A,A,A,P,C,G,P,E,P,C,E,G,E,C,E,B,G,P,G,E,G,C,E,G,B,P,A

WinVal:		dw	10,20,50,100,200,750	; C,A,P,E,G,B

Výstupem programu je následující text:

SECTION             .text
ReelTab: db C,C,C,C,C,A,A,P,P,E,P,A,C,P,A,C,G,E,A,E,G,C,A,G,E,G,A,P,P,B,C,A
         db C,C,C,A,C,A,A,P,E,P,A,E,P,A,C,G,E,G,E,P,C,P,A,G,E,G,C,A,E,B,A,C
         db C,C,C,G,C,A,A,A,P,C,G,P,E,P,C,E,G,E,C,E,B,G,P,G,E,G,C,E,G,B,P,A
WinVal:         dw      10,20,50,100,200,750

Program na svém konci obsahuje tabulku definice rozmístění symbolů na válcích ReelTab, ve které jsou použita symbolická označení symbolů ze začátku programu. Ústřední funkcí pro výpis textu na konzolu je funkce PrintChar, která zobrazí znak v registru AL. Funkce zajišťuje sledování pozice znaku na řádku, což je využíváno při odsazení textu na požadovanou pozici funkcí PrintTabPos. Funkce PrintText zobrazí text z adresy DS:AX ukončený binární nulou. Funkce PrintNum zobrazí číslo z registru AX. Funkce PrintReel zobrazí definici jednoho válce. Načítá definiční bajty z tabulky ReelTab a převádí je na znaky pomocí tabulky TextSymb.

Na první pohled se funkce programu může zdát nelogická - načítat data z programu a zobrazovat je ve stejné formě jako zdrojový text. Důvodem je zajištění snadné modifikovatelnosti programu a zabezpečení, aby byl připraven pro koncový program kompaktní zdrojový kód i po změnách v definičních tabulkách a nedošlo tak k nesynchronitě programů.

V následující části zajistíme vyhodnocení statistiky výher. Připravíme funkce, které projdou všechny kombinace válců, vyhodnotí možné výhry a zařadí je do tabulek typů výher. Doplňte do programu následující části kódu (nebo můžete kód stáhnout jako předvariantu B).

Doplněk do definic v záhlaví programu:


LINES		equ	5		; number of winning lines
SYMMASK		equ	7		; mask of symbol index
POSMASK		equ	1fh		; mask of reel position

struc		WinItem
win_value	resw 	1		; value of win prize (1 to 750)
win_type	resw	1		; winning types
					;  3 bits: symbol 1
					;  3 bits: number of lines with symbol 1
					;  3 bits: symbol 2
					;  3 bits: number of lines with symbol 2
					;  3 bits: symbol 3
					;  1 bit:  number of lines with symbol 3
win_num		resw	1		; number of wins
win_rand	resw	1		; randomness (0 to 0ffffh)
endstruc

WINITEM_SIZE	equ	8

Doplněk na konec hlavní funkce programu (před funkci int 20h):


; ------------- Initialize winning tables

		mov	dl,1		; DL <- 1 winning lines
Start2:		call	CalcWinTab	; calculate winning table
		call	SortWinTab	; sort winning table

; ------------- Print winning table
		
Start7:		call	PrintWinTab	; print winning table
		inc	dx		; increase number of winning lines
		cmp	dl,LINES	; were all winning lines?
		jbe	Start2		; next winning line

; ------------- Print help 5

		mov	ax,TextHelp5	; AX <- help 5
		call	PrintText	; print help 5

Doplněk do funkcí programu:


; ----------------------------------------------------------------------------
;                            Print Winning Table
; ----------------------------------------------------------------------------
; INPUT:	DL = number of lines (1 to 5)
; ----------------------------------------------------------------------------

; ------------- Push registers

PrintWinTab:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push 	si		; push SI

; ------------- Prepare registers

		cld			; set direction up
		mov	si,WinTab	; SI <- winning table
		mov	cx,[WinTabNum]	; CX <- number of wintab items

; ------------- Print label

		mov	ax,TextWinTab	; AX <- text of label
		call	PrintText	; print text of label
		xor	ax,ax		; AX <- 0
		mov	al,dl		; AL <- number of lines
		call	PrintNum	; print number of label

; ------------- Print prefix of line

		mov	ax,TextDW2	; AX <- text ": dw"
		call	PrintText	; print text ": dw"

; ------------- Print zero profit

		xor	ax,ax		; AX <- 0
		call	PrintNumCom	; print zero profit with comma

; ------------- Print number of items

		mov	ax,cx		; AX <- number of items
		call	PrintNumCom	; print number of items with comma

; ------------- Print total wins

		mov	ax,[WinTabTot]	; AX <- total wins
		call	PrintNumCom	; print number of total wins with comma

; ------------- Print total randomness

		mov	ax,[WinTabRand]	; AX <- total randomness
		call	PrintNum	; print total randomness

; ------------- Print remark separator

		mov	ax,TextRemark	; AX <- text "; "
		call	PrintText	; print text "; "
		mov	ax,TextProfit	; AX <- "Profit"
		call	PrintText	; print text "Profit"

; ------------- Print profit

		push	dx		; push DX
		mov	ax,[WinTabProf]	; AX <- profit
		xor	dx,dx		; DX <- 0
		mov	bx,100		; BX <- 100 divisor
		div	bx		; AX <- percents, DX <- hundredths
		call	PrintNum	; print percents
		mov	al,"."		; decimal point
		call	PrintChar	; print decimal point
		xchg	ax,dx		; AX <- hundredths, DX <- percents
		mov	bl,10           ; BL <- 10 divisor
		div	bl		; AL <- decimals, AH <- hundreths
		or	ax,"00"		; correction to characters
		call	PrintChar	; print decimals
		mov	al,ah		; AL <- hundreths
		call	PrintChar	; print hundreths
		pop	dx		; pop DX
		mov	al,"%"		; percentage character
		call	PrintChar	; print percentage

; ------------- Print end of line

		call	PrintCRLF	; print end of line
		jcxz	PrintWinTab9	; there is no wintab item

; ------------- Print prefix of line

PrintWinTab2:	mov	ax,TextDW	; AX <- text "dw"
		call	PrintText	; print text "dw"

; ------------- Print winning prize

		mov	ax,[si+win_value] ; AX <- winning prize
		call	PrintNumCom	; print winning prize with comma

; ------------- Print winning type

		mov	ax,[si+win_type] ; AX <- winning type
		call	PrintNumCom	; print winning type with comma

; ------------- Print number of wins

		mov	ax,[si+win_num]	; AX <- number of wins
		call	PrintNumCom	; print number of wins with comma

; ------------- Print randomness

		mov	ax,[si+win_rand]; AX <- randomness
		call	PrintNum	; print randomness

; ------------- Print remark separator

		mov	ax,TextRemark	; AX <- text "; "
		call	PrintText	; print text "; "

; ------------- Winning types

		mov	dx,[si+win_type] ; DX <- winning types

; ------------- Print winning value of symbol

PrintWinTab3:	mov	ax,dx		; AX <- winning symbol
		shr	dx,1		; DX >> 1
		shr	dx,1		; DX >> 1
		shr	dx,1		; DX >> 1
		and	ax,7		; AX = symbol
		shl	ax,1		; AX = symbol * 2
		xchg	ax,bx		; BX <- offset in table
		mov	ax,[bx+WinVal]	; AX <- winning value
		call	PrintNum	; print winning value

; ------------- Print number of lines with symbol

		mov	ax,dx		; AX <- number of lines
		shr	dx,1		; DX >> 1
		shr	dx,1		; DX >> 1
		shr	dx,1		; DX >> 1
		and	ax,7		; AX = number of symbol
		cmp	ax,1		; is there 2 or more lines?
		jbe	PrintWinTab4	; there is only 1 line
		push	ax		; push AX
		mov	al,"x"		; character "x"
		call	PrintChar	; print character "x"
		pop	ax		; pop AX
		call	PrintNum	; print number of lines

; ------------- Test, if there will be next symbol

PrintWinTab4:	test	dx,7 << 3	; will be next symbol?
		jz	PrintWinTab6	; it was last symbol
		mov	al," "		; separator (space)
		call	PrintChar	; print separator
		jmp	short PrintWinTab3 ; print next symbol

; ------------- Print end of line

PrintWinTab6:	call	PrintCRLF	; print end of line

; ------------- Next winning prize

		add	si,WINITEM_SIZE	; next winning item
		loop	PrintWinTab2	; nest winning item

; ------------- pop registers

PrintWinTab9:	pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop 	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                     Sort winning table (slow bubble sort)
; ----------------------------------------------------------------------------

; ------------- Push registers

SortWinTab:	push	ax		; push AX
		push	cx		; push CX
		push	si		; push SI

; ------------- Start one passage

		cld			; direction up
SortWinTab2:	mov	si,WinTab	; SI <- winning table
		mov	cx,[WinTabNum]	; CX <- number of winning table items
		jcxz	SortWinTab7	; not enough items
		dec	cx		; CX <- number of item pairs
		jcxz	SortWinTab7	; not enough items
		
; ------------- Compare two items

SortWinTab3:	mov	ax,[si+win_value] ; winning value
		cmp	ax,[si+WINITEM_SIZE+win_value] ; compare with next item
		jne	SortWinTab4	; winning value is not the same
		mov	ax,[si+win_type] ; winning type
		cmp	ax,[si+WINITEM_SIZE+win_type] ; compare with next item	
SortWinTab4:	jbe	SortWinTab6	; items are in right order

; ------------- Exchange items

		mov	cx,WINITEM_SIZE/2 ; CX <- number of words
SortWinTab5:	lodsw			; AX <- load 1 word of item
		xchg	ax,[si+WINITEM_SIZE-2] ; exchange 1 word
		mov	[si-2],ax	; store 1 word
		loop	SortWinTab5	; next word of item
		jmp	short SortWinTab2 ; repeat sorting

; ------------- Next item

SortWinTab6:	add	si,WINITEM_SIZE	; SI <- next item
		loop	SortWinTab3	; sort next item

; ------------- Pop registers

SortWinTab7:	pop	si		; pop SI
		pop	cx		; pop CX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                         Calculate winning table
; ----------------------------------------------------------------------------
; INPUT:	DL = number of lines (1 to 5)
; ----------------------------------------------------------------------------

; ------------- Push registers

CalcWinTab:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	di		; push DI
		push	bp		; push BP
		push	es		; push ES

; ------------- Prepare registers

		xor	bx,bx		; BX <- 0 reel position pointer
		mov	[WinTabNum],bx	; reset counter of wintab items
		mov	[WinTabTot],bx	; reset counter of total wins
		mov	di,WinTab	; DI <- winning table
		push	ds		; push DS
		pop	es		; ES <- data segment
		cld			; set direction up

; ------------- Test winning symbol -> DH mask, BP symbols

CalcWinTab2:	call	TestSymbol	; test winning symbol

; ------------- Calculate winning prize -> AX

		call	GetPrize	; calculate winning prize
		or	ax,ax		; is any winning prize?
		jz	CalcWinTab6	; there is no winning prize
		inc	word [WinTabTot] ; increase counter of total wins

; ------------- Calculate winning types -> BP

		push	ax		; push AX
		call	GetTypes	; calculate winning types
		xchg	ax,bp		; BP <- winning types
		pop	ax		; pop AX

; ------------- Search, if this win already exists

		mov	si,WinTab	; SI <- winning table
		mov	cx,[WinTabNum]	; CX <- number of winning table items
		jcxz	CalcWinTab5	; there is no wintab item
CalcWinTab3:	cmp	ax,[si+win_value]; check winning prize
		jne	CalcWinTab4	; it is not this case
		cmp	bp,[si+win_type]; check winning types
		jne	CalcWinTab4	; it is not this case
		inc	word [si+win_num]; increase number of wins
		jmp	short CalcWinTab6 ; next reel position

CalcWinTab4:	add	si,WINITEM_SIZE	; next wintable item
		loop	CalcWinTab3	; test next item

; ------------- Create new winning table item

CalcWinTab5:	stosw			; store winning prize
		xchg	ax,bp		; AX <- winning types
		stosw			; store winning types
		mov	ax,1		; AX <- 1 initial number of wins
		stosw			; store number of wins
		stosw			; store randomness
		inc	word [WinTabNum]; increase number of wintable items

; ------------- Next reel position

CalcWinTab6:	inc	bx		; increase reel position
		jns	CalcWinTab2	; next position

; ------------- Pop registers

		pop	es		; pop ES
		pop	bp		; pop BP
		pop	di		; pop DI
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                          Calculate winning types
; ----------------------------------------------------------------------------
; INPUT:	DL = number of lines (1 to 5)
;		DH = winning mask, bit 0 to 4: there is win on line 0 to 4
;		BP = winning symbols on lines
;			bit  0 to  2: symbol in line 0
;			bit  3 to  5: symbol in line 1
;			bit  6 to  8: symbol in line 2
;			bit  9 to 11: symbol in line 3
;			bit 12 to 14: symbol in line 4
; OUTPUT:	AX = winning types
;			bit  0 to  2: symbol 1
;			bit  3 to  5: number of lines with symbol 1
;			bit  6 to  8: symbol 2
;			bit  9 to 11: number of lines with symbol 2
;			bit 12 to 14: symbol 3
;			bit 15:       number of lines with symbol 3
; ----------------------------------------------------------------------------

; ------------- Push registers

GetTypes:	push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	di		; push DI
		push	bp		; push BP

; ------------- Prepare registers

		xor	si,si		; SI <- 0 number of lines LOW
		xor	di,di		; DI <- 0 number of lines HIGH

; ------------- Test, if there is a win on this line

GetTypes2:	test	dh,1		; is there a win?
        	jz	GetTypes5	; there is not a win

; ------------- Winning symbol complement -> CX

		mov	cx,SYMBOLS-1	; CX <- number of symbols-1
		sub	cx,bp		; CX <- winning symbol complement
		and	cx,SYMMASK	; mask winning symbol complement
		mov	ax,cx		; AX <- winning symbol complement
		add	cx,ax		; CX <- symbol * 2
		add	cx,ax		; CX <- symbol * 3

; ------------- Prepare mask -> BX:AX

		mov	ax,1		; AX <- 1 mask LOW
		xor	bx,bx		; BX <- 0 mask HIGH
		jcxz	GetTypes4	; no rotation
GetTypes3:	shl	ax,1		; rotate AX left
		rcl	bx,1		; rotate BX left with carry
		loop	GetTypes3	; rotate next bit

; ------------- Increase symbol counter

GetTypes4:	add	si,ax		; increase counter LOW
		adc	di,bx		; increase counter HIGH

; ------------- Next line

GetTypes5:	shr	dh,1		; rotate winning mask
		mov	cl,3		; CL <- 3 number of rotation
		shr	bp,cl		; rotate winning symbols on lines
		dec	dl		; will there be next line?
		jnz	GetTypes2	; next line

; ------------- Pack symbol counters

		xor	ax,ax		; AX <- 0 winning types
		mov	dx,SYMBOLS-1	; DX <- number of symbols-1
GetTypes6:	mov	bx,si		; BX <- counter LOW
		and	bx,7		; mask number of lines
		jz	GetTypes7	; this symbol has 0 lines

; ------------- Add this symbol to winning types

		shl	ax,cl		; shift winning types left
		or	ax,bx		; AX << number of lines
		shl	ax,cl		; shift winning types left
		or	ax,dx		; AX << symbol number

; ------------- Next symbol

GetTypes7:	shr	di,1		; rotate lines counter HIGH
		rcr	si,1		; rotate lines counter LOW
		shr	di,1		; rotate lines counter HIGH
		rcr	si,1		; rotate lines counter LOW
		shr	di,1		; rotate lines counter HIGH
		rcr	si,1		; rotate lines counter LOW
		sub	dx,1		; number of symbol
		jnc	GetTypes6	; next symbol

; ------------- Pop registers

		pop	bp		; pop BP
		pop	di		; pop DI
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		ret

; ----------------------------------------------------------------------------
;                          Calculate winning prize
; ----------------------------------------------------------------------------
; INPUT:	DL = number of lines (1 to 5)
;		DH = winning mask, bit 0 to 4: there is win on line 0 to 4
;		BP = winning symbols on lines
;			bit  0 to  2: symbol in line 0
;			bit  3 to  5: symbol in line 1
;			bit  6 to  8: symbol in line 2
;			bit  9 to 11: symbol in line 3
;			bit 12 to 14: symbol in line 4
; OUTPUT:	AX = winning prize
; ----------------------------------------------------------------------------

; ------------- Push registers

GetPrize:	push	bx		; push BX
		push	dx		; push DX
		push	bp		; push BP

; ------------- Prepare registers

		xor	ax,ax		; AX <- 0 prize accumulator
		
; ------------- Test, if there is a win on this line

GetPrize2:	test	dh,1		; is there a win?
        	jz	GetPrize3	; there is not a win

; ------------- Add winning value

		mov	bx,bp		; bx <- symbol
		and	bx,SYMMASK	; mask one symbol
		shl	bx,1		; index of symbol * 2
		add	ax,[bx+WinVal]	; add winning value

; ------------- Next line

GetPrize3:	shr	dh,1		; rotate winning mask
		shr	bp,1
		shr	bp,1
		shr	bp,1		; rotate symbols on lines
		dec	dl		; will there be next line?
		jnz	GetPrize2	; next line

; ------------- Pop registers

		pop	bp		; pop BP
		pop	dx		; pop DX
		pop	bx		; pop BX
		ret

; ----------------------------------------------------------------------------
;                            Test winning symbols
; ----------------------------------------------------------------------------
; INPUT:	BX = reel positions
;			bit  0 to  4: position of reel 0
;			bit  5 to  9: position of reel 1
;			bit 10 to 14: position of reel 2
; OUTPUT:	DH = winning mask, bit 0 to 4: there is win on line 0 to 4
;		BP = winning symbols on lines
;			bit  0 to  2: symbol in line 0
;			bit  3 to  5: symbol in line 1
;			bit  6 to  8: symbol in line 2
;			bit  9 to 11: symbol in line 3
;			bit 12 to 14: symbol in line 4
; ----------------------------------------------------------------------------

; ------------- Push registers

TestSymbol:	push	ax		; push AX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI

; ------------- Prepare registers

		cld			; direction up
		mov	si,Lines	; SI <- offsets of lines
		xor	bp,bp		; BP <- 0 winning symbols
		mov	cx,100h		; CH <- 1 bit mask, CL <- 0 rotations
		mov	dx,LINES	; DH <- 0 winning mask, DL <- lines

; ------------- Get symbol on reel 0 -> BP, CH

TestSymb2:	push	cx		; push CX
		push	dx		; push DX

		lodsw			; AX <- offset of symbol
		push	bx		; push BX
		add	bx,ax		; add offset of symbol
		and	bx,POSMASK	; mask of position of reel 0
		mov	al,[bx+Reel0]	; symbol on reel 0
		mov	ah,0		; AH <- 0
		mov	ch,al		; CH <- save symbol on reel 0
		shl	ax,cl		; rotate symbol on position
		or	bp,ax		; BP <- save symbol in this line
		pop	bx		; pop BX

; ------------- Get symbol on reel 1 -> DL

		lodsw			; AX <- offset of symbol
		push	bx		; push BX
		mov	cl,5		; CL <- number of rotations
		shr	bx,cl		; rotate position of reel 1
		add	bx,ax		; add offset of symbol
		and	bx,POSMASK	; mask of position of reel 1
		mov	dl,[bx+Reel1]	; symbol on reel 1
		pop	bx		; pop BX
		
; ------------- Get symbol on reel 2 -> DH

		lodsw			; AX <- offset of symbol
		push	bx		; push BX
		mov	cl,10		; CL <- number of rotations
		shr	bx,cl		; rotate position of reel 2
		add	bx,ax		; add offset of symbol
		and	bx,POSMASK	; mask of position of reel 2
		mov	dh,[bx+Reel2]	; symbol on reel 2
		pop	bx		; pop BX

; ------------- Compare symbols if there are identical
		
		cmp	ch,dl		; are symbols 0 and 1 identical?
		jne	TestSymb3	; there are not identical
		cmp	ch,dh		; are symbols 0 and 2 identical?

TestSymb3:	pop	dx		; pop DX
		pop	cx		; pop CX
		jne	TestSymb4	; symbols are not identical

; ------------- Set flag this is winning position	

		or	dh,ch		; DH <- set winning mask

; ------------- Next line

TestSymb4:	add	cl,3		; increase number of rotation of symbol
		shl	ch,1		; shift winning mask
		dec	dl		; decrement line counter
		jnz	TestSymb2	; next line

; ------------- Pop registers

		pop	si		; pop SI
		mov	ch,dh		; CH <- winning mask
		pop	dx		; pop DX
		mov	dh,ch		; DH <- winning mask
		pop	cx		; pop CX
		pop	ax		; pop AX		
		ret

Doplněk do dat na konci programu:


TextHelp5:	db	13,10
		db	"WinTabs:",9,"dw",9,"WinTab1",13,10
		db	9,9,"dw",9,"WinTab2",13,10
		db	9,9,"dw",9,"WinTab3",13,10
		db	9,9,"dw",9,"WinTab4",13,10
		db	9,9,"dw",9,"WinTab5",13,10,0

TextWinTab:	db	13,10,"WinTab",0
TextRemark:	db	9,"; ",0
TextProfit:	db	"Profit ",0

Lines:
Line1:		dw	 0,  0,  0		; 1: middle line
Line2:		dw	 1,  1,  1		; 2: top line
Line3:		dw	-1, -1, -1		; 3: bottom line
Line4:		dw	 1,  0, -1		; 4: top diagonal
Line5:		dw	-1,  0,  1		; 5: bottom diagonal

WinTabRand:	dw	0			; total randomness of wins
WinTabTot:	dw	0			; total wins
WinTabProf:	dw	0			; game profit per mille
WinTabMul:	dw	8000			; multiplier for game profit
WinTabNum:	dw	0			; number of items
WinTab:		times 1000 db 0			; winning table
WinTab:		times 1000 db 0			; winning table

Výstupem programu je následující text:

SECTION         .text
ReelTab: db C,C,C,C,C,A,A,P,P,E,P,A,C,P,A,C,G,E,A,E,G,C,A,G,E,G,A,P,P,B,C,A
         db C,C,C,A,C,A,A,P,E,P,A,E,P,A,C,G,E,G,E,P,C,P,A,G,E,G,C,A,E,B,A,C
         db C,C,C,G,C,A,A,A,P,C,G,P,E,P,C,E,G,E,C,E,B,G,P,G,E,G,C,E,G,B,P,A
WinVal:         dw      10,20,50,100,200,750
WinTab1:        dw      0,      6,      1240,   0       ; Profit 0.00%
                dw      10,     8,      576,    1       ; 10
                dw      20,     9,      256,    1       ; 20
                dw      50,     10,     150,    1       ; 50
                dw      100,    11,     144,    1       ; 100
                dw      200,    12,     112,    1       ; 200
                dw      750,    13,     2,      1       ; 750

WinTab2:        dw      0,      13,     2396,   0       ; Profit 0.00%
                dw      10,     8,      1082,   1       ; 10
                dw      20,     9,      482,    1       ; 20
                dw      20,     16,     24,     1       ; 10x2
                dw      30,     584,    18,     1       ; 10 20
                dw      40,     17,     2,      1       ; 20x2
                dw      50,     10,     288,    1       ; 50
                dw      70,     649,    8,      1       ; 20 50
                dw      100,    11,     260,    1       ; 100
                dw      150,    714,    4,      1       ; 50 100
                dw      200,    12,     196,    1       ; 200
                dw      210,    776,    4,      1       ; 10 200
                dw      300,    779,    24,     1       ; 100 200
                dw      750,    13,     4,      1       ; 750

WinTab3:        dw      0,      29,     3505,   0       ; Profit 0.00%
                dw      10,     8,      1547,   1       ; 10
                dw      20,     9,      695,    1       ; 20
                dw      20,     16,     53,     1       ; 10x2
                dw      30,     24,     6,      1       ; 10x3
                dw      30,     584,    40,     1       ; 10 20
                dw      40,     17,     2,      1       ; 20x2
                dw      40,     592,    1,      1       ; 10x2 20
                dw      50,     10,     413,    1       ; 50
                dw      50,     1096,   1,      1       ; 10 20x2
                dw      60,     648,    1,      1       ; 10 50
                dw      70,     649,    20,     1       ; 20 50
                dw      80,     41544,  2,      1       ; 10 20 50
                dw      90,     657,    1,      1       ; 20x2 50
                dw      100,    11,     370,    1       ; 100
                dw      100,    18,     1,      1       ; 50x2
                dw      110,    712,    3,      1       ; 10 100
                dw      150,    714,    8,      1       ; 50 100
                dw      200,    12,     275,    1       ; 200
                dw      200,    19,     2,      1       ; 100x2
                dw      200,    722,    1,      1       ; 50x2 100
                dw      210,    776,    6,      1       ; 10 200
                dw      220,    777,    1,      1       ; 20 200
                dw      230,    49736,  1,      1       ; 10 20 200
                dw      250,    778,    1,      1       ; 50 200
                dw      300,    779,    43,     1       ; 100 200
                dw      310,    49864,  1,      1       ; 10 100 200
                dw      400,    20,     2,      1       ; 200x2
                dw      500,    1291,   2,      1       ; 100 200x2
                dw      750,    13,     6,      1       ; 750

WinTab4:        dw      0,      31,     4548,   0       ; Profit 0.00%
                dw      10,     8,      1809,   1       ; 10
                dw      20,     9,      906,    1       ; 20
                dw      20,     16,     165,    1       ; 10x2
                dw      30,     24,     28,     1       ; 10x3
                dw      30,     584,    40,     1       ; 10 20
                dw      40,     17,     23,     1       ; 20x2
                dw      40,     32,     6,      1       ; 10x4
                dw      40,     592,    1,      1       ; 10x2 20
                dw      50,     10,     563,    1       ; 50
                dw      50,     1096,   1,      1       ; 10 20x2
                dw      60,     25,     1,      1       ; 20x3
                dw      60,     648,    1,      1       ; 10 50
                dw      70,     649,    20,     1       ; 20 50
                dw      80,     41544,  2,      1       ; 10 20 50
                dw      90,     657,    1,      1       ; 20x2 50
                dw      100,    11,     514,    1       ; 100
                dw      100,    18,     1,      1       ; 50x2
                dw      110,    712,    3,      1       ; 10 100
                dw      150,    714,    8,      1       ; 50 100
                dw      200,    12,     387,    1       ; 200
                dw      200,    19,     2,      1       ; 100x2
                dw      200,    722,    1,      1       ; 50x2 100
                dw      210,    776,    6,      1       ; 10 200
                dw      220,    777,    1,      1       ; 20 200
                dw      230,    49736,  1,      1       ; 10 20 200
                dw      250,    778,    1,      1       ; 50 200
                dw      300,    779,    43,     1       ; 100 200
                dw      310,    49864,  1,      1       ; 10 100 200
                dw      400,    20,     2,      1       ; 200x2
                dw      500,    1291,   2,      1       ; 100 200x2
                dw      750,    13,     8,      1       ; 750

WinTab5:        dw      0,      32,     5546,   0       ; Profit 0.00%
                dw      10,     8,      2053,   1       ; 10
                dw      20,     9,      1117,   1       ; 20
                dw      20,     16,     269,    1       ; 10x2
                dw      30,     24,     46,     1       ; 10x3
                dw      30,     584,    40,     1       ; 10 20
                dw      40,     17,     44,     1       ; 20x2
                dw      40,     32,     16,     1       ; 10x4
                dw      40,     592,    1,      1       ; 10x2 20
                dw      50,     10,     703,    1       ; 50
                dw      50,     40,     6,      1       ; 10x5
                dw      50,     1096,   1,      1       ; 10 20x2
                dw      60,     25,     2,      1       ; 20x3
                dw      60,     648,    1,      1       ; 10 50
                dw      70,     649,    20,     1       ; 20 50
                dw      80,     41544,  2,      1       ; 10 20 50
                dw      90,     657,    1,      1       ; 20x2 50
                dw      100,    11,     634,    1       ; 100
                dw      100,    18,     6,      1       ; 50x2
                dw      110,    712,    3,      1       ; 10 100
                dw      150,    714,    8,      1       ; 50 100
                dw      200,    12,     483,    1       ; 200
                dw      200,    19,     14,     1       ; 100x2
                dw      200,    722,    1,      1       ; 50x2 100
                dw      210,    776,    6,      1       ; 10 200
                dw      220,    777,    1,      1       ; 20 200
                dw      230,    49736,  1,      1       ; 10 20 200
                dw      250,    778,    1,      1       ; 50 200
                dw      300,    779,    43,     1       ; 100 200
                dw      310,    49864,  1,      1       ; 10 100 200
                dw      400,    20,     10,     1       ; 200x2
                dw      500,    1291,   2,      1       ; 100 200x2
                dw      750,    13,     10,     1       ; 750

WinTabs:        dw      WinTab1
                dw      WinTab2
                dw      WinTab3
                dw      WinTab4
                dw      WinTab5

V této chvíli je možné provést doladění rozmístění a počtu symbolů na válcích - aby byla co nejvyšší pestrost typů výher. A také ověřit, zda některá výhra nepřesahuje povolenou hranici výše výhry.

Na začátku programu je uvedena definice struktury jednoho záznamu tabulky výher WinItem. Záznam se skládá ze 4 položek. První položkou je hodnota výhry příslušného výherního typu. Druhou položkou je typ výhry. Obsahuje seznam symbolů na výherních liniích spakovaný do 16-bitové položky. V seznamu je jeden výherní symbol zastoupen 3 bity, další 3 bity vyjadřují počet linií se stejným symbolem. Celkem mohou být v seznamu 3 typy symbolů. Třetí symbol může mít hodnoty pouze 0 nebo 1, protože při 3 různých symbolech se žádný symbol nemůže vyskytovat ve více liniích.

Hlavní funkce prochází všech 5 výherních linií automatu, tj. sázky 1, 2, 3, 4 a 5. Horní hru není třeba počítat, protože se odvozuje od sázky 5 vynásobením výhry 4x (protože skutečná sázka je 20, tj. 5 credit a 15 bank). Pro každou výherní linii je zavolána funkce CalcWinTab. Funkce prochází všechny možné kombinace pozic válců (vyjádřené 15 bitovým číslem, ve kterém je pozice každého válce zastoupena 5 bity), zjišťuje shodné symboly v jednotlivých liniích pomocí funkce TestSymbol, pro zjištěnou kombinaci symbolů vypočte výhru funkcí GetPrize a kombinaci typů symbolů pomocí funkce GetTypes. Prohledá tabulku výherních typů a buď započítá další výskyt daného typu nebo vytvoří nový typ výhry.

Funkce TestSymbol slouží ke zjištění, zda se v některých liniích vyskytují shodné symboly. Test provádí ve všech možných 5 liniích. Funkce prochází jednotlivé výherní linie, na každé linii nejdříve načte symboly na všech 3 válcích a poté porovná, zda se tyto symboly shodují. K adresaci symbolů na válcích využívá tabulku Lines, která obsahuje offsety jednotlivých pozic oproti středové linii. Jsou-li nalezeny shodné symboly na všech 3 pozicích, je nastaven příslušný bit v registru masky výherních linií.

Funkce GetPrize zjišťuje hodnotu výhry pro danou pozici válců. Využívá při tom výsledky funkce TestSymbol. Prochází jednotlivé výherní linie a vyskytuje-li se na linii výhra, započítá hodnotu výhry podle tabulky výherních kombinací.

Funkce GetTypes slouží ke spakování symbolů na výherních pozicích do 16-bitové položky výherního typu. Využívá při tom výsledky funkce TestSymbol. Prochází jednotlivé linie a narazí-li na linii s výhrou, inkrementuje 3-bitové počitadlo výskytu příslušného symbolu v 32-bitovém registru střadače počtů symbolů. Po zjištění symbolů na všech liniích prochází vytvořený seznam počtu symbolů, narazí-li na symbol s nenulovým výskytem, přidá symbol spolu s počtem výskytů do pakovaného střadače typů výher. Je přitom zajištěno, že výhry nižších symbolů se vyskytují na nižších pozicích střadače.

Po sestavení výherní tabulky je tabulka setříděna funkcí SortWinTab. Třídění probíhá poměrně pomalou nenáročnou metodou "bublinovým tříděním", ale v tomto případě není rychlost důležitá. Hlavním třídicím kritériem je hodnota výhry, vedlejším kritériem typ výhry.

Nakonec jsou tabulky výher zobrazeny funkcí PrintWinTab. Funkce prochází jednotlivé záznamy příslušné tabulky sázek. Nejdříve zobrazí první pomyslný záznam, který obsahuje informace: celkový počet záznamů v tabulce, celkový počet výher, celkovou náhodnost výher a v komentáři výhernost tabulky. Dále následují jednotlivé záznamy tabulky obsahující položky: hodnota výhry, typ výhry (jako běžné dekadické číslo), počet výher tohoto typu a náhodnost výhry. V komentáři se zobrazí jednotlivé složky výhry rozloženě (v pořadí od nižších výher, vícenásobné výhry jsou zobrazeny i s jejich násobky).

Přidejte do programu následující funkci a doplňte její volání do hlavní funkce za volání funkce SortWinTab (nebo můžete kód stáhnout jako předvariantu C).


; ----------------------------------------------------------------------------
;                     Calculate winning game profit
; ----------------------------------------------------------------------------
; INPUT:	DL = number of lines (1 to 5)
; ----------------------------------------------------------------------------

; ------------- Push registers

CalcWinProf:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	di		; push DI

; ------------- Prepare registers

		push	dx		; push number of lines

		mov	bx,WinTab	; BX <- winning table
		xor	si,si		; SI <- 0 accumulator LOW
		xor	di,di		; DI <- 0 accumulator HIGH
		mov	cx,[WinTabNum]	; CX <- number of winning table items

; ------------- Add value of one item

CalcWinProf2:	mov	ax,[bx+win_value] ; winning value
		shl	ax,1		; winning value * 2
		mul	word [bx+win_num] ; profit of this item
;		mul	word [bx+win_rand] ; profit of this item
		add	si,ax		; add accumulator LOW
		adc	di,dx		; add accumulator HIGH

; ------------- Next item

		add	bx,WINITEM_SIZE	; BX <- address of next item
		loop	CalcWinProf2	; next item

		pop	bx		; BL <- number of lines

; ------------- Calculate game profit per mille (10000 * win_sum / (bet * 65536))

		mov	ax,10000	; profit multiplier
		mul	si		; calculate profit per mille LOW
		xchg	dx,si		; SI <- multiple HIGH
		mov	ax,10000	; profit multiplier
		mul	di		; calculate profit per mille HIGH
		add	ax,si		; carry from LOW
		adc	dx,0		; carry
		mov	bh,0		; BX = number of lines
		mov	bl,[bx+BetTab-1]; BX <- bet
		div	bx		; divide with bet
		mov	[WinTabProf],ax	; game profit per mille

; ------------- Pop registers

		pop	di		; pop DI
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret
BetTab:		db	1,2,3,4,5

Zkrácený výstup programu:

WinTab1:        dw      0,      6,      1240,   0       ; Profit 172.97%
WinTab2:        dw      0,      13,     2396,   0       ; Profit 172.97%
WinTab3:        dw      0,      29,     3505,   0       ; Profit 172.97%
WinTab4:        dw      0,      31,     4548,   0       ; Profit 172.97%
WinTab5:        dw      0,      32,     5546,   0       ; Profit 172.97%

Funkce počítá výhernost tabulky. Výhernost je počítána z náhodností jednotlivých typů výher (tedy počet výher z celkového možného počtu 65536) vynásobenou hodnotou výhry a vydělenou celkovou hodnotou sázek pro celkový počet 65536 sázek. Na rozdíl od koncového tvaru funkce je funkce nyní upravena tak, aby používala položku počtu výher namísto pravděpodobnosti výhry (příkazy "shl ax,1" a "mul word [bx+win_num]"), jedná se o poměr celkové sumy výher k vložené sázce pro 32768 možných kombinací). Tím bude vypočítána skutečná výhernost automatu, nebude-li použita výherní tabulka. Vypočtenou výhernost je možné později ověřit sledováním statistiky úpravou programu automatu tak, že k vygenerování pozice bude použito náhodné číslo a budou zapnuty přepínače DEBUG a FAST.

Nyní budou postupně přidány funkce pro výpočet náhodnosti jednotlivých typů výher. Opravte zpět předešlou funkci na výpočet výhernosti (zrušte zmíněné 2 příkazy a odkomentuje příkaz s "win_rand") a doplňte následující funkci, jejíž volání uveďte před voláním funkce CalcWinProf (nebo můžete kód stáhnout jako předvariantu D).


; ----------------------------------------------------------------------------
;                         Calculate randomness
; ----------------------------------------------------------------------------
; INPUT:	DL = number of lines (1 to 5)
; ----------------------------------------------------------------------------

; ------------- Push registers

CalcWinRand:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX

; ------------- Prepare registers

		mov	word [WinTabRand],0 ; reset total randomness
		mov	bx,WinTab	; BX <- winning table
		mov	cx,[WinTabNum]	; CX <- number of winning table items

; ------------- Calculate one value

CalcWinRand2:	mov	ax,[WinTabMul]	; AX <- multiplier for game profit
		xor	dx,dx		; DX <- 0
		div     word [bx+win_value] ; / winning value
		mov	dx,[bx+win_num]	; number of wins
		shr	dx,1		; number of wins / 2
		shr	dx,1		; number of wins / 4
		add	ax,dx		; AX += additional correction
		mov	[bx+win_rand],ax ; randomness of this win
		add	[WinTabRand],ax	; add to total randomness
		add	bx,WINITEM_SIZE	; BX <- next winning item
		loop	CalcWinRand2	; calculate next item

; ------------- Pop registers

		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

Zkrácený výstup programu:

WinTab1:        dw      0,      6,      1240,   1799    ; Profit 93.49%
WinTab2:        dw      0,      13,     2396,   3184    ; Profit 100.31%
WinTab3:        dw      0,      29,     3505,   4794    ; Profit 137.81%
WinTab4:        dw      0,      31,     4548,   5388    ; Profit 114.98%
WinTab5:        dw      0,      32,     5546,   5797    ; Profit 98.63%

Funkce počítá pravděpodobnosti jednotlivých typů výher v závislosti na proměnné WinTabMul, což je pomocný násobící koeficient. Pravděpodobnost výhry každého typu je přímo úměrná tomuto koeficientu, nepřímo úměrná hodnotě výhry a se sníženou závislostí též úměrná počtu výher. Jak je patrno z výstupu programu, došlo k srovnání pravděpodobností výskytu výherních kombinací oproti zvela náhodnému generování, při kterém by docházelo příliš často k výskytu podobných a tudíž málo zajímavých kombinací symbolů.

Dále bude provedena první korekce výhernosti. Doplňte do hlavní funkce, za volání funkce CalcWinProf, následující kód (nebo můžete kód stáhnout jako předvariantu E).


PROFIT		equ	9400		; profit of game * 100

; ------------- First correction of game profit - direct proportion

		push	dx		; push DX (winning lines)
		mov	ax,PROFIT	; required profit
		mul	word [WinTabMul] ; profit * multiplier
		div	word [WinTabProf] ; / current profit
		mov	[WinTabMul],ax	; new multiplier
		pop	dx		; pop DX (winning lines)

; ------------- Second correction of game profit - loop correction

		mov	cx,1000		; CX <- number of iterations
Start3:		call	CalcWinRand	; calculate game randomness
		call	CalcWinProf	; calculate game profit

Zkrácený výstup programu:

WinTab1:        dw      0,      6,      1240,   1805    ; Profit 93.61%
WinTab2:        dw      0,      13,     2396,   3028    ; Profit 95.83%
WinTab3:        dw      0,      29,     3505,   3518    ; Profit 99.49%
WinTab4:        dw      0,      31,     4548,   4334    ; Profit 91.85%
WinTab5:        dw      0,      32,     5546,   5307    ; Profit 89.84%

Kód zajistí opravu násobícího koeficientu podle rozdílu požadované výhernosti (konstanta PROFIT) a skutečné výhernosti. Jak je patrné, přesnost výhernosti se již více přiblížila požadované výhernosti.

Pokračujte dále doplněním dalšího kódu (nebo můžete kód stáhnout jako předvariantu F).


		mov	ax,PROFIT	; AX <- required profit
		cmp	ax,[WinTabProf]	; is profit correct?
		je	Start7		; profit matches
		mov	ax,1		; correction up
		jg	Start4		; do correction up
		neg	ax		; else correction down
Start4:		add	[WinTabMul],ax	; correction of multiplier
		loop	Start3		; try next calculation

Zkrácený výstup programu:

WinTab1:        dw      0,      6,      1240,   1817    ; Profit 94.10%
WinTab2:        dw      0,      13,     2396,   2982    ; Profit 93.86%
WinTab3:        dw      0,      29,     3505,   3345    ; Profit 94.24%
WinTab4:        dw      0,      31,     4548,   4447    ; Profit 94.00%
WinTab5:        dw      0,      32,     5546,   5539    ; Profit 94.03%

Kód pomocí iterace postupně upřesňuje násobící koeficient tak, aby se výhernost co nejvíce přiblížila požadované výhernosti. Je vidět, že chybovost výhernosti činí teď již jen kolem 0.5%. Projevuje se zde nepřesnost vyjádření pravděpodobností pomocí celých čísel, výhernost proto nelze již tímto způsobem více upřesnit.

Poslední úprava spočívá v doplnění následující koncové iterace (nebo můžete kód stáhnout jako koncovou variantu).


; ------------- Third correction of game profit - correction of first win

		mov	cx,[WinTab+win_rand] ; randomness of first win
		shr	cx,1		; CX = number of iterations
		jcxz	Start7		; what?
Start5:		mov	ax,PROFIT	; AX <- required profit
		cmp	ax,[WinTabProf]	; is profit correct?
		je	Start7		; profit matches
		mov	ax,1		; correction up
		jg	Start6		; do correction up
		neg	ax		; else correction down
Start6:		add	[WinTab+win_rand],ax ; correction of first win
		add	[WinTabRand],ax	; correction of total randomness
		call	CalcWinProf	; calculate game profit
		loop	Start5		; try next calculation

Koncový výstup programu:

Don't edit this file, it is generated by program.

SECTION         .text

; ------------- Symbols on reels
; C=cherry, A=apple, P=plum, E=pear, G=grape, B=bell

ReelTab: db C,C,C,C,C,A,A,P,P,E,P,A,C,P,A,C,G,E,A,E,G,C,A,G,E,G,A,P,P,B,C,A
         db C,C,C,A,C,A,A,P,E,P,A,E,P,A,C,G,E,G,E,P,C,P,A,G,E,G,C,A,E,B,A,C
         db C,C,C,G,C,A,A,A,P,C,G,P,E,P,C,E,G,E,C,E,B,G,P,G,E,G,C,E,G,B,P,A

; ------------- Winning values (3 equal symbols)

WinVal:         dw      10,20,50,100,200,750

; ------------- Winning tables
; Head of one table: zero win, items in table, total wins, total randomness
; One item of table: win value, types, wins, randomness

WinTab1:        dw      0,      6,      1240,   1811    ; Profit 94.00%
                dw      10,     8,      576,    948     ; 10
                dw      20,     9,      256,    469     ; 20
                dw      50,     10,     150,    199     ; 50
                dw      100,    11,     144,    117     ; 100
                dw      200,    12,     112,    68      ; 200
                dw      750,    13,     2,      10      ; 750

WinTab2:        dw      0,      13,     2396,   3000    ; Profit 94.00%
                dw      10,     8,      1082,   1027    ; 10
                dw      20,     9,      482,    489     ; 20
                dw      20,     16,     24,     375     ; 10x2
                dw      30,     584,    18,     250     ; 10 20
                dw      40,     17,     2,      184     ; 20x2
                dw      50,     10,     288,    219     ; 50
                dw      70,     649,    8,      107     ; 20 50
                dw      100,    11,     260,    138     ; 100
                dw      150,    714,    4,      50      ; 50 100
                dw      200,    12,     196,    85      ; 200
                dw      210,    776,    4,      36      ; 10 200
                dw      300,    779,    24,     30      ; 100 200
                dw      750,    13,     4,      10      ; 750

WinTab3:        dw      0,      29,     3505,   3298    ; Profit 94.00%
                dw      10,     8,      1547,   845     ; 10
                dw      20,     9,      695,    426     ; 20
                dw      20,     16,     53,     266     ; 10x2
                dw      30,     24,     6,      169     ; 10x3
                dw      30,     584,    40,     178     ; 10 20
                dw      40,     17,     2,      126     ; 20x2
                dw      40,     592,    1,      126     ; 10x2 20
                dw      50,     10,     413,    204     ; 50
                dw      50,     1096,   1,      101     ; 10 20x2
                dw      60,     648,    1,      84      ; 10 50
                dw      70,     649,    20,     77      ; 20 50
                dw      80,     41544,  2,      63      ; 10 20 50
                dw      90,     657,    1,      56      ; 20x2 50
                dw      100,    11,     370,    142     ; 100
                dw      100,    18,     1,      50      ; 50x2
                dw      110,    712,    3,      46      ; 10 100
                dw      150,    714,    8,      35      ; 50 100
                dw      200,    12,     275,    93      ; 200
                dw      200,    19,     2,      25      ; 100x2
                dw      200,    722,    1,      25      ; 50x2 100
                dw      210,    776,    6,      25      ; 10 200
                dw      220,    777,    1,      23      ; 20 200
                dw      230,    49736,  1,      22      ; 10 20 200
                dw      250,    778,    1,      20      ; 50 200
                dw      300,    779,    43,     26      ; 100 200
                dw      310,    49864,  1,      16      ; 10 100 200
                dw      400,    20,     2,      12      ; 200x2
                dw      500,    1291,   2,      10      ; 100 200x2
                dw      750,    13,     6,      7       ; 750

WinTab4:        dw      0,      31,     4548,   4447    ; Profit 94.00%
                dw      10,     8,      1809,   1076    ; 10
                dw      20,     9,      906,    538     ; 20
                dw      20,     16,     165,    353     ; 10x2
                dw      30,     24,     28,     215     ; 10x3
                dw      30,     584,    40,     218     ; 10 20
                dw      40,     17,     23,     161     ; 20x2
                dw      40,     32,     6,      157     ; 10x4
                dw      40,     592,    1,      156     ; 10x2 20
                dw      50,     10,     563,    264     ; 50
                dw      50,     1096,   1,      124     ; 10 20x2
                dw      60,     25,     1,      104     ; 20x3
                dw      60,     648,    1,      104     ; 10 50
                dw      70,     649,    20,     94      ; 20 50
                dw      80,     41544,  2,      78      ; 10 20 50
                dw      90,     657,    1,      69      ; 20x2 50
                dw      100,    11,     514,    190     ; 100
                dw      100,    18,     1,      62      ; 50x2
                dw      110,    712,    3,      56      ; 10 100
                dw      150,    714,    8,      43      ; 50 100
                dw      200,    12,     387,    127     ; 200
                dw      200,    19,     2,      31      ; 100x2
                dw      200,    722,    1,      31      ; 50x2 100
                dw      210,    776,    6,      30      ; 10 200
                dw      220,    777,    1,      28      ; 20 200
                dw      230,    49736,  1,      27      ; 10 20 200
                dw      250,    778,    1,      24      ; 50 200
                dw      300,    779,    43,     30      ; 100 200
                dw      310,    49864,  1,      20      ; 10 100 200
                dw      400,    20,     2,      15      ; 200x2
                dw      500,    1291,   2,      12      ; 100 200x2
                dw      750,    13,     8,      10      ; 750

WinTab5:        dw      0,      32,     5546,   5531    ; Profit 94.00%
                dw      10,     8,      2053,   1260    ; 10
                dw      20,     9,      1117,   656     ; 20
                dw      20,     16,     269,    444     ; 10x2
                dw      30,     24,     46,     262     ; 10x3
                dw      30,     584,    40,     261     ; 10 20
                dw      40,     17,     44,     199     ; 20x2
                dw      40,     32,     16,     192     ; 10x4
                dw      40,     592,    1,      188     ; 10x2 20
                dw      50,     10,     703,    326     ; 50
                dw      50,     40,     6,      152     ; 10x5
                dw      50,     1096,   1,      151     ; 10 20x2
                dw      60,     25,     2,      125     ; 20x3
                dw      60,     648,    1,      125     ; 10 50
                dw      70,     649,    20,     112     ; 20 50
                dw      80,     41544,  2,      94      ; 10 20 50
                dw      90,     657,    1,      83      ; 20x2 50
                dw      100,    11,     634,    233     ; 100
                dw      100,    18,     6,      76      ; 50x2
                dw      110,    712,    3,      68      ; 10 100
                dw      150,    714,    8,      52      ; 50 100
                dw      200,    12,     483,    157     ; 200
                dw      200,    19,     14,     40      ; 100x2
                dw      200,    722,    1,      37      ; 50x2 100
                dw      210,    776,    6,      36      ; 10 200
                dw      220,    777,    1,      34      ; 20 200
                dw      230,    49736,  1,      32      ; 10 20 200
                dw      250,    778,    1,      30      ; 50 200
                dw      300,    779,    43,     35      ; 100 200
                dw      310,    49864,  1,      24      ; 10 100 200
                dw      400,    20,     10,     20      ; 200x2
                dw      500,    1291,   2,      15      ; 100 200x2
                dw      750,    13,     10,     12      ; 750

; ------------- List of winning tables

WinTabs:        dw      WinTab1
                dw      WinTab2
                dw      WinTab3
                dw      WinTab4
                dw      WinTab5

Tato poslední upřesňující iterace provádí jemné dokorigování výhernosti modifikací výhernosti prvního (nejpočetnějšího) výherního typu. Dosažená přesnost je 0.02%.

Download zdrojových textů výpočtu tabulky výher.

Zpět na aplikaci VEGASLOT