Giter Site home page Giter Site logo

tempai-core's Introduction

About

CI Coverage Status Go Report Card

This is riichi mahjong Golang package. Package supports calculation for:

  1. Shanten value
  2. Effectivity drops
  3. Tempai
  4. Hand yaku
  5. Han/Fu hand value based on yaku
  6. Scroing base on han/fu value

The game itself is NOT the purpose of this particular package.

This package is extracted from a larger repo(private) of my code and it is been quite tested. I've found a good number of corner-cases to include in my tests. You can see the example of effetivity calculator, based on this package here: https://tempai.net/en/eff .

I've also validated my code against more than 1 million tenhou Phoenix replays, downloaded from tenhou.net server. So it seems that the results of calculation could be trusted.

Installation

go get github.com/dnovikoff/tempai-core/...

Quick Start by exmaples

All examples could be found in example folder. Note that provided examples are simple and do not cover all possible package functionality. You can also explore *_test.go test files to search for more usage examples.

All example hand inputs provided in tenhou-style string format:

  1. 123456789s for Sou
  2. 123456789m for Man
  3. 123456789p for Pin
  4. 1234z for East, South, West, North
  5. 567z for White, Green, Red

Calculate shanten number

Shanten, Tempai and effectivity calculators support different forms separatly or all-together:

  1. Regular hand
  2. Seven pairs
  3. Kokushi

You can also take into considiration any number of visible tiles to affect results. Calculating hands with opened melds is also supported.

examples/shanten/shanten_test.go

generator := compact.NewTileGenerator()
tiles, _ := generator.CompactFromString("3567m5677p268s77z")
res := shanten.Calculate(tiles)
fmt.Printf("Hand is %s\n", tiles.Instances())

fmt.Printf("Regular shanten value is: %v\n", res.Regular.Value)
fmt.Printf("Pairs shanten value is: %v\n", res.Pairs.Value)
fmt.Printf("Kokushi shanten value is: %v\n", res.Kokushi.Value)
fmt.Printf("Total shanten value is: %v\n", res.Total.Value)

uke := res.Total.CalculateUkeIre(compact.NewTotals().Merge(tiles))
fmt.Printf("Total uke ire: %v/%v\n", uke.UniqueCount(), uke.Count())
fmt.Printf("Hand improves: %s\n", res.Total.Improves.Tiles())

Output:

Hand is 3567m5677p268s77z
Regular shanten value is: 2
Pairs shanten value is: 4
Kokushi shanten value is: 11
Total shanten value is: 2
Total uke ire: 18/63
Hand improves: 123458m456789p12347s7z

Calculate tempai

Tempai results could be transformed into yaku results -> han/fu value -> score values

examples/tempai/tempai_test.go

generator := compact.NewTileGenerator()
tiles, _ := generator.CompactFromString("789m4466678p234s")
results := tempai.Calculate(tiles)
fmt.Printf("Hand is %s\n", tiles.Instances())
fmt.Printf("Waits are %s\n", results.Waits().Tiles())

Output:

Hand is 789m4466678p234s
Waits are 469p

Calculate tile effectivity

Calculating Uke-Ure value for hand.

examples/effective/effective_test.go

generator := compact.NewTileGenerator()
tiles, _ := generator.CompactFromString("5677m4456899p25s3z")
results := effective.Calculate(tiles)
fmt.Printf("Hand is %s\n", tiles.Instances())
best := results.Sorted(tiles).Best()
fmt.Printf("Best to drop is %v\n", best.Tile)
fmt.Printf("Best shanten: %v\n", best.Shanten.Total.Value)

Output:

Hand is 5677m4456899p25s3z
Best to drop is 3z
Best shanten: 3

Calculate han+fu value

Package supports configuration of different rulesets. Configuration options includes:

  1. Mangan round (4.30/3.60 could be rounded to mangan)
  2. Yakuman summ option
  3. Double yakuman option
  4. Kazoe Yakuman/Sanbaiman
  5. Changing hoba value

Included rulesets for: EMA, JPML-A, JPLML-B, Tenhou. You can also configure your own ruleset

examples/score/score_test.go

