Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

改變一些文字的開頭大寫使其類似物件導向語言的public,並且優化main.go部分程式碼顯示。 #164

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// 使用 IntelliSense 以得知可用的屬性。
// 暫留以檢視現有屬性的描述。
// 如需詳細資訊,請瀏覽: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"console": "integratedTerminal"
}
]
}
6 changes: 3 additions & 3 deletions console.go → Console/console.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package main
package Console

import (
"os/exec"
"os"
"os/exec"
"runtime"
)

Expand All @@ -23,7 +23,7 @@ func init() {
}
}

func clearConsole() {
func ClearScreen() {
if clearFunc, ok := clearFuncMap[runtime.GOOS]; ok {
clearFunc()
}
Expand Down
80 changes: 80 additions & 0 deletions IDataParser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package main

import "github.com/EndlessCheng/mahjong-helper/util/model"

type DataParser interface {
// 数据来源(是天凤还是雀魂)
GetDataSourceType() int

// 获取自家初始座位:0-第一局的东家 1-第一局的南家 2-第一局的西家 3-第一局的北家
// 仅处理雀魂数据,天凤返回 -1
GetSelfSeat() int

// 原始 JSON
GetMessage() string

// 解析前,根据消息内容来决定是否要进行后续解析
SkipMessage() bool

// 尝试解析用户名
IsLogin() bool
HandleLogin()

// round 开始/重连
// roundNumber: 场数(如东1为0,东2为1,...,南1为4,...,南4为7,...),对于三麻来说南1也是4
// benNumber: 本场数
// dealer: 庄家 0-3
// doraIndicators: 宝牌指示牌
// handTiles: 手牌
// numRedFives: 按照 mps 的顺序,赤5个数
IsInit() bool
ParseInit() (roundNumber int, benNumber int, dealer int, doraIndicators []int, handTiles []int, numRedFives []int)

// 自家摸牌
// tile: 0-33
// isRedFive: 是否为赤5
// kanDoraIndicator: 摸牌时,若为暗杠摸的岭上牌,则可以翻出杠宝牌指示牌,否则返回 -1(目前恒为 -1,见 IsNewDora)
IsSelfDraw() bool
ParseSelfDraw() (tile int, isRedFive bool, kanDoraIndicator int)

// 舍牌
// who: 0=自家, 1=下家, 2=对家, 3=上家
// isTsumogiri: 是否为摸切(who=0 时忽略该值)
// isReach: 是否为立直宣言(isReach 对于天凤来说恒为 false,见 IsReach)
// canBeMeld: 是否可以鳴牌(who=0 时忽略该值)
// kanDoraIndicator: 大明杠/加杠的杠宝牌指示牌,在切牌后出现,没有则返回 -1(天凤恒为-1,见 IsNewDora)
IsDiscard() bool
ParseDiscard() (who int, discardTile int, isRedFive bool, isTsumogiri bool, isReach bool, canBeMeld bool, kanDoraIndicator int)

// 鳴牌(含暗杠、加杠)
// kanDoraIndicator: 暗杠的杠宝牌指示牌,在他家暗杠时出现,没有则返回 -1(天凤恒为-1,见 IsNewDora)
IsOpen() bool
ParseOpen() (who int, meld *model.Meld, kanDoraIndicator int)

// 立直声明(IsReach 对于雀魂来说恒为 false,见 ParseDiscard)
IsReach() bool
ParseReach() (who int)

// 振听
IsFuriten() bool

// 本局是否和牌
IsRoundWin() bool
ParseRoundWin() (whos []int, points []int)

// 是否流局
// 四风连打 四家立直 四杠散了 九种九牌 三家和了 | 流局听牌 流局未听牌 | 流局满贯
// 三家和了
IsRyuukyoku() bool
ParseRyuukyoku() (type_ int, whos []int, points []int)

// 拔北宝牌
IsNukiDora() bool
ParseNukiDora() (who int, isTsumogiri bool)

// 这一项放在末尾处理
// 杠宝牌(雀魂在暗杠后的摸牌时出现)
// kanDoraIndicator: 0-33
IsNewDora() bool
ParseNewDora() (kanDoraIndicator int)
}
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
- [使用说明](#使用说明)
- [示例](#示例)
* [牌效率](#牌效率)
* [鸣牌判断](#鸣牌判断)
* [鳴牌判断](#鳴牌判断)
* [手摸切与安牌显示](#手摸切与安牌显示)
- [牌谱与观战](#牌谱与观战)
- [其他功能说明](#其他功能说明)
Expand Down Expand Up @@ -91,12 +91,12 @@
补充说明:

- 无改良时,不显示改良进张数
- 鸣牌时会显示用手上的哪些牌去吃/碰,详见后文
- 鳴牌时会显示用手上的哪些牌去吃/碰,详见后文
- 防守时,切牌的文字颜色会因这张牌的安全程度而不同,详见后文
- 门清听牌时,会显示立直的期望点数(考虑自摸、一发和里宝);若默听有役则会额外显示默听的荣和点数
- 存在高低目的场合会显示加权和率的平均点数
- 役种只对较为特殊的进行提示,如三色、一通、七对等。雀魂乱斗之间会有额外的古役提醒
- 若鸣牌且无役会提示 `[无役]`
- 若鳴牌且无役会提示 `[无役]`
- 听牌或一向听时根据自家舍牌情况提示振听
- m-万子 p-饼子 s-索子 z-字牌,顺序为东南西北白发中

Expand Down Expand Up @@ -140,11 +140,11 @@

![](img/example03a.png)

### 鸣牌判断
### 鳴牌判断

下图是一个鸣了红中之后,听坎 5s 的例子,宝牌为 6m。

上家打出 6m 宝牌之后考虑是否鸣牌
上家打出 6m 宝牌之后考虑是否鳴牌

这里就可以考虑用 57m 吃,打出 9m,提升打点的同时又能维持听牌。此外,若巡目尚早可以拆掉 46s 追求混一色。

Expand All @@ -155,7 +155,7 @@
下图展示了某局中三家的手摸切情况(宝牌为红中和 6s,自家手牌此时为 345678m 569p 45667s):

- 白色为手切,暗灰色为摸切
- 鸣牌后打出的那张牌会用灰底白字显示,供读牌分析用
- 鳴牌后打出的那张牌会用灰底白字显示,供读牌分析用
- 副露玩家的手切中张牌(3-7)会有不同颜色的高亮,用来辅助判断其听牌率
- 玩家立直或听牌率较高时会额外显示对该玩家的安牌,用 | 分隔,左侧为现物,右侧按照危险度由低到高排序(No Chance 和 One Chance 的安牌作为补充参考显示在后面,简写为 NC 和 OC)
- 下图上家亲家暗杠 2m 后 4p 立直,对家 8s 追立,下家一副露但是手切了很多中张牌,听牌率较高
Expand Down Expand Up @@ -200,7 +200,7 @@

`mahjong-helper 234688m 34s # 6666P 234p`

- 分析鸣牌
- 分析鳴牌

在 `+` 后面添加要鸣的牌,支持用 0 表示的红宝牌

Expand Down
46 changes: 24 additions & 22 deletions analysis.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package main

import (
"github.com/EndlessCheng/mahjong-helper/util"
"fmt"
"strings"
"github.com/fatih/color"

"github.com/EndlessCheng/mahjong-helper/util"
"github.com/EndlessCheng/mahjong-helper/util/model"
"github.com/fatih/color"
)

func simpleBestDiscardTile(playerInfo *model.PlayerInfo) int {
Expand All @@ -18,7 +19,7 @@ func simpleBestDiscardTile(playerInfo *model.PlayerInfo) int {
} else {
return -1
}
if shanten == 1 && len(playerInfo.DiscardTiles) < 9 && len(results14) > 0 && len(incShantenResults14) > 0 && !playerInfo.IsNaki() { // 鸣牌时的向听倒退暂不考虑
if shanten == 1 && len(playerInfo.DiscardTiles) < 9 && len(results14) > 0 && len(incShantenResults14) > 0 && !playerInfo.IsNaki() { // 鳴牌时的向听倒退暂不考虑
if results14[0].Result13.Waits.AllCount() < 9 && results14[0].Result13.MixedWaitsScore < incShantenResults14[0].Result13.MixedWaitsScore {
bestAttackDiscardTile = incShantenResults14[0].DiscardTile
}
Expand All @@ -45,6 +46,7 @@ func humanHands(playerInfo *model.PlayerInfo) string {
return humanHands
}

// analysis player hand risk
func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTable) error {
// 手牌
humanTiles := humanHands(playerInfo)
Expand All @@ -55,13 +57,13 @@ func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTab
switch countOfTiles % 3 {
case 1:
result := util.CalculateShantenWithImproves13(playerInfo)
fmt.Println("当前" + util.NumberToChineseShanten(result.Shanten) + ":")
r := &analysisResult{
fmt.Println("當前" + util.NumberToChineseShanten(result.Shanten) + ":")
r := &AnalysisResult{
discardTile34: -1,
result13: result,
mixedRiskTable: mixedRiskTable,
MixedRiskTable: mixedRiskTable,
}
r.printWaitsWithImproves13_oneRow()
r.PrintWaitsWithImproves13_oneRow()
case 2:
// 分析手牌
shanten, results14, incShantenResults14 := util.CalculateShantenWithImproves14(playerInfo)
Expand All @@ -73,7 +75,7 @@ func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTab
if len(results14) > 0 {
r13 := results14[0].Result13
if r13.RiichiPoint > 0 && r13.FuritenRate == 0 && r13.DamaPoint >= 5200 && r13.DamaWaits.AllCount() == r13.Waits.AllCount() {
color.HiGreen("默听打点充足:追求和率默听,追求打点立直")
color.HiGreen("默聽打點充足,若追求和率可以默聽,追求打點可以選擇立直")
}
// 局收支相近时,提示:局收支相近,追求和率打xx,追求打点打xx
}
Expand All @@ -87,11 +89,11 @@ func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTab
// TODO: 接近流局时提示河底是哪家

// 何切分析结果
printResults14WithRisk(results14, mixedRiskTable)
printResults14WithRisk(incShantenResults14, mixedRiskTable)
PrintResults14WithRisk(results14, mixedRiskTable)
PrintResults14WithRisk(incShantenResults14, mixedRiskTable)
default:
err := fmt.Errorf("参数错误: %d 张牌", countOfTiles)
if debugMode {
if DebugMode {
panic(err)
}
return err
Expand All @@ -101,7 +103,7 @@ func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTab
return nil
}

// 分析鸣牌
// 分析鳴牌
// playerInfo: 自家信息
// targetTile34: 他家舍牌
// isRedFive: 此舍牌是否为赤5
Expand All @@ -119,41 +121,41 @@ func analysisMeld(playerInfo *model.PlayerInfo, targetTile34 int, isRedFive bool
return nil // fmt.Errorf("输入错误:无法鸣这张牌")
}

// 鸣牌
// 鳴牌
humanTiles := humanHands(playerInfo)
handsTobeNaki := humanTiles + " " + model.SepTargetTile + " " + util.Tile34ToStr(targetTile34) + "?"
fmt.Println(handsTobeNaki)
fmt.Println(strings.Repeat("=", len(handsTobeNaki)))

// 原始手牌分析结果
fmt.Println("当前" + util.NumberToChineseShanten(result.Shanten) + ":")
r := &analysisResult{
fmt.Println("當前" + util.NumberToChineseShanten(result.Shanten) + ":")
r := &AnalysisResult{
discardTile34: -1,
result13: result,
mixedRiskTable: mixedRiskTable,
MixedRiskTable: mixedRiskTable,
}
r.printWaitsWithImproves13_oneRow()
r.PrintWaitsWithImproves13_oneRow()

// 提示信息
// TODO: 局收支相近时,提示:局收支相近,追求和率打xx,追求打点打xx
if shanten == -1 {
color.HiRed("【已和牌】")
} else if shanten <= 1 {
// 鸣牌后听牌或一向听,提示型听
// 鳴牌后听牌或一向听,提示型听
if len(results14) > 0 && results14[0].LeftDrawTilesCount > 0 && results14[0].LeftDrawTilesCount <= 16 {
color.HiGreen("考虑型听?")
}
}

// TODO: 接近流局时提示河底是哪家

// 鸣牌何切分析结果
printResults14WithRisk(results14, mixedRiskTable)
printResults14WithRisk(incShantenResults14, mixedRiskTable)
// 鳴牌何切分析结果
PrintResults14WithRisk(results14, mixedRiskTable)
PrintResults14WithRisk(incShantenResults14, mixedRiskTable)
return nil
}

func analysisHumanTiles(humanTilesInfo *model.HumanTilesInfo) (playerInfo *model.PlayerInfo, err error) {
func AnalysisHumanTiles(humanTilesInfo *model.HumanTilesInfo) (playerInfo *model.PlayerInfo, err error) {
defer func() {
if er := recover(); er != nil {
err = er.(error)
Expand Down
Loading