-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b464f70
commit c5796c1
Showing
10 changed files
with
354 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
//go:build !prod || full || novomatic | ||
|
||
package links | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/slotopol/server/game/jewels4all" | ||
"github.com/spf13/pflag" | ||
) | ||
|
||
func init() { | ||
FlagsSetters = append(FlagsSetters, func(flags *pflag.FlagSet) { | ||
flags.Bool("jewels4all", false, "'Jewels 4 All' Novomatic 5x3 slots") | ||
}) | ||
ScatIters = append(ScatIters, func(flags *pflag.FlagSet, ctx context.Context) { | ||
if is, _ := flags.GetBool("jewels4all"); is { | ||
var rn, _ = flags.GetString("reels") | ||
jewels4all.CalcStat(ctx, rn) | ||
} | ||
}) | ||
|
||
for _, alias := range []string{ | ||
"jewels4all", | ||
} { | ||
GameAliases[alias] = "jewels4all" | ||
} | ||
|
||
GameFactory["jewels4all"] = func(rd string) any { | ||
if _, ok := jewels4all.ChanceMap[rd]; ok { | ||
return jewels4all.NewGame(rd) | ||
} | ||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package jewels4all | ||
|
||
import "github.com/slotopol/server/game" | ||
|
||
// RTP(no eu) = 67.344781% | ||
// RTP(eu at y=1,5) = 1706.345577% | ||
// RTP(eu at y=2,3,4) = 7818.930041% | ||
// euro avr: rtpeu = 5373.896256% | ||
var Reels = game.Reels5x{ | ||
{1, 1, 1, 2, 2, 2, 6, 6, 3, 3, 3, 7, 7, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7}, | ||
{1, 1, 1, 2, 2, 2, 6, 6, 3, 3, 3, 7, 7, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7}, | ||
{1, 1, 1, 2, 2, 2, 6, 6, 3, 3, 3, 7, 7, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7}, | ||
{1, 1, 1, 2, 2, 2, 6, 6, 3, 3, 3, 7, 7, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7}, | ||
{1, 1, 1, 2, 2, 2, 6, 6, 3, 3, 3, 7, 7, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7}, | ||
} | ||
|
||
// Map with wild chances. | ||
var ChanceMap = map[string]float64{ | ||
// RTP = 67.345(sym) + wc*5373.9(eu) = 90.019449% | ||
"90": 1 / 237., | ||
// RTP = 67.345(sym) + wc*5373.9(eu) = 91.995681% | ||
"92": 1 / 218., | ||
// RTP = 67.345(sym) + wc*5373.9(eu) = 93.948228% | ||
"94": 1 / 202., | ||
// RTP = 67.345(sym) + wc*5373.9(eu) = 96.082194% | ||
"96": 1 / 187., | ||
// RTP = 67.345(sym) + wc*5373.9(eu) = 98.052760% | ||
"98": 1 / 175., | ||
// RTP = 67.345(sym) + wc*5373.9(eu) = 99.913849% | ||
"100": 1 / 165., | ||
// RTP = 67.345(sym) + wc*5373.9(eu) = 110.335951% | ||
"110": 1 / 125., | ||
} | ||
|
||
// Lined payment. | ||
var LinePay = [8][5]float64{ | ||
{0, 0, 20, 100, 1000}, // 1 crown | ||
{0, 0, 10, 60, 500}, // 2 gold | ||
{0, 0, 10, 60, 500}, // 3 money | ||
{0, 0, 5, 40, 200}, // 4 ruby | ||
{0, 0, 5, 40, 200}, // 5 sapphire | ||
{0, 0, 5, 20, 100}, // 6 emerald | ||
{0, 0, 5, 20, 100}, // 7 amethyst | ||
{0, 0, 0, 0, 0}, // 8 euro | ||
} | ||
|
||
const ( | ||
jid = 1 // jackpot ID | ||
) | ||
|
||
// Jackpot win combinations. | ||
var Jackpot = [8][5]int{ | ||
{0, 0, 0, 0, 0}, // 1 crown | ||
{0, 0, 0, 0, 0}, // 2 gold | ||
{0, 0, 0, 0, 0}, // 3 money | ||
{0, 0, 0, 0, 0}, // 4 ruby | ||
{0, 0, 0, 0, 0}, // 5 sapphire | ||
{0, 0, 0, 0, 0}, // 6 emerald | ||
{0, 0, 0, 0, 0}, // 7 amethyst | ||
{0, 0, 0, 0, 0}, // 8 euro | ||
} | ||
|
||
type Game struct { | ||
game.Slot5x3 `yaml:",inline"` | ||
} | ||
|
||
func NewGame(rd string) *Game { | ||
return &Game{ | ||
Slot5x3: game.Slot5x3{ | ||
RD: rd, | ||
SBL: game.MakeSblNum(5), | ||
Bet: 1, | ||
}, | ||
} | ||
} | ||
|
||
const wild = 8 | ||
|
||
var bl = game.BetLinesNvm10 | ||
|
||
func (g *Game) Scanner(screen game.Screen, ws *game.WinScan) { | ||
g.ScanLined(screen, ws) | ||
} | ||
|
||
// Lined symbols calculation. | ||
func (g *Game) ScanLined(screen game.Screen, ws *game.WinScan) { | ||
var scrnwild game.Screen5x3 = *screen.(*game.Screen5x3) | ||
for x := 1; x <= 5; x++ { | ||
for y := 1; y <= 3; y++ { | ||
if screen.At(x, y) == wild { | ||
for i := max(0, x-2); i <= min(4, x); i++ { | ||
for j := max(0, y-2); j <= min(2, y); j++ { | ||
scrnwild[i][j] = wild | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
for li := g.SBL.Next(0); li != 0; li = g.SBL.Next(li) { | ||
var line = bl.Line(li) | ||
|
||
var sym3 = scrnwild.Pos(3, line) | ||
var xy = game.NewLine5x() | ||
var num = 1 | ||
xy.Set(3, line.At(3)) | ||
if sym2 := scrnwild.Pos(2, line); sym2 == sym3 || sym2 == wild || sym3 == wild { | ||
if sym3 == wild { | ||
sym3 = sym2 | ||
} | ||
xy.Set(2, line.At(2)) | ||
num++ | ||
if sym1 := scrnwild.Pos(1, line); sym1 == sym3 || sym1 == wild || sym3 == wild { | ||
if sym3 == wild { | ||
sym3 = sym1 | ||
} | ||
xy.Set(1, line.At(1)) | ||
num++ | ||
} | ||
} | ||
if sym4 := scrnwild.Pos(4, line); sym4 == sym3 || sym4 == wild || sym3 == wild { | ||
if sym3 == wild { | ||
sym3 = sym4 | ||
} | ||
xy.Set(4, line.At(4)) | ||
num++ | ||
if sym5 := scrnwild.Pos(5, line); sym5 == sym3 || sym5 == wild || sym3 == wild { | ||
if sym3 == wild { | ||
sym3 = sym5 | ||
} | ||
xy.Set(5, line.At(5)) | ||
num++ | ||
} | ||
} | ||
|
||
if num >= 3 { | ||
ws.Wins = append(ws.Wins, game.WinItem{ | ||
Pay: g.Bet * LinePay[sym3-1][num-1], | ||
Mult: 1, | ||
Sym: sym3, | ||
Num: num, | ||
Line: li, | ||
XY: xy, | ||
}) | ||
} else { | ||
xy.Free() | ||
} | ||
} | ||
} | ||
|
||
func (g *Game) Spin(screen game.Screen) { | ||
screen.Spin(&Reels) | ||
} | ||
|
||
func (g *Game) SetLines(sbl game.SBL) error { | ||
var mask game.SBL = (1<<len(bl) - 1) << 1 | ||
if sbl == 0 { | ||
return game.ErrNoLineset | ||
} | ||
if sbl&^mask != 0 { | ||
return game.ErrLinesetOut | ||
} | ||
if g.FreeSpins() > 0 { | ||
return game.ErrNoFeature | ||
} | ||
g.SBL = sbl | ||
return nil | ||
} | ||
|
||
func (g *Game) SetReels(rd string) error { | ||
if _, ok := ChanceMap[rd]; !ok { | ||
return game.ErrNoReels | ||
} | ||
g.RD = rd | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package jewels4all | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/slotopol/server/game" | ||
) | ||
|
||
func BruteForce5x(ctx context.Context, s game.Stater, g game.SlotGame, reels game.Reels, x, y int) { | ||
var screen = g.NewScreen() | ||
defer screen.Free() | ||
var ws game.WinScan | ||
var r1 = reels.Reel(1) | ||
var r2 = reels.Reel(2) | ||
var r3 = reels.Reel(3) | ||
var r4 = reels.Reel(4) | ||
var r5 = reels.Reel(5) | ||
for i1 := range r1 { | ||
screen.SetCol(1, r1, i1) | ||
for i2 := range r2 { | ||
screen.SetCol(2, r2, i2) | ||
for i3 := range r3 { | ||
screen.SetCol(3, r3, i3) | ||
for i4 := range r4 { | ||
screen.SetCol(4, r4, i4) | ||
for i5 := range r5 { | ||
screen.SetCol(5, r5, i5) | ||
var sym game.Sym | ||
if x > 0 { | ||
sym = screen.At(x, y) | ||
screen.Set(x, y, wild) | ||
} | ||
g.Scanner(screen, &ws) | ||
if x > 0 { | ||
screen.Set(x, y, sym) | ||
} | ||
s.Update(&ws) | ||
ws.Reset() | ||
if s.Count()&100 == 0 { | ||
select { | ||
case <-ctx.Done(): | ||
return | ||
default: | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
func CalcStatEuro(ctx context.Context, x, y int) float64 { | ||
var reels = &Reels | ||
var g = NewGame("92") | ||
g.SBL = game.MakeSblNum(1) | ||
var sbl = float64(g.SBL.Num()) | ||
var s game.Stat | ||
|
||
fmt.Printf("calculations of euro at [%d,%d]\n", x, y) | ||
|
||
var total = float64(reels.Reshuffles()) | ||
var dur = func() time.Duration { | ||
var t0 = time.Now() | ||
var ctx2, cancel2 = context.WithCancel(ctx) | ||
defer cancel2() | ||
go s.Progress(ctx2, time.NewTicker(2*time.Second), sbl, total) | ||
BruteForce5x(ctx2, &s, g, reels, x, y) | ||
return time.Since(t0) | ||
}() | ||
|
||
var reshuf = float64(s.Reshuffles) | ||
var lrtp = s.LinePay / reshuf / sbl * 100 | ||
_ = jid | ||
fmt.Printf("completed %.5g%%, selected %d lines, time spent %v\n", reshuf/total*100, g.SBL.Num(), dur) | ||
fmt.Printf("reels lengths [%d, %d, %d, %d, %d], total reshuffles %d\n", | ||
len(reels.Reel(1)), len(reels.Reel(2)), len(reels.Reel(3)), len(reels.Reel(4)), len(reels.Reel(5)), reels.Reshuffles()) | ||
fmt.Printf("RTP[%d,%d] = %.6f%%\n", x, y, lrtp) | ||
return lrtp | ||
} | ||
|
||
func CalcStat(ctx context.Context, rn string) (rtp float64) { | ||
var wc float64 | ||
if rn != "" { | ||
var ok bool | ||
if wc, ok = ChanceMap[rn]; !ok { | ||
return 0 | ||
} | ||
} else { | ||
wc, rn = ChanceMap["95"], "95" | ||
} | ||
|
||
var b = 1 / wc | ||
fmt.Printf("wild chance %.5g, b = %.5g\n", wc, b) | ||
var rtp00 = CalcStatEuro(ctx, 0, 0) | ||
var rtpeu float64 | ||
for x := 1; x <= 5; x++ { | ||
for y := 1; y <= 3; y++ { | ||
rtpeu += CalcStatEuro(ctx, x, y) | ||
} | ||
} | ||
rtpeu /= 15 | ||
rtp = rtp00 + wc*rtpeu | ||
fmt.Printf("euro avr: rtpeu = %.6f%%\n", rtpeu) | ||
fmt.Printf("RTP = %.5g(sym) + wc*%.5g(eu) = %.6f%%\n", rtp00, rtpeu, rtp) | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.