s := score.GetScore(score.RulesEMA(), 4, 22, 0)
fmt.Printf("Hand value is %v.%v (%v)\n", s.Han, s.Fu, s.Fu.Round())
fmt.Printf("Dealer ron: %v\n", s.PayRonDealer)
fmt.Printf("Dealer tsumo: %v all\n", s.PayTsumoDealer)
fmt.Printf("Ron: %v\n", s.PayRon)
fmt.Printf("Tsumo: %v/%v\n", s.PayTsumoDealer, s.PayTsumo)
changes := s.GetChanges(base.WindEast, base.WindEast, 0)
fmt.Printf("Total for dealer tsumo is %v\n", changes.TotalWin())

Output:

Hand value is 4.22 (30)
Dealer ron: 11600
Dealer tsumo: 3900 all
Ron: 7700
Tsumo: 3900/2000
Total for dealer tsumo is 11700

Calculate yaku for hand

Package supports configuration of different rulesets. Configuration options includes:

  1. Setting any number of akkadors (not limited by red fives)
  2. Renhou could be configured as yakuman or mangan
  3. Uradoras could be disabled (for JPML-A)
  4. Ipatsu could be disabled (for JPML-A)
  5. Haitei could be combined with Rinshan
  6. Enabling/Disabling open Tanyao

Included rulesets for: EMA, JPML-A, JPLML-B, Tenhou with red fives. You can also configure your own ruleset

examples/yaku/yaku_test.go

generator := compact.NewTileGenerator()
tiles, _ := generator.CompactFromString("33z123m456p66778s")
winTile := generator.Instance(tile.Sou5)

results := tempai.Calculate(tiles).Index()
ctx := &yaku.Context{
    Tile:      winTile,
    Rules:     yaku.RulesEMA(),
    IsTsumo:   true,
    IsChankan: true,
}
yakuResult := yaku.Win(results, ctx, nil)
fmt.Printf("%v\n", yakuResult.Yaku.String())
fmt.Printf("Value: %v.%v\n", yakuResult.Sum(), yakuResult.Fus.Sum())

Output:

YakuChankan: 1, YakuPinfu: 1, YakuTsumo: 1
Value: 3.20

Perfomance

There is an examples/performance folder with some mesaurement program. I've already made some code improvements, based on profiling for simular test code. Although there could be more space for improve, the results on my machine seems quite fine to start with.

go run ./examples/performance/main.go

Output:

================== Test shanten
Repeat: 10000
Elapsed: 255.822276ms
Estemated speed: 39089.637369968514 per second
================== Test tempai
Repeat: 10000
Elapsed: 122.52142ms
Estemated speed: 81618.38150423003 per second
Tempai hand count: 4826
================== Test effectivity
Repeat: 1000
Elapsed: 255.058354ms
Estemated speed: 3920.6714240773313 per second

tempai-core's People

Contributors

dnovikoff avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

tempai-core's Issues

Issue with Riichi Mahjong Points Calculation

I am using this package for calculating Riichi mahjong points. I've noticed an inconsistency when handling special hands, particularly with YakumanTenhou and YakumanKokushi13.

Problem Description:

When setting ctx.IsFirstTake = true and providing a Kokushi13 tile set, both YakumanTenhou and YakumanKokushi13 should be valid simultaneously. However, only YakumanKokushi13 gets registered.

The root cause appears to be in the func (c *calculator) run() *Result method. If c.tryKokushi() returns true, the function immediately proceeds to c.calculateResult(), bypassing the c.tryTsumo() method where YakumanTenhou is determined and added.

Expected Behavior:

Both YakumanTenhou and YakumanKokushi13 should be recognized and calculated correctly when the conditions are met.

Suggested Solution:

Adjust the function's control flow to ensure that c.tryTsumo() is called even when c.tryKokushi() returns true.

Can it correctly calculate the shanten for less than 13 tiles case?

thank you for this go package. I have two problems with it.

  1. how can I get the right shanten value for less than 13 tiles case? the same case in tempai.net is right, "11223m55p1z" best drop is 1z, shanten value is 0, but use these package, it got 5, all less than 13 tiles case will get the wrong answer.
  2. I found that when tenhon and tempai.net calculate the effective, If there is 3n+1 tiles in hand, it will be completed to 3n+2, but effective.Calculate() won't do that, it will get a wrong answer with 3n+1 tiles. Does anyone need the effective with 3n+1 tiles? if I want to completed the 3n+2nd tile, what rule should I use ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.