├── tools ├── tentool │ ├── .gitignore │ ├── utils │ │ ├── check.go │ │ ├── routines.go │ │ ├── gzfile.go │ │ ├── tracker.go │ │ ├── interactive_writer.go │ │ ├── options.go │ │ ├── file.go │ │ ├── interactive_tracker.go │ │ ├── donwload_test.go │ │ └── scheduler.go │ ├── stats │ │ ├── test_data │ │ │ ├── list.js │ │ │ ├── scc20120404.html │ │ │ ├── list_old.js │ │ │ ├── sca.log │ │ │ ├── sce20180101.html │ │ │ ├── scf.log │ │ │ ├── scb.log │ │ │ ├── scd.log │ │ │ └── sce.log │ │ ├── urls.go │ │ ├── cmd_yadisk.go │ │ ├── parse_test.go │ │ ├── parse.go │ │ └── index.go │ ├── export.json │ ├── logs │ │ ├── parse.go │ │ ├── cmd_status.go │ │ ├── cmd_collect.go │ │ ├── cmd_yadisk.go │ │ ├── id_test.go │ │ ├── cmd_remove_index.go │ │ ├── cmd_get.go │ │ ├── parse_test.go │ │ └── test_data │ │ │ └── scc.html │ ├── Makefile │ ├── main.go │ └── README.md └── tools.go ├── vendor ├── github.com │ ├── spf13 │ │ ├── pflag │ │ │ ├── .gitignore │ │ │ ├── .golangci.yaml │ │ │ ├── .editorconfig │ │ │ ├── .travis.yml │ │ │ └── LICENSE │ │ └── cobra │ │ │ ├── .mailmap │ │ │ ├── MAINTAINERS │ │ │ ├── .gitignore │ │ │ ├── command_notwin.go │ │ │ ├── Makefile │ │ │ ├── command_win.go │ │ │ └── .golangci.yml │ ├── c2h5oh │ │ └── datasize │ │ │ ├── .travis.yml │ │ │ ├── .gitignore │ │ │ └── LICENSE │ ├── golang │ │ └── protobuf │ │ │ ├── AUTHORS │ │ │ ├── CONTRIBUTORS │ │ │ └── LICENSE │ ├── facebookgo │ │ ├── stackerr │ │ │ ├── readme.md │ │ │ ├── .travis.yml │ │ │ └── license │ │ └── stack │ │ │ ├── .travis.yml │ │ │ └── license │ ├── stretchr │ │ └── testify │ │ │ ├── require │ │ │ ├── require_forward.go.tmpl │ │ │ ├── require.go.tmpl │ │ │ ├── forward_requirements.go │ │ │ ├── doc.go │ │ │ └── requirements.go │ │ │ ├── assert │ │ │ ├── assertion_format.go.tmpl │ │ │ ├── assertion_forward.go.tmpl │ │ │ ├── errors.go │ │ │ ├── forward_assertions.go │ │ │ ├── yaml │ │ │ │ ├── yaml_fail.go │ │ │ │ ├── yaml_custom.go │ │ │ │ └── yaml_default.go │ │ │ └── doc.go │ │ │ └── LICENSE │ ├── dnovikoff │ │ └── tempai-core │ │ │ ├── yaku │ │ │ ├── types.go │ │ │ ├── fu.go │ │ │ ├── limit.go │ │ │ ├── resources.go │ │ │ ├── limit_string.go │ │ │ ├── fu_string.go │ │ │ ├── win.go │ │ │ ├── context.go │ │ │ ├── rules_predefined.go │ │ │ ├── rules.go │ │ │ └── yakuman_string.go │ │ │ ├── hand │ │ │ ├── calc │ │ │ │ ├── tags.go │ │ │ │ ├── meld_debug.go │ │ │ │ ├── meld_stack.go │ │ │ │ ├── counter_block.go │ │ │ │ ├── meld.go │ │ │ │ ├── options.go │ │ │ │ ├── meld_kokushi.go │ │ │ │ └── melds.go │ │ │ ├── tempai │ │ │ │ ├── debug.go │ │ │ │ └── type_string.go │ │ │ └── effective │ │ │ │ ├── sort.go │ │ │ │ └── effective.go │ │ │ ├── base │ │ │ ├── wind.go │ │ │ └── wind_string.go │ │ │ ├── tile │ │ │ └── type.go │ │ │ ├── compact │ │ │ ├── packed_masks.go │ │ │ ├── test_generator.go │ │ │ ├── constants.go │ │ │ ├── generator.go │ │ │ └── totals.go │ │ │ ├── score │ │ │ ├── rules.go │ │ │ └── rules_prefefined.go │ │ │ └── LICENSE │ ├── satori │ │ └── go.uuid │ │ │ ├── .travis.yml │ │ │ └── LICENSE │ ├── inconshreveable │ │ └── mousetrap │ │ │ ├── trap_others.go │ │ │ ├── README.md │ │ │ └── trap_windows.go │ ├── davecgh │ │ └── go-spew │ │ │ └── LICENSE │ └── pmezard │ │ └── go-difflib │ │ └── LICENSE ├── go.uber.org │ └── multierr │ │ ├── .gitignore │ │ ├── .codecov.yml │ │ ├── Makefile │ │ ├── LICENSE.txt │ │ └── README.md ├── google.golang.org │ └── protobuf │ │ ├── internal │ │ ├── editiondefaults │ │ │ ├── editions_defaults.binpb │ │ │ └── defaults.go │ │ ├── flags │ │ │ ├── proto_legacy_enable.go │ │ │ ├── proto_legacy_disable.go │ │ │ └── flags.go │ │ ├── genid │ │ │ ├── name.go │ │ │ ├── doc.go │ │ │ ├── wrappers.go │ │ │ ├── map_entry.go │ │ │ ├── empty_gen.go │ │ │ ├── goname.go │ │ │ ├── field_mask_gen.go │ │ │ ├── source_context_gen.go │ │ │ ├── any_gen.go │ │ │ ├── duration_gen.go │ │ │ └── timestamp_gen.go │ │ ├── impl │ │ │ ├── codec_unsafe.go │ │ │ ├── enum.go │ │ │ ├── pointer_unsafe_opaque.go │ │ │ └── bitmap.go │ │ ├── protolazy │ │ │ └── pointer_unsafe.go │ │ ├── editionssupport │ │ │ └── editions.go │ │ ├── pragma │ │ │ └── pragma.go │ │ ├── descopts │ │ │ └── options.go │ │ ├── set │ │ │ └── ints.go │ │ └── encoding │ │ │ └── text │ │ │ └── doc.go │ │ ├── encoding │ │ └── prototext │ │ │ └── doc.go │ │ ├── runtime │ │ └── protoiface │ │ │ └── legacy.go │ │ ├── proto │ │ ├── proto_reflect.go │ │ ├── proto_methods.go │ │ ├── reset.go │ │ ├── wrappers.go │ │ └── proto.go │ │ ├── cmd │ │ └── protoc-gen-go │ │ │ └── internal_gengo │ │ │ └── init_opaque.go │ │ ├── PATENTS │ │ └── LICENSE └── gopkg.in │ ├── yaml.v2 │ ├── .travis.yml │ ├── NOTICE │ ├── writerc.go │ └── LICENSE.libyaml │ └── yaml.v3 │ └── NOTICE ├── .gitignore ├── network ├── examples │ ├── logs1.zip │ ├── logs2.zip │ ├── logs3.zip │ ├── logs4.zip │ ├── doc.txt │ ├── f5182_2018-01-22_12_36_49.log │ └── second.log ├── auth_test.go ├── xml_connection_debug.go ├── auth.go └── xml_connection.go ├── cmd ├── pimboo-server │ ├── example.gif │ ├── main.go │ ├── README.md │ └── game │ │ └── player.go └── tenhou-proxy │ └── README.md ├── tbase ├── lobby_test.go ├── seed.go ├── helpers.go ├── sex.go ├── draw.go ├── yaku_test.go ├── meld.go ├── meld_test.go ├── lobby.go ├── meld_encode.go └── called.go ├── log ├── xml_test.go ├── controller.go ├── null_controller.go ├── test_data │ ├── README.txt │ └── example.txt └── info_test.go ├── parser ├── parse.go ├── seed.go ├── agari.go ├── node_reader.go └── xml.go ├── server ├── xml_test.go ├── examples_test.go └── controller.go ├── Makefile ├── .github └── workflows │ └── ci.yaml ├── go.mod ├── README.md ├── LICENSE ├── util ├── async_writer.go └── util_test │ └── xml_test.go ├── client └── controller.go ├── protoc.mk └── proto └── stats └── stats.proto /tools/tentool/.gitignore: -------------------------------------------------------------------------------- 1 | /tenhou 2 | /export 3 | /gobin -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /gobin 2 | /build 3 | /coverage.txt 4 | /database -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | cover.html 3 | cover.out 4 | /bin 5 | -------------------------------------------------------------------------------- /network/examples/logs1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnovikoff/tenhou/HEAD/network/examples/logs1.zip -------------------------------------------------------------------------------- /network/examples/logs2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnovikoff/tenhou/HEAD/network/examples/logs2.zip -------------------------------------------------------------------------------- /network/examples/logs3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnovikoff/tenhou/HEAD/network/examples/logs3.zip -------------------------------------------------------------------------------- /network/examples/logs4.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnovikoff/tenhou/HEAD/network/examples/logs4.zip -------------------------------------------------------------------------------- /cmd/pimboo-server/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnovikoff/tenhou/HEAD/cmd/pimboo-server/example.gif -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/.golangci.yaml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable-all: true 3 | enable: 4 | - nolintlint 5 | -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | // +build tools 2 | 3 | package tools 4 | 5 | import ( 6 | _ "github.com/golang/protobuf/protoc-gen-go" 7 | ) 8 | -------------------------------------------------------------------------------- /tools/tentool/utils/check.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "log" 4 | 5 | func Check(err error) { 6 | if err == nil { 7 | return 8 | } 9 | log.Fatal(err) 10 | } 11 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/list.js: -------------------------------------------------------------------------------- 1 | list([ 2 | {file:'sca20180926.log.gz',size:35919}, 3 | {file:'sca20180927.log.gz',size:33557}, 4 | {file:'sca20180928.log.gz',size:35839} 5 | ]); 6 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/scc20120404.html: -------------------------------------------------------------------------------- 1 | 12:20 | 13 | 四鳳東喰赤- | 牌譜 | チーター(+46.0) 里中静流(+2.0) Lask&Yu(-19.0) きょうしろう(-29.0)
2 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnovikoff/tenhou/HEAD/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/.mailmap: -------------------------------------------------------------------------------- 1 | Steve Francia 2 | Bjørn Erik Pedersen 3 | Fabiano Franz 4 | -------------------------------------------------------------------------------- /vendor/github.com/c2h5oh/datasize/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: go 4 | go: 5 | - 1.4 6 | - 1.5 7 | - 1.6 8 | - 1.7 9 | - 1.8 10 | - 1.9 11 | - tip 12 | 13 | script: 14 | - go test -v 15 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /tbase/lobby_test.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestLobbyEncode(t *testing.T) { 10 | assert.Equal(t, "0841", RulesDzjanso.String()) 11 | } 12 | -------------------------------------------------------------------------------- /tools/tentool/export.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "search": "^2023.+$", 4 | "file": "export/logs2023_part.zip" 5 | }, 6 | { 7 | "search": "^([0-9]{4}).+$", 8 | "file": "export/logs$1.zip" 9 | } 10 | ] -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/MAINTAINERS: -------------------------------------------------------------------------------- 1 | maintainers: 2 | - spf13 3 | - johnSchnake 4 | - jpmcb 5 | - marckhouzam 6 | inactive: 7 | - anthonyfok 8 | - bep 9 | - bogem 10 | - broady 11 | - eparis 12 | - jharshman 13 | - wfernandes 14 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stackerr/readme.md: -------------------------------------------------------------------------------- 1 | stackerr [![Build Status](https://secure.travis-ci.org/facebookgo/stackerr.png)](http://travis-ci.org/facebookgo/stackerr) 2 | ======== 3 | 4 | Documentation: https://godoc.org/github.com/facebookgo/stackerr 5 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentFormat}} 2 | func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.go] 12 | indent_style = tab 13 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/list_old.js: -------------------------------------------------------------------------------- 1 | list([ 2 | {file:'2018/sca20180101.log.gz',size:79921}, 3 | {file:'2018/sca20180102.log.gz',size:60186}, 4 | {file:'2018/sca20180103.log.gz',size:63155}, 5 | {file:'2018/scf20180924.html.gz',size:1984} 6 | ]); 7 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require.go.tmpl: -------------------------------------------------------------------------------- 1 | {{ replace .Comment "assert." "require."}} 2 | func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } 5 | t.FailNow() 6 | } 7 | -------------------------------------------------------------------------------- /tbase/seed.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/score" 5 | "github.com/dnovikoff/tempai-core/tile" 6 | ) 7 | 8 | type Seed struct { 9 | RoundNumber int 10 | Honba score.Honba 11 | Sticks score.RiichiSticks 12 | Dice [2]int 13 | Indicator tile.Instance 14 | } 15 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.4.x" 5 | - "1.5.x" 6 | - "1.6.x" 7 | - "1.7.x" 8 | - "1.8.x" 9 | - "1.9.x" 10 | - "1.10.x" 11 | - "1.11.x" 12 | - "1.12.x" 13 | - "1.13.x" 14 | - "1.14.x" 15 | - "tip" 16 | 17 | go_import_path: gopkg.in/yaml.v2 18 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/encoding/prototext/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package prototext marshals and unmarshals protocol buffer messages as the 6 | // textproto format. 7 | package prototext 8 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/flags/proto_legacy_enable.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build protolegacy 6 | // +build protolegacy 7 | 8 | package flags 9 | 10 | const protoLegacy = true 11 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/flags/proto_legacy_disable.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build !protolegacy 6 | // +build !protolegacy 7 | 8 | package flags 9 | 10 | const protoLegacy = false 11 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/sca.log: -------------------------------------------------------------------------------- 1 | L1001 | 15:24 | 三般南喰赤- | ケモさん(+95.0) セネ.(-27.0) 鰐吉(-68.0) 2 | L1001 | 15:35 | 四般南喰赤- | 鰐吉(+57.0) NoName(+25.0) ケモさん(-23.0) セネ.(-59.0) 3 | L1002 | 21:00 | 四般南喰赤- | 小宇(+66.0) exia_ang(+8.0) 小狂三(-20.0) Zeroの雨(-54.0) 4 | L1002 | 21:30 | 四般南喰赤- | 小狂三(+51.0) Zeroの雨(+15.0) 小宇(-9.0) exia_ang(-57.0) 5 | L1002 | 21:50 | 四般南喰赤- | exia_ang(+41.0) 小狂三(+9.0) 小宇(-20.0) Zeroの雨(-30.0) -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/types.go: -------------------------------------------------------------------------------- 1 | package yaku 2 | 3 | type HanPoints int 4 | type FuPoints int 5 | type FuPointsRounded int 6 | 7 | func (p FuPoints) Round() FuPointsRounded { 8 | if p == 25 { 9 | return FuPointsRounded(p) 10 | } 11 | left := p % 10 12 | if left == 0 { 13 | return FuPointsRounded(p) 14 | } 15 | return FuPointsRounded(p - left + 10) 16 | } 17 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/sce20180101.html: -------------------------------------------------------------------------------- 1 | 22:27 | 24 | 四琥南喰赤祝2 | 牌譜 | DERESUKE(+64.0,+12枚) siruneko(+10.0,-1枚) リツミサン(-19.0,-3枚) 群青日和@(-55.0,-8枚)
2 | 23:10 | 23 | 四琥南喰赤祝2 | 牌譜 | 群青日和@(+53.0,-2枚) リツミサン(+5.0,-3枚) siruneko(-18.0,+8枚) DERESUKE(-40.0,-3枚)
3 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: go 4 | 5 | go: 6 | - 1.9.x 7 | - 1.10.x 8 | - 1.11.x 9 | - tip 10 | 11 | matrix: 12 | allow_failures: 13 | - go: tip 14 | 15 | install: 16 | - go get golang.org/x/lint/golint 17 | - export PATH=$GOPATH/bin:$PATH 18 | - go install ./... 19 | 20 | script: 21 | - verify/all.sh -v 22 | - go test ./... 23 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/github.com/c2h5oh/datasize/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/name.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package genid 6 | 7 | const ( 8 | NoUnkeyedLiteral_goname = "noUnkeyedLiteral" 9 | NoUnkeyedLiteralA_goname = "XXX_NoUnkeyedLiteral" 10 | 11 | BuilderSuffix_goname = "_builder" 12 | ) 13 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/runtime/protoiface/legacy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package protoiface 6 | 7 | type MessageV1 interface { 8 | Reset() 9 | String() string 10 | ProtoMessage() 11 | } 12 | 13 | type ExtensionRangeV1 struct { 14 | Start, End int32 // both inclusive 15 | } 16 | -------------------------------------------------------------------------------- /tools/tentool/logs/parse.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "regexp" 5 | "sort" 6 | ) 7 | 8 | var reg = regexp.MustCompile(`tenhou\.net/0/\?log=([0-9a-z-]+)`) 9 | 10 | // ParseIDs parses stat file to find ids of logs 11 | func ParseIDs(data string) []string { 12 | sub := reg.FindAllStringSubmatch(data, -1) 13 | res := make([]string, len(sub)) 14 | for k, v := range sub { 15 | res[k] = v[1] 16 | } 17 | sort.Strings(res) 18 | return res 19 | } 20 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/editiondefaults/defaults.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package editiondefaults contains the binary representation of the editions 6 | // defaults. 7 | package editiondefaults 8 | 9 | import _ "embed" 10 | 11 | //go:embed editions_defaults.binpb 12 | var Defaults []byte 13 | -------------------------------------------------------------------------------- /tbase/helpers.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | func IntList(val string) []int { 9 | s := StringList(val) 10 | if s == nil { 11 | return nil 12 | } 13 | x := make([]int, len(s)) 14 | for k, v := range s { 15 | i, _ := strconv.Atoi(v) 16 | x[k] = i 17 | } 18 | return x 19 | } 20 | 21 | func StringList(val string) []string { 22 | if val == "" { 23 | return nil 24 | } 25 | return strings.Split(val, ",") 26 | } 27 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package genid contains constants for declarations in descriptor.proto 6 | // and the well-known types. 7 | package genid 8 | 9 | import "google.golang.org/protobuf/reflect/protoreflect" 10 | 11 | const GoogleProtobuf_package protoreflect.FullName = "google.protobuf" 12 | -------------------------------------------------------------------------------- /vendor/github.com/satori/go.uuid/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | go: 4 | - 1.2 5 | - 1.3 6 | - 1.4 7 | - 1.5 8 | - 1.6 9 | - 1.7 10 | - 1.8 11 | - 1.9 12 | - tip 13 | matrix: 14 | allow_failures: 15 | - go: tip 16 | fast_finish: true 17 | before_install: 18 | - go get github.com/mattn/goveralls 19 | - go get golang.org/x/tools/cmd/cover 20 | script: 21 | - $HOME/gopath/bin/goveralls -service=travis-ci 22 | notifications: 23 | email: false 24 | -------------------------------------------------------------------------------- /tools/tentool/Makefile: -------------------------------------------------------------------------------- 1 | tentool_bin := ./gobin/tentool 2 | 3 | gobin: 4 | mkdir gobin 5 | 6 | .PHONY: tentool 7 | tentool: 8 | go build -o $(tentool_bin) "./" 9 | 10 | .PHONY: init 11 | init: tentool 12 | $(tentool_bin) stats init 13 | $(tentool_bin) logs init 14 | 15 | .PHONY: yadisk 16 | yadisk: tentool 17 | $(tentool_bin) stats yadisk 18 | $(tentool_bin) logs yadisk 19 | 20 | .PHONY: download 21 | download: yadisk 22 | $(tentool_bin) stats download 23 | $(tentool_bin) logs update 24 | $(tentool_bin) logs download 25 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/calc/tags.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | type Tags int 4 | 5 | const ( 6 | TagChi Tags = 1 << iota 7 | TagPon 8 | TagKan 9 | TagPair 10 | TagTanki 11 | TagKanchan 12 | TagPenchan 13 | TagRyanman 14 | TagComplete 15 | TagKokushi 16 | TagKoksuhi13 17 | TagOpened 18 | 19 | TagHonor 20 | TagTerminal 21 | TagMiddle 22 | ) 23 | 24 | func (t Tags) CheckAny(x Tags) bool { 25 | return (t & x) != 0 26 | } 27 | 28 | func (t Tags) CheckAll(x Tags) bool { 29 | return (t & x) == x 30 | } 31 | -------------------------------------------------------------------------------- /log/xml_test.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "encoding/xml" 5 | "io/ioutil" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/dnovikoff/tenhou/parser" 12 | ) 13 | 14 | func TestXML(t *testing.T) { 15 | data, err := ioutil.ReadFile("test_data/example.xml") 16 | require.NoError(t, err) 17 | x := &parser.Root{} 18 | err = xml.Unmarshal(data, &x) 19 | require.NoError(t, err) 20 | 21 | assert.NoError(t, ProcessXMLNodes(x.Nodes, NullController{})) 22 | } 23 | -------------------------------------------------------------------------------- /tools/tentool/stats/urls.go: -------------------------------------------------------------------------------- 1 | package stats 2 | 3 | const ( 4 | MainPageURL = "http://tenhou.net/sc/raw/" 5 | ListURL = "http://tenhou.net/sc/raw/list.cgi" 6 | ListOldURL = "http://tenhou.net/sc/raw/list.cgi?old" 7 | ) 8 | 9 | func MakeFullURL(short string) string { 10 | return MainPageURL + short 11 | } 12 | 13 | func MakeFullURLs(short []string) []string { 14 | if short == nil { 15 | return nil 16 | } 17 | x := make([]string, len(short)) 18 | for k, v := range short { 19 | x[k] = MakeFullURL(v) 20 | } 21 | return x 22 | } 23 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/wrappers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package genid 6 | 7 | import "google.golang.org/protobuf/reflect/protoreflect" 8 | 9 | // Generic field name and number for messages in wrappers.proto. 10 | const ( 11 | WrapperValue_Value_field_name protoreflect.Name = "value" 12 | WrapperValue_Value_field_number protoreflect.FieldNumber = 1 13 | ) 14 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /tools/tentool/logs/cmd_status.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/dnovikoff/tenhou/tools/tentool/utils" 7 | ) 8 | 9 | func Status() { 10 | index, err := LoadIndex() 11 | utils.Check(err) 12 | total := index.Len() 13 | if total == 0 { 14 | fmt.Println("No logs downloaded") 15 | return 16 | } 17 | downloaded := 0 18 | for _, v := range index.indexed { 19 | if v.Check() { 20 | downloaded++ 21 | } 22 | } 23 | fmt.Printf("Downloaded %v ot of %v files (%v%%)\n", downloaded, total, downloaded*100/total) 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/forward_requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /parser/parse.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "encoding/xml" 5 | "strings" 6 | 7 | "github.com/facebookgo/stackerr" 8 | ) 9 | 10 | func ParseXML(input string) (ret Nodes, err error) { 11 | // Dirty hack 12 | input = "" + input + "" 13 | d := xml.NewDecoder(strings.NewReader(input)) 14 | d.Strict = false 15 | var root Root 16 | err = stackerr.Wrap(d.Decode(&root)) 17 | for k, v := range root.Nodes { 18 | if len(v.Attributes) == 0 { 19 | root.Nodes[k].Attributes = nil 20 | } 21 | } 22 | ret = root.Nodes 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /server/xml_test.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestJoinWrite(t *testing.T) { 11 | c := NewXMLWriter() 12 | c.CancelJoin() 13 | c.Join(0, 9, false) 14 | c.Join(1, 2, true) 15 | 16 | assert.Equal(t, ` `, c.String()) 17 | c2 := NewXMLWriter() 18 | require.NoError(t, ProcessXMLMessage(c.String(), c2)) 19 | assert.Equal(t, ` `, c2.String()) 20 | } 21 | -------------------------------------------------------------------------------- /tbase/sex.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | type Sex int 4 | 5 | const ( 6 | SexUnknown Sex = iota 7 | SexMale 8 | SexFemale 9 | SexComputer 10 | ) 11 | 12 | func (sx Sex) Letter() string { 13 | switch sx { 14 | case SexMale: 15 | return "M" 16 | case SexFemale: 17 | return "F" 18 | case SexComputer: 19 | return "C" 20 | } 21 | return "?" 22 | } 23 | 24 | func ParseSexLetter(in string) Sex { 25 | switch in { 26 | case "M": 27 | return SexMale 28 | case "F": 29 | return SexFemale 30 | case "C": 31 | return SexComputer 32 | } 33 | return SexUnknown 34 | } 35 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/impl/codec_unsafe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package impl 6 | 7 | // When using unsafe pointers, we can just treat enum values as int32s. 8 | 9 | var ( 10 | coderEnumNoZero = coderInt32NoZero 11 | coderEnum = coderInt32 12 | coderEnumPtr = coderInt32Ptr 13 | coderEnumSlice = coderInt32Slice 14 | coderEnumPackedSlice = coderInt32PackedSlice 15 | ) 16 | -------------------------------------------------------------------------------- /tools/tentool/logs/cmd_collect.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | 7 | "github.com/dnovikoff/tenhou/tools/tentool/utils" 8 | ) 9 | 10 | func Collect(args []string) { 11 | index, err := LoadIndex() 12 | utils.Check(err) 13 | newLinks := 0 14 | for _, v := range args { 15 | bytes, err := ioutil.ReadFile(v) 16 | utils.Check(err) 17 | links := ParseIDs(string(bytes)) 18 | newLinks += index.AddIDs(links) 19 | } 20 | fmt.Printf("Found %v new links provided files. New database size: %v\n", newLinks, index.Len()) 21 | utils.Check(index.Save()) 22 | } 23 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stackerr/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.2 5 | - 1.3 6 | 7 | matrix: 8 | fast_finish: true 9 | 10 | before_install: 11 | - go get -v code.google.com/p/go.tools/cmd/vet 12 | - go get -v github.com/golang/lint/golint 13 | - go get -v code.google.com/p/go.tools/cmd/cover 14 | 15 | install: 16 | - go install -race -v std 17 | - go get -race -t -v ./... 18 | - go install -race -v ./... 19 | 20 | script: 21 | - go vet ./... 22 | - $HOME/gopath/bin/golint . 23 | - go test -cpu=2 -race -v ./... 24 | - go test -cpu=2 -covermode=atomic ./... 25 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/calc/meld_debug.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func DebugMeld(m Meld) string { 8 | if m == nil { 9 | return "nil" 10 | } 11 | x := m.Tiles().String() 12 | w := m.Waits() 13 | if len(w) > 0 { 14 | x += " (" + w.String() + ")" 15 | } 16 | return x 17 | } 18 | 19 | func DebugMeldsString(m Melds) string { 20 | return strings.Join(DebugMelds(m), " ") 21 | } 22 | 23 | func DebugMelds(m Melds) []string { 24 | data := make([]string, len(m)) 25 | for k, v := range m { 26 | data[k] = DebugMeld(v) 27 | } 28 | return data 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/inconshreveable/mousetrap/trap_others.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package mousetrap 5 | 6 | // StartedByExplorer returns true if the program was invoked by the user 7 | // double-clicking on the executable from explorer.exe 8 | // 9 | // It is conservative and returns false if any of the internal calls fail. 10 | // It does not guarantee that the program was run from a terminal. It only can tell you 11 | // whether it was launched from explorer.exe 12 | // 13 | // On non-Windows platforms, it always returns false. 14 | func StartedByExplorer() bool { 15 | return false 16 | } 17 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/protolazy/pointer_unsafe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package protolazy 6 | 7 | import ( 8 | "sync/atomic" 9 | "unsafe" 10 | ) 11 | 12 | func atomicLoadIndex(p **[]IndexEntry) *[]IndexEntry { 13 | return (*[]IndexEntry)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) 14 | } 15 | func atomicStoreIndex(p **[]IndexEntry, v *[]IndexEntry) { 16 | atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/fu.go: -------------------------------------------------------------------------------- 1 | package yaku 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/hand/calc" 5 | ) 6 | 7 | func GetMeldFu(m calc.Meld) FuPoints { 8 | tags := m.Tags() 9 | if tags.CheckAny(calc.TagKanchan | calc.TagPenchan | calc.TagTanki) { 10 | return 2 11 | } 12 | if !tags.CheckAny(calc.TagPon) { 13 | return 0 14 | } 15 | var value FuPoints = 2 16 | if tags.CheckAny(calc.TagTerminal | calc.TagHonor) { 17 | value = 4 18 | } 19 | if !tags.CheckAny(calc.TagOpened) { 20 | value *= 2 21 | } 22 | if tags.CheckAny(calc.TagKan) { 23 | value *= 4 24 | } 25 | return value 26 | } 27 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2016 Canonical Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2016 Canonical Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /tbase/draw.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | type DrawType int 4 | 5 | const ( 6 | DrawUnknown DrawType = iota 7 | DrawEnd 8 | Draw9 9 | DrawReach4 10 | DrawRon3 11 | DrawKan4 12 | DrawWind4 13 | DrawNagashi 14 | ) 15 | 16 | var DrawMap = map[string]DrawType{ 17 | "": DrawEnd, 18 | "yao9": Draw9, 19 | "reach4": DrawReach4, 20 | "ron3": DrawRon3, 21 | "kan4": DrawKan4, 22 | "kaze4": DrawWind4, 23 | "nm": DrawNagashi, 24 | } 25 | 26 | var ReverseDrawMap = func() map[DrawType]string { 27 | ret := make(map[DrawType]string, len(DrawMap)) 28 | for k, v := range DrawMap { 29 | ret[v] = k 30 | } 31 | return ret 32 | }() 33 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/scf.log: -------------------------------------------------------------------------------- 1 | C0431 | 20:08 | 四般南喰赤- | 牌譜 | Ⓟ豊後葵(+56.0) 【罪歌】(+10.0) Ⓟ小川裕之(-20.0) みかん太(-46.0)
2 | C0431 | 20:48 | 四般南喰赤- | 牌譜 | みかん太(+53.0) Ⓟ小川裕之(+11.0) 【罪歌】(-11.0) Ⓟ豊後葵(-53.0)
3 | C0431 | 21:17 | 四般南喰赤- | 牌譜 | Ⓟ豊後葵(+54.0) みかん太(+17.0) Ⓟ小川裕之(-21.0) 【罪歌】(-50.0)
4 | C0431 | 21:47 | 四般南喰赤- | 牌譜 | Ⓟ豊後葵(+54.0) 【罪歌】(+17.0) Ⓟ小川裕之(-29.0) みかん太(-42.0)
-------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/proto/proto_reflect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // The protoreflect build tag disables use of fast-path methods. 6 | //go:build protoreflect 7 | // +build protoreflect 8 | 9 | package proto 10 | 11 | import ( 12 | "google.golang.org/protobuf/reflect/protoreflect" 13 | "google.golang.org/protobuf/runtime/protoiface" 14 | ) 15 | 16 | const hasProtoMethods = false 17 | 18 | func protoMethods(m protoreflect.Message) *protoiface.Methods { 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /tools/tentool/utils/routines.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | ) 7 | 8 | type Routines struct { 9 | wg sync.WaitGroup 10 | lastError atomic.Value 11 | } 12 | 13 | func (r *Routines) Start(f func() error) { 14 | r.wg.Add(1) 15 | go func() { 16 | defer r.wg.Done() 17 | err := f() 18 | if err != nil { 19 | r.lastError.Store(err) 20 | } 21 | }() 22 | } 23 | 24 | func (r *Routines) Error() error { 25 | x := r.lastError.Load() 26 | if x == nil { 27 | return nil 28 | } 29 | return x.(error) 30 | } 31 | 32 | func (r *Routines) Wait() error { 33 | r.wg.Wait() 34 | return r.Error() 35 | } 36 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/map_entry.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package genid 6 | 7 | import "google.golang.org/protobuf/reflect/protoreflect" 8 | 9 | // Generic field names and numbers for synthetic map entry messages. 10 | const ( 11 | MapEntry_Key_field_name protoreflect.Name = "key" 12 | MapEntry_Value_field_name protoreflect.Name = "value" 13 | 14 | MapEntry_Key_field_number protoreflect.FieldNumber = 1 15 | MapEntry_Value_field_number protoreflect.FieldNumber = 2 16 | ) 17 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/proto/proto_methods.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // The protoreflect build tag disables use of fast-path methods. 6 | //go:build !protoreflect 7 | // +build !protoreflect 8 | 9 | package proto 10 | 11 | import ( 12 | "google.golang.org/protobuf/reflect/protoreflect" 13 | "google.golang.org/protobuf/runtime/protoiface" 14 | ) 15 | 16 | const hasProtoMethods = true 17 | 18 | func protoMethods(m protoreflect.Message) *protoiface.Methods { 19 | return m.ProtoMethods() 20 | } 21 | -------------------------------------------------------------------------------- /network/auth_test.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestAuth(t *testing.T) { 10 | tst := func(in string) string { 11 | ret, err := AuthAnswer(in) 12 | if err != nil { 13 | return err.Error() 14 | } 15 | return ret 16 | } 17 | assert.Equal(t, "20180117-c1ebb26f", tst("20180117-e7b5e83e")) 18 | assert.Equal(t, "Wrong size", tst("2018011-e7b5e83e")) 19 | assert.Equal(t, "Wrong size", tst("20180117-e7b5e83")) 20 | assert.Equal(t, "Wrong parts", tst("20180117e7b5e83e")) 21 | assert.Equal(t, "strconv.ParseInt: parsing \"2180a17\": invalid syntax", tst("2a180a17-e7b5e83e")) 22 | } 23 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stack/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.3 5 | 6 | matrix: 7 | fast_finish: true 8 | 9 | before_install: 10 | - if ! go get code.google.com/p/go.tools/cmd/vet; then go get golang.org/x/tools/cmd/vet; fi 11 | - go get -v github.com/golang/lint/golint 12 | - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi 13 | 14 | install: 15 | - go install -race -v std 16 | - go get -race -t -v ./... 17 | - go install -race -v ./... 18 | 19 | script: 20 | - go vet ./... 21 | - $HOME/gopath/bin/golint . 22 | - go test -cpu=2 -race -v ./... 23 | - go test -cpu=2 -covermode=atomic ./... 24 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/empty_gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Code generated by generate-protos. DO NOT EDIT. 6 | 7 | package genid 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | const File_google_protobuf_empty_proto = "google/protobuf/empty.proto" 14 | 15 | // Names for google.protobuf.Empty. 16 | const ( 17 | Empty_message_name protoreflect.Name = "Empty" 18 | Empty_message_fullname protoreflect.FullName = "google.protobuf.Empty" 19 | ) 20 | -------------------------------------------------------------------------------- /tools/tentool/logs/cmd_yadisk.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "github.com/dnovikoff/tenhou/tools/tentool/utils" 5 | ) 6 | 7 | type yadisk struct { 8 | interactive bool 9 | index *FileIndex 10 | } 11 | 12 | func (y *yadisk) Run(args []string) { 13 | index, err := LoadIndex() 14 | utils.Check(err) 15 | y.index = index 16 | if len(args) == 0 { 17 | args = []string{"https://yadi.sk/d/FIIkaucSNjR3Kw"} 18 | } 19 | for _, v := range args { 20 | utils.Check(y.download(v)) 21 | } 22 | } 23 | 24 | func (y *yadisk) download(u string) error { 25 | return utils.YaDiskDownload(u, Location, y.interactive, func(_, p string) error { 26 | return addZipToIndex(y.index, p) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/base/wind.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/tile" 5 | ) 6 | 7 | //go:generate stringer -type=Wind 8 | type Wind int 9 | 10 | const ( 11 | WindEast Wind = iota 12 | WindSouth 13 | WindWest 14 | WindNorth 15 | WindEnd 16 | ) 17 | 18 | func (w Wind) tile() tile.Tile { 19 | return tile.Tile(w) + tile.East 20 | } 21 | 22 | func (w Wind) CheckTile(t tile.Tile) bool { 23 | return w.tile() == t 24 | } 25 | 26 | func (w Wind) fix() Wind { 27 | if w < 0 { 28 | return (w + (4 * (w / -4)) + 4) % 4 29 | } 30 | return w % 4 31 | } 32 | 33 | func (w Wind) Advance(num int) Wind { 34 | return (w + Wind(num)).fix() 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | # Vim files https://github.com/github/gitignore/blob/master/Global/Vim.gitignore 23 | # swap 24 | [._]*.s[a-w][a-z] 25 | [._]s[a-w][a-z] 26 | # session 27 | Session.vim 28 | # temporary 29 | .netrwhist 30 | *~ 31 | # auto-generated tag files 32 | tags 33 | 34 | *.exe 35 | cobra.test 36 | bin 37 | 38 | .idea/ 39 | *.iml 40 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/tile/type.go: -------------------------------------------------------------------------------- 1 | package tile 2 | 3 | type Type int 4 | 5 | const ( 6 | TypeMan Type = Type(Man1) 7 | TypePin Type = Type(Pin1) 8 | TypeSou Type = Type(Sou1) 9 | TypeWind Type = Type(East) 10 | TypeDragon Type = Type(White) 11 | TypeNull Type = Type(TileNull) 12 | ) 13 | 14 | func (t Type) Tile(num int) Tile { 15 | return Tile(t) + Tile(num-1) 16 | } 17 | 18 | // TypeRune used for stringifying tiles 19 | func TypeRune(t Type) rune { 20 | switch t { 21 | case TypeMan: 22 | return 'm' 23 | case TypePin: 24 | return 'p' 25 | case TypeSou: 26 | return 's' 27 | case TypeDragon, TypeWind: 28 | return 'z' 29 | } 30 | return '-' 31 | } 32 | -------------------------------------------------------------------------------- /tools/tentool/stats/cmd_yadisk.go: -------------------------------------------------------------------------------- 1 | package stats 2 | 3 | import ( 4 | "github.com/dnovikoff/tenhou/tools/tentool/utils" 5 | ) 6 | 7 | type yadisk struct { 8 | interactive bool 9 | index *FileIndex 10 | } 11 | 12 | func (y *yadisk) Run(args []string) { 13 | index, err := LoadIndex() 14 | utils.Check(err) 15 | y.index = index 16 | if len(args) == 0 { 17 | args = []string{"https://yadi.sk/d/uOv87aVsd-l-3A"} 18 | } 19 | for _, v := range args { 20 | utils.Check(y.download(v)) 21 | } 22 | } 23 | 24 | func (y *yadisk) download(u string) error { 25 | return utils.YaDiskDownload(u, Location, y.interactive, func(publicURL, path string) error { 26 | return y.index.Add(publicURL, path) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/goname.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package genid 6 | 7 | // Go names of implementation-specific struct fields in generated messages. 8 | const ( 9 | State_goname = "state" 10 | 11 | SizeCache_goname = "sizeCache" 12 | SizeCacheA_goname = "XXX_sizecache" 13 | 14 | UnknownFields_goname = "unknownFields" 15 | UnknownFieldsA_goname = "XXX_unrecognized" 16 | 17 | ExtensionFields_goname = "extensionFields" 18 | ExtensionFieldsA_goname = "XXX_InternalExtensions" 19 | ExtensionFieldsB_goname = "XXX_extensions" 20 | ) 21 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/impl/enum.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package impl 6 | 7 | import ( 8 | "reflect" 9 | 10 | "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | type EnumInfo struct { 14 | GoReflectType reflect.Type // int32 kind 15 | Desc protoreflect.EnumDescriptor 16 | } 17 | 18 | func (t *EnumInfo) New(n protoreflect.EnumNumber) protoreflect.Enum { 19 | return reflect.ValueOf(n).Convert(t.GoReflectType).Interface().(protoreflect.Enum) 20 | } 21 | func (t *EnumInfo) Descriptor() protoreflect.EnumDescriptor { return t.Desc } 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: generate 2 | all: generate test build 3 | 4 | include protoc.mk 5 | 6 | gobin: 7 | mkdir gobin 8 | 9 | # github.com/golang/protobuf/protoc-gen-go 10 | CMD := $(protoc_go_cmd) --go_out=paths=source_relative,plugins=grpc:./genproto --proto_path=./proto 11 | 12 | .PHONY: generate 13 | generate: $(protoc_gen_go) 14 | rm -rf genproto 15 | mkdir genproto 16 | # cd proto && 17 | $(CMD) ./proto/stats/*.proto 18 | 19 | .PHONY: test 20 | test: 21 | go test -mod vendor ./... 22 | 23 | .PHONY: build 24 | build: 25 | mkdir -p build 26 | GOBIN=$(shell pwd)/build go install -mod vendor ./cmd/... 27 | 28 | .PHONY: testcover 29 | testcover: 30 | go test -mod vendor -race -coverprofile=coverage.txt -covermode=atomic ./... 31 | -------------------------------------------------------------------------------- /tbase/yaku_test.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | // func TestYakuParse(t *testing.T) { 4 | // ret, err := ParseYakuList("35,6,52,2,54,1") 5 | // require.NoError(t, err) 6 | // assert.Equal(t, "YakuAkaDora: 1, YakuChinitsu: 6, YakuDora: 2", ret.String()) 7 | // } 8 | 9 | // func TestYakuParseWrong(t *testing.T) { 10 | // _, err := ParseYakuList("35,6,52,2,a54,1") 11 | // require.Error(t, err) 12 | // assert.Contains(t, err.Error(), "invalid syntax") 13 | // _, err = ParseYakuList("35,6,52,2,54,") 14 | // require.Error(t, err) 15 | // assert.Contains(t, err.Error(), "invalid syntax") 16 | // _, err = ParseYakuList("35,6,52,2,154,1") 17 | // require.Error(t, err) 18 | // assert.Contains(t, err.Error(), "Yaku with value 154 not found in map") 19 | // } 20 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/calc/meld_stack.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | type meldStack struct { 4 | melds Melds 5 | index int 6 | } 7 | 8 | func newMeldStack(capacity int) *meldStack { 9 | return &meldStack{ 10 | melds: make(Melds, capacity), 11 | } 12 | } 13 | 14 | func (ms *meldStack) size() int { 15 | return ms.index 16 | } 17 | 18 | func (ms *meldStack) reset() { 19 | ms.index = 0 20 | } 21 | 22 | func (ms *meldStack) push(meld Meld) { 23 | ms.melds[ms.index] = meld 24 | ms.index++ 25 | } 26 | 27 | func (ms *meldStack) getMelds() Melds { 28 | return ms.melds[:ms.index] 29 | } 30 | 31 | func (ms *meldStack) back() Meld { 32 | return ms.melds[ms.index-1] 33 | } 34 | 35 | func (ms *meldStack) pop() { 36 | ms.index-- 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go: -------------------------------------------------------------------------------- 1 | //go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default 2 | // +build testify_yaml_fail,!testify_yaml_custom,!testify_yaml_default 3 | 4 | // Package yaml is an implementation of YAML functions that always fail. 5 | // 6 | // This implementation can be used at build time to replace the default implementation 7 | // to avoid linking with [gopkg.in/yaml.v3]: 8 | // 9 | // go test -tags testify_yaml_fail 10 | package yaml 11 | 12 | import "errors" 13 | 14 | var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)") 15 | 16 | func Unmarshal([]byte, interface{}) error { 17 | return errNotImplemented 18 | } 19 | -------------------------------------------------------------------------------- /network/examples/doc.txt: -------------------------------------------------------------------------------- 1 | 1. Все сообщения от сервера и от клиента заканчиваются на терминальный ноль "\0" или "\x00". Сервер может присылать за раз несколько сообщений. Но это не критично и бот умеет работать с одним сообщением за раз. 2 | 2. Есть два основных типа сообщений. Сообщения лично для клиента, которые требуют его действий (например открытия) и общие сообщения про происходящее на столе. 3 | 3. Взятие клиента кодируется как (присылает сервер), сброс клиента 4 | 4. Сброс другого игрока . e - шимоча, f - тоймен, g - камича. После сброса игрока отсылается еще один тег, который обозначает конец хода игрока. Например полный сброс тоймена будет выглядеть как " ". Маленькая буква обозначает цумогири, большая буква обозначает сброс из руки. 5 | -------------------------------------------------------------------------------- /tools/tentool/logs/id_test.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestParseLogID(t *testing.T) { 11 | fullID := "2018092823gm-00a9-0000-2735720b" 12 | parsed := ParseID(fullID) 13 | assert.Equal(t, &ParsedID{ 14 | Time: "2018092823gm", 15 | Type: "00a9", 16 | Number: "0000", 17 | OriginalID: "2735720b", 18 | DownloadID: "2735720b"}, 19 | parsed) 20 | assert.Equal(t, "https://tenhou.net/0/log/?2018092823gm-00a9-0000-2735720b", GetDownloadLink(parsed)) 21 | path, err := GetFilePath(parsed, fullID) 22 | require.NoError(t, err) 23 | assert.Equal(t, "0000/00a9/2018/09/28/23/2018092823gm-00a9-0000-2735720b", path) 24 | 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/compact/packed_masks.go: -------------------------------------------------------------------------------- 1 | package compact 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/tile" 5 | ) 6 | 7 | type PackedMasks uint64 8 | 9 | func SinglePackedMasks(mask Mask, index uint) PackedMasks { 10 | return PackedMasks(mask.Mask() << (4 * index)) 11 | } 12 | 13 | func (pm PackedMasks) Set(mask Mask, index uint) PackedMasks { 14 | erase := ^SinglePackedMasks(15, index) 15 | return (pm & erase) | SinglePackedMasks(mask, index) 16 | } 17 | 18 | func (pm PackedMasks) Get(index uint, tile tile.Tile) Mask { 19 | return NewMask(uint(pm)>>(4*index), tile) 20 | } 21 | 22 | func (pm PackedMasks) CountBits() int { 23 | cnt := 0 24 | 25 | for pm > 0 { 26 | cnt += int(pm & 1) 27 | pm >>= 1 28 | } 29 | return cnt 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/tempai/debug.go: -------------------------------------------------------------------------------- 1 | package tempai 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/dnovikoff/tempai-core/hand/calc" 9 | ) 10 | 11 | func DebugTempai(in *TempaiResult) string { 12 | buf := &bytes.Buffer{} 13 | // fmt.Fprintf(buf, "%v", in.Type) 14 | // fmt.Fprintf(buf, " Tiles: %v", in.Closed.Instances()) 15 | // if in.Declared != nil { 16 | // fmt.Fprintf(buf, " [%v]", meld.DebugMelds(in.Declared)) 17 | // } 18 | if in.Pair != nil { 19 | fmt.Fprintf(buf, " %v", calc.DebugMeld(in.Pair)) 20 | } 21 | if in.Melds != nil { 22 | fmt.Fprintf(buf, " %v", calc.DebugMeldsString(in.Melds)) 23 | } 24 | fmt.Fprintf(buf, " %v", calc.DebugMeld(in.Last)) 25 | return strings.TrimSpace(buf.String()) 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/limit.go: -------------------------------------------------------------------------------- 1 | package yaku 2 | 3 | type Limit int 4 | 5 | //go:generate stringer -type=Limit 6 | // Limit numbers are now fixed and should not be changed 7 | const ( 8 | LimitNone Limit = 0 9 | LimitMangan Limit = 1 10 | LimitHaneman Limit = 2 11 | LimitBaiman Limit = 3 12 | LimitSanbaiman Limit = 4 13 | LimitYakuman Limit = 5 14 | ) 15 | 16 | func (lim Limit) ShortString() string { 17 | return lim.String()[len("Limit"):] 18 | } 19 | 20 | func (lim Limit) BaseHans() HanPoints { 21 | switch lim { 22 | case LimitMangan: 23 | return 5 24 | case LimitHaneman: 25 | return 6 26 | case LimitBaiman: 27 | return 8 28 | case LimitSanbaiman: 29 | return 11 30 | case LimitYakuman: 31 | return 13 32 | } 33 | return 0 34 | } 35 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/editionssupport/editions.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package editionssupport defines constants for editions that are supported. 6 | package editionssupport 7 | 8 | import "google.golang.org/protobuf/types/descriptorpb" 9 | 10 | const ( 11 | Minimum = descriptorpb.Edition_EDITION_PROTO2 12 | Maximum = descriptorpb.Edition_EDITION_2023 13 | 14 | // MaximumKnown is the maximum edition that is known to Go Protobuf, but not 15 | // declared as supported. In other words: end users cannot use it, but 16 | // testprotos inside Go Protobuf can. 17 | MaximumKnown = descriptorpb.Edition_EDITION_2024 18 | ) 19 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/writerc.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | // Set the writer error and return false. 4 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 5 | emitter.error = yaml_WRITER_ERROR 6 | emitter.problem = problem 7 | return false 8 | } 9 | 10 | // Flush the output buffer. 11 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 12 | if emitter.write_handler == nil { 13 | panic("write handler not set") 14 | } 15 | 16 | // Check if the buffer is empty. 17 | if emitter.buffer_pos == 0 { 18 | return true 19 | } 20 | 21 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 22 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 23 | } 24 | emitter.buffer_pos = 0 25 | return true 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/command_notwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2023 The Cobra Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !windows 16 | // +build !windows 17 | 18 | package cobra 19 | 20 | var preExecHookFn func(*Command) 21 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/tempai/type_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Type"; DO NOT EDIT. 2 | 3 | package tempai 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[TypeNone-0] 12 | _ = x[TypeRegular-1] 13 | _ = x[TypePairs-2] 14 | _ = x[TypeKokushi-3] 15 | } 16 | 17 | const _Type_name = "TypeNoneTypeRegularTypePairsTypeKokushi" 18 | 19 | var _Type_index = [...]uint8{0, 8, 19, 28, 39} 20 | 21 | func (i Type) String() string { 22 | if i < 0 || i >= Type(len(_Type_index)-1) { 23 | return "Type(" + strconv.FormatInt(int64(i), 10) + ")" 24 | } 25 | return _Type_name[_Type_index[i]:_Type_index[i+1]] 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/base/wind_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Wind"; DO NOT EDIT. 2 | 3 | package base 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[WindEast-0] 12 | _ = x[WindSouth-1] 13 | _ = x[WindWest-2] 14 | _ = x[WindNorth-3] 15 | _ = x[WindEnd-4] 16 | } 17 | 18 | const _Wind_name = "WindEastWindSouthWindWestWindNorthWindEnd" 19 | 20 | var _Wind_index = [...]uint8{0, 8, 17, 25, 34, 41} 21 | 22 | func (i Wind) String() string { 23 | if i < 0 || i >= Wind(len(_Wind_index)-1) { 24 | return "Wind(" + strconv.FormatInt(int64(i), 10) + ")" 25 | } 26 | return _Wind_name[_Wind_index[i]:_Wind_index[i+1]] 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2016 Dave Collins 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | range: 80..100 3 | round: down 4 | precision: 2 5 | 6 | status: 7 | project: # measuring the overall project coverage 8 | default: # context, you can create multiple ones with custom titles 9 | enabled: yes # must be yes|true to enable this status 10 | target: 100 # specify the target coverage for each commit status 11 | # option: "auto" (must increase from parent commit or pull request base) 12 | # option: "X%" a static target percentage to hit 13 | if_not_found: success # if parent is not found report status as success, error, or failure 14 | if_ci_failed: error # if ci fails report status as success, error, or failure 15 | 16 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/resources.go: -------------------------------------------------------------------------------- 1 | package yaku 2 | 3 | type Dictionary map[string]string 4 | 5 | func AppendResources8(in Dictionary, str string, indexes []uint8) Dictionary { 6 | for i := 0; i < len(indexes)-1; i++ { 7 | in[str[indexes[i]:indexes[i+1]]] = "" 8 | } 9 | return in 10 | } 11 | 12 | func AppendResources16(in Dictionary, str string, indexes []uint16) Dictionary { 13 | for i := 0; i < len(indexes)-1; i++ { 14 | in[str[indexes[i]:indexes[i+1]]] = "" 15 | } 16 | return in 17 | } 18 | 19 | func GetResources() Dictionary { 20 | mp := make(Dictionary) 21 | mp = AppendResources16(mp, _Yaku_name, _Yaku_index[:]) 22 | mp = AppendResources16(mp, _Yakuman_name, _Yakuman_index[:]) 23 | mp = AppendResources8(mp, _Fu_name, _Fu_index[:]) 24 | mp = AppendResources8(mp, _Limit_name, _Limit_index[:]) 25 | return mp 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/compact/test_generator.go: -------------------------------------------------------------------------------- 1 | package compact 2 | 3 | import ( 4 | "github.com/stretchr/testify/require" 5 | 6 | "github.com/dnovikoff/tempai-core/tile" 7 | ) 8 | 9 | type TestGenerator struct { 10 | impl *Generator 11 | t require.TestingT 12 | } 13 | 14 | func NewTestGenerator(t require.TestingT) *TestGenerator { 15 | return &TestGenerator{NewTileGenerator(), t} 16 | } 17 | 18 | func (tg *TestGenerator) TilesLeft() tile.Instances { 19 | return tg.impl.TilesLeft() 20 | } 21 | 22 | func (tg *TestGenerator) InstancesFromString(str string) tile.Instances { 23 | x, err := tg.impl.InstancesFromString(str) 24 | require.NoError(tg.t, err) 25 | return x 26 | } 27 | 28 | func (tg *TestGenerator) CompactFromString(str string) Instances { 29 | x, err := tg.impl.CompactFromString(str) 30 | require.NoError(tg.t, err) 31 | return x 32 | } 33 | -------------------------------------------------------------------------------- /server/examples_test.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | 9 | "github.com/dnovikoff/tenhou/tbase" 10 | "github.com/dnovikoff/tenhou/util" 11 | ) 12 | 13 | type exampleWriter struct { 14 | XMLWriter 15 | t *testing.T 16 | } 17 | 18 | const goodID = "IDDEADBEAF-xxxxxxxx" 19 | 20 | func (w exampleWriter) Hello(name string, tid string, sex tbase.Sex) { 21 | if name != goodID { 22 | require.False(w.t, strings.HasPrefix(name, "ID"), "remove sensetive data "+name) 23 | } 24 | w.XMLWriter.Hello(name, tid, sex) 25 | } 26 | 27 | func TestExamples(t *testing.T) { 28 | w := exampleWriter{NewXMLWriter(), t} 29 | util.ProcessExampleLogs(t, "Send:", func(line string) { 30 | w.Reset() 31 | require.NoError(t, ProcessXMLMessage(line, w), line) 32 | util.CompareLines(t, line, w.String()) 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /cmd/pimboo-server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "log" 7 | 8 | "github.com/dnovikoff/tenhou/cmd/pimboo-server/game" 9 | "github.com/dnovikoff/tenhou/network" 10 | ) 11 | 12 | var addrFlag = flag.String("addr", ":10080", "listen addr") 13 | 14 | func checkError(err error) { 15 | if err == nil { 16 | return 17 | } 18 | log.Fatal(err) 19 | } 20 | 21 | func main() { 22 | flag.Parse() 23 | ln := network.NewListener() 24 | ln.OnError = func(err error) { 25 | checkError(err) 26 | } 27 | ln.Handler = func(c network.XMLConnection) { 28 | log.Printf("New game connection") 29 | game := game.NewGame(c) 30 | game.Run() 31 | c.Close() 32 | log.Printf("Game connection closed") 33 | } 34 | log.Printf("Starting server on addr '%v'", *addrFlag) 35 | err := ln.ListenAndServe(context.Background(), "tcp", *addrFlag) 36 | checkError(err) 37 | } 38 | -------------------------------------------------------------------------------- /tools/tentool/logs/cmd_remove_index.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/dnovikoff/tenhou/tools/tentool/utils" 8 | ) 9 | 10 | func RemoveIndex(prefix string) { 11 | index, err := LoadIndex() 12 | utils.Check(err) 13 | removed := 0 14 | 15 | index.data.Files = removeIndex(index.data.Files, prefix, &removed) 16 | for _, v := range index.data.Zips { 17 | v.Files = removeIndex(v.Files, prefix, &removed) 18 | } 19 | fmt.Printf("Removed %v links. New database size: %v\n", removed, index.Len()) 20 | utils.Check(index.Save()) 21 | } 22 | 23 | func removeIndex(infos []*FileInfo, prefix string, removed *int) []*FileInfo { 24 | next := make([]*FileInfo, 0, len(infos)) 25 | for _, v := range infos { 26 | if !strings.HasPrefix(v.ID, prefix) { 27 | next = append(next, v) 28 | } else { 29 | *removed++ 30 | } 31 | } 32 | return next 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | name: Build 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Set up Go 1.24.3 9 | uses: actions/setup-go@v1 10 | with: 11 | go-version: 1.24.3 12 | 13 | - name: Check out source code 14 | uses: actions/checkout@v1 15 | 16 | - name: Generate 17 | env: 18 | GOPROXY: "off" 19 | run: make generate 20 | 21 | - name: Build 22 | env: 23 | GOPROXY: "off" 24 | run: make build 25 | 26 | - name: Test 27 | env: 28 | GOPROXY: "off" 29 | run: make testcover 30 | 31 | - name: Upload coverage to Codecov 32 | uses: codecov/codecov-action@v1 33 | with: 34 | file: ./coverage.txt 35 | fail_ci_if_error: true 36 | verbose: false 37 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/dnovikoff/tenhou 2 | 3 | go 1.24.3 4 | 5 | require ( 6 | github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 7 | github.com/dnovikoff/tempai-core v0.0.0-20250525213436-fc253e399aa7 8 | github.com/facebookgo/stackerr v0.0.0-20150612192056-c2fcf88613f4 9 | github.com/golang/protobuf v1.5.4 10 | github.com/satori/go.uuid v1.2.0 11 | github.com/spf13/cobra v1.9.1 12 | github.com/stretchr/testify v1.10.0 13 | go.uber.org/multierr v1.11.0 14 | google.golang.org/protobuf v1.36.6 15 | gopkg.in/yaml.v2 v2.4.0 16 | ) 17 | 18 | require ( 19 | github.com/davecgh/go-spew v1.1.1 // indirect 20 | github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect 21 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 22 | github.com/pmezard/go-difflib v1.0.0 // indirect 23 | github.com/spf13/pflag v1.0.6 // indirect 24 | gopkg.in/yaml.v3 v3.0.1 // indirect 25 | ) 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | [![CI](https://github.com/dnovikoff/tenhou/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/dnovikoff/tenhou/actions?query=workflow%3ACI) 4 | [![Coverage Status](https://img.shields.io/codecov/c/github/dnovikoff/tenhou.svg)](https://codecov.io/gh/dnovikoff/tenhou) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/dnovikoff/tenhou)](https://goreportcard.com/report/github.com/dnovikoff/tenhou) 6 | 7 | golang package for working with tenhou net logs and protocol 8 | 9 | This package contains functions for parsing/generating: 10 | 1. Log files 11 | 2. Client messages 12 | 3. Server messages 13 | 14 | ## Proxy logging server 15 | See documentation [here](cmd/tenhou-proxy/README.md) 16 | 17 | ## Pimbooo example server 18 | See documentation [here](cmd/pimboo-server/README.md) 19 | 20 | ## Tenhou stats and log downloader 21 | See documentation [here](tools/tentool/README.md) -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/limit_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Limit"; DO NOT EDIT. 2 | 3 | package yaku 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[LimitNone-0] 12 | _ = x[LimitMangan-1] 13 | _ = x[LimitHaneman-2] 14 | _ = x[LimitBaiman-3] 15 | _ = x[LimitSanbaiman-4] 16 | _ = x[LimitYakuman-5] 17 | } 18 | 19 | const _Limit_name = "LimitNoneLimitManganLimitHanemanLimitBaimanLimitSanbaimanLimitYakuman" 20 | 21 | var _Limit_index = [...]uint8{0, 9, 20, 32, 43, 57, 69} 22 | 23 | func (i Limit) String() string { 24 | if i < 0 || i >= Limit(len(_Limit_index)-1) { 25 | return "Limit(" + strconv.FormatInt(int64(i), 10) + ")" 26 | } 27 | return _Limit_name[_Limit_index[i]:_Limit_index[i+1]] 28 | } 29 | -------------------------------------------------------------------------------- /parser/seed.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/facebookgo/stackerr" 7 | 8 | "github.com/dnovikoff/tempai-core/score" 9 | "github.com/dnovikoff/tenhou/tbase" 10 | "github.com/dnovikoff/tenhou/util" 11 | ) 12 | 13 | func ParseSeed(in string) (ret tbase.Seed, err error) { 14 | seed := tbase.IntList(in) 15 | if len(seed) != 6 { 16 | err = stackerr.Newf("Expected 6 elements for seed") 17 | return 18 | } 19 | ret.RoundNumber = seed[0] 20 | ret.Honba = score.Honba(seed[1]) 21 | ret.Sticks = score.RiichiSticks(seed[2]) 22 | ret.Dice = [2]int{seed[3], seed[4]} 23 | ret.Indicator = util.InstanceFromTenhou(seed[5]) 24 | return 25 | } 26 | 27 | func SeedString(seed *tbase.Seed) string { 28 | return fmt.Sprintf("%d,%d,%d,%d,%d,%d", 29 | seed.RoundNumber, 30 | seed.Honba, 31 | seed.Sticks, 32 | seed.Dice[0], 33 | seed.Dice[1], 34 | util.InstanceToTenhou(seed.Indicator), 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go: -------------------------------------------------------------------------------- 1 | //go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default 2 | // +build testify_yaml_custom,!testify_yaml_fail,!testify_yaml_default 3 | 4 | // Package yaml is an implementation of YAML functions that calls a pluggable implementation. 5 | // 6 | // This implementation is selected with the testify_yaml_custom build tag. 7 | // 8 | // go test -tags testify_yaml_custom 9 | // 10 | // This implementation can be used at build time to replace the default implementation 11 | // to avoid linking with [gopkg.in/yaml.v3]. 12 | // 13 | // In your test package: 14 | // 15 | // import assertYaml "github.com/stretchr/testify/assert/yaml" 16 | // 17 | // func init() { 18 | // assertYaml.Unmarshal = func (in []byte, out interface{}) error { 19 | // // ... 20 | // return nil 21 | // } 22 | // } 23 | package yaml 24 | 25 | var Unmarshal func(in []byte, out interface{}) error 26 | -------------------------------------------------------------------------------- /cmd/pimboo-server/README.md: -------------------------------------------------------------------------------- 1 | ## pimbooo example server 2 | Pimboo (Pin-Man-Bamboo) is a small example server for a game of two players. 3 | The server is created in demonstration purposes only and does not aim for a production. 4 | 5 | Download example server 6 | ``` 7 | go get -u github.com/dnovikoff/tenhou/cmd/pimboo-server 8 | ``` 9 | 10 | Run application 11 | ``` 12 | $GOPATH/bin/pimboo-server 13 | ``` 14 | 15 | Add to your `hosts` file 16 | ``` 17 | 127.0.0.1 b.mjv.jp 18 | ``` 19 | 20 | 1. Login into flash client http://tenhou.net/0/ . 21 | 2. Click on any lobby 22 | 3. See start of the game 23 | 24 | ![Example of game](https://raw.githubusercontent.com/dnovikoff/tenhou/master/cmd/pimboo-server/example.gif) 25 | 26 | The server suggests Ron on any opponent drop and Tsumo on any take. 27 | If you call a Noten-agari, a Furiten-Ron or agari on a wrong tile, you will pay a penalty. 28 | 29 | The game continues until one of the opponents will drop under zero points. -------------------------------------------------------------------------------- /tools/tentool/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | _ "net/http/pprof" 8 | "os" 9 | "runtime/pprof" 10 | 11 | "github.com/spf13/cobra" 12 | 13 | "github.com/dnovikoff/tenhou/tools/tentool/logs" 14 | "github.com/dnovikoff/tenhou/tools/tentool/stats" 15 | ) 16 | 17 | func main() { 18 | cpuProfile := os.Getenv("CPUPROFILE") 19 | httpProfile := os.Getenv("HTTPPROFILE") 20 | if cpuProfile != "" { 21 | f, err := os.Create(cpuProfile) 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | pprof.StartCPUProfile(f) 26 | defer func() { 27 | pprof.StopCPUProfile() 28 | f.Close() 29 | }() 30 | } 31 | if httpProfile != "" { 32 | go func() { 33 | log.Println(http.ListenAndServe(httpProfile, nil)) 34 | }() 35 | } 36 | rootCmd := &cobra.Command{Use: "tentool"} 37 | rootCmd.AddCommand(stats.CMD(), logs.CMD()) 38 | 39 | if err := rootCmd.Execute(); err != nil { 40 | fmt.Println(err) 41 | os.Exit(1) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/inconshreveable/mousetrap/README.md: -------------------------------------------------------------------------------- 1 | # mousetrap 2 | 3 | mousetrap is a tiny library that answers a single question. 4 | 5 | On a Windows machine, was the process invoked by someone double clicking on 6 | the executable file while browsing in explorer? 7 | 8 | ### Motivation 9 | 10 | Windows developers unfamiliar with command line tools will often "double-click" 11 | the executable for a tool. Because most CLI tools print the help and then exit 12 | when invoked without arguments, this is often very frustrating for those users. 13 | 14 | mousetrap provides a way to detect these invocations so that you can provide 15 | more helpful behavior and instructions on how to run the CLI tool. To see what 16 | this looks like, both from an organizational and a technical perspective, see 17 | https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/ 18 | 19 | ### The interface 20 | 21 | The library exposes a single interface: 22 | 23 | func StartedByExplorer() (bool) 24 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/fu_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Fu"; DO NOT EDIT. 2 | 3 | package yaku 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[FuNone-0] 12 | _ = x[FuBase-1] 13 | _ = x[FuBaseClosedRon-2] 14 | _ = x[FuBase7-3] 15 | _ = x[FuSet-4] 16 | _ = x[FuTsumo-5] 17 | _ = x[FuMeld-6] 18 | _ = x[FuNoOpenFu-7] 19 | _ = x[FuBadWait-8] 20 | _ = x[FuPair-9] 21 | } 22 | 23 | const _Fu_name = "FuNoneFuBaseFuBaseClosedRonFuBase7FuSetFuTsumoFuMeldFuNoOpenFuFuBadWaitFuPair" 24 | 25 | var _Fu_index = [...]uint8{0, 6, 12, 27, 34, 39, 46, 52, 62, 71, 77} 26 | 27 | func (i Fu) String() string { 28 | if i < 0 || i >= Fu(len(_Fu_index)-1) { 29 | return "Fu(" + strconv.FormatInt(int64(i), 10) + ")" 30 | } 31 | return _Fu_name[_Fu_index[i]:_Fu_index[i+1]] 32 | } 33 | -------------------------------------------------------------------------------- /tools/tentool/utils/gzfile.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "compress/gzip" 5 | "encoding/json" 6 | "os" 7 | ) 8 | 9 | type JSONGZFile struct { 10 | Path string 11 | Pretty bool 12 | } 13 | 14 | func (f *JSONGZFile) Load(out interface{}) error { 15 | file, err := os.Open(f.fileName()) 16 | if err != nil { 17 | return err 18 | } 19 | defer file.Close() 20 | gz, err := gzip.NewReader(file) 21 | if err != nil { 22 | return err 23 | } 24 | defer gz.Close() 25 | return json.NewDecoder(gz).Decode(out) 26 | } 27 | 28 | func (f *JSONGZFile) fileName() string { 29 | return f.Path + ".gz" 30 | } 31 | 32 | func (f *JSONGZFile) Save(data interface{}) (err error) { 33 | file, err := CreateFile(f.fileName()) 34 | if err != nil { 35 | return 36 | } 37 | defer file.CommitOnSuccess(&err) 38 | gz := gzip.NewWriter(file) 39 | defer gz.Close() 40 | enc := json.NewEncoder(gz) 41 | if f.Pretty { 42 | enc.SetIndent("", " ") 43 | } 44 | err = enc.Encode(data) 45 | return 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/doc.go: -------------------------------------------------------------------------------- 1 | // Package require implements the same assertions as the `assert` package but 2 | // stops test execution when a test fails. 3 | // 4 | // # Example Usage 5 | // 6 | // The following is a complete example using require in a standard test function: 7 | // 8 | // import ( 9 | // "testing" 10 | // "github.com/stretchr/testify/require" 11 | // ) 12 | // 13 | // func TestSomething(t *testing.T) { 14 | // 15 | // var a string = "Hello" 16 | // var b string = "Hello" 17 | // 18 | // require.Equal(t, a, b, "The two words should be the same.") 19 | // 20 | // } 21 | // 22 | // # Assertions 23 | // 24 | // The `require` package have same global functions as in the `assert` package, 25 | // but instead of returning a boolean result they call `t.FailNow()`. 26 | // 27 | // Every assertion function also takes an optional string message as the final argument, 28 | // allowing custom error messages to be appended to the message the assertion method outputs. 29 | package require 30 | -------------------------------------------------------------------------------- /tools/tentool/utils/tracker.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "io" 4 | 5 | type Tracker interface { 6 | Start(total int64) 7 | Write(bytes int) 8 | Done(total int64, err error) 9 | } 10 | 11 | func newWriteTracker(f ...Tracker) *writeTracker { 12 | return &writeTracker{f: f} 13 | } 14 | 15 | type writeTracker struct { 16 | w io.Writer 17 | total int64 18 | f []Tracker 19 | } 20 | 21 | func (w *writeTracker) add(f Tracker) *writeTracker { 22 | w.f = append(w.f, f) 23 | return w 24 | } 25 | 26 | func (w *writeTracker) attach(x io.Writer, total int64) { 27 | w.w = x 28 | if total < 0 { 29 | total = 0 30 | } 31 | for _, v := range w.f { 32 | v.Start(total) 33 | } 34 | } 35 | 36 | func (w *writeTracker) done(written int64, err error) error { 37 | for _, v := range w.f { 38 | v.Done(written, err) 39 | } 40 | return err 41 | } 42 | 43 | func (w *writeTracker) Write(p []byte) (int, error) { 44 | n, err := w.w.Write(p) 45 | for _, v := range w.f { 46 | v.Write(n) 47 | } 48 | return n, err 49 | } 50 | -------------------------------------------------------------------------------- /log/controller.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "github.com/dnovikoff/tenhou/client" 5 | "github.com/dnovikoff/tenhou/tbase" 6 | ) 7 | 8 | type Controller interface { 9 | // Should return false if not interested 10 | Open(Info) bool 11 | Close() 12 | 13 | Shuffle(Shuffle) 14 | Go(client.WithLobby) 15 | Start(client.WithDealer) 16 | Init(Init) 17 | Draw(WithOpponentAndInstance) 18 | Discard(WithOpponentAndInstance) 19 | Declare(Declare) 20 | Ryuukyoku(tbase.Ryuukyoku) 21 | Reach(client.Reach) 22 | Agari(tbase.Agari) 23 | Indicator(client.WithInstance) 24 | Disconnect(client.WithOpponent) 25 | 26 | client.UNController 27 | } 28 | 29 | type Shuffle struct { 30 | Seed string 31 | Ref string 32 | } 33 | 34 | type Declare struct { 35 | client.WithOpponent 36 | Meld tbase.Meld 37 | } 38 | 39 | type WithOpponentAndInstance struct { 40 | client.WithOpponent 41 | client.WithInstance 42 | } 43 | 44 | type Init struct { 45 | tbase.Init 46 | Hands tbase.Hands 47 | // TODO: research 48 | Shuffle string 49 | } 50 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/Makefile: -------------------------------------------------------------------------------- 1 | # Directory to put `go install`ed binaries in. 2 | export GOBIN ?= $(shell pwd)/bin 3 | 4 | GO_FILES := $(shell \ 5 | find . '(' -path '*/.*' -o -path './vendor' ')' -prune \ 6 | -o -name '*.go' -print | cut -b3-) 7 | 8 | .PHONY: build 9 | build: 10 | go build ./... 11 | 12 | .PHONY: test 13 | test: 14 | go test -race ./... 15 | 16 | .PHONY: gofmt 17 | gofmt: 18 | $(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX)) 19 | @gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true 20 | @[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" | cat - $(FMT_LOG) && false) 21 | 22 | .PHONY: golint 23 | golint: 24 | @cd tools && go install golang.org/x/lint/golint 25 | @$(GOBIN)/golint ./... 26 | 27 | .PHONY: staticcheck 28 | staticcheck: 29 | @cd tools && go install honnef.co/go/tools/cmd/staticcheck 30 | @$(GOBIN)/staticcheck ./... 31 | 32 | .PHONY: lint 33 | lint: gofmt golint staticcheck 34 | 35 | .PHONY: cover 36 | cover: 37 | go test -race -coverprofile=cover.out -coverpkg=./... -v ./... 38 | go tool cover -html=cover.out -o cover.html 39 | -------------------------------------------------------------------------------- /tools/tentool/stats/parse_test.go: -------------------------------------------------------------------------------- 1 | package stats 2 | 3 | import ( 4 | "io/ioutil" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestParseMainPage(t *testing.T) { 12 | assert.Equal(t, []string{ 13 | "scraw2006.zip", 14 | "scraw2007.zip", 15 | "scraw2008.zip", 16 | "scraw2009.zip", 17 | "scraw2010.zip", 18 | "scraw2011.zip", 19 | "scraw2012.zip", 20 | "scraw2013.zip", 21 | "scraw2014.zip", 22 | "scraw2015.zip", 23 | "scraw2016.zip", 24 | "scraw2017.zip", 25 | }, ParseMain(loadTestData(t, "raw.html"))) 26 | } 27 | 28 | func TestParseList(t *testing.T) { 29 | assert.Equal(t, []ListItem{ 30 | {File: "sca20180926.log.gz", Size: 35919}, 31 | {File: "sca20180927.log.gz", Size: 33557}, 32 | {File: "sca20180928.log.gz", Size: 35839}, 33 | }, MustParseList(loadTestData(t, "list.js"))) 34 | } 35 | 36 | func loadTestData(t require.TestingT, filename string) string { 37 | data, err := ioutil.ReadFile("test_data/" + filename) 38 | require.NoError(t, err) 39 | return string(data) 40 | } 41 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/Makefile: -------------------------------------------------------------------------------- 1 | BIN="./bin" 2 | SRC=$(shell find . -name "*.go") 3 | 4 | ifeq (, $(shell which golangci-lint)) 5 | $(warning "could not find golangci-lint in $(PATH), run: curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh") 6 | endif 7 | 8 | .PHONY: fmt lint test install_deps clean 9 | 10 | default: all 11 | 12 | all: fmt test 13 | 14 | fmt: 15 | $(info ******************** checking formatting ********************) 16 | @test -z $(shell gofmt -l $(SRC)) || (gofmt -d $(SRC); exit 1) 17 | 18 | lint: 19 | $(info ******************** running lint tools ********************) 20 | golangci-lint run -v 21 | 22 | test: install_deps 23 | $(info ******************** running tests ********************) 24 | go test -v ./... 25 | 26 | richtest: install_deps 27 | $(info ******************** running tests with kyoh86/richgo ********************) 28 | richgo test -v ./... 29 | 30 | install_deps: 31 | $(info ******************** downloading dependencies ********************) 32 | go get -v ./... 33 | 34 | clean: 35 | rm -rf $(BIN) 36 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/field_mask_gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Code generated by generate-protos. DO NOT EDIT. 6 | 7 | package genid 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | const File_google_protobuf_field_mask_proto = "google/protobuf/field_mask.proto" 14 | 15 | // Names for google.protobuf.FieldMask. 16 | const ( 17 | FieldMask_message_name protoreflect.Name = "FieldMask" 18 | FieldMask_message_fullname protoreflect.FullName = "google.protobuf.FieldMask" 19 | ) 20 | 21 | // Field names for google.protobuf.FieldMask. 22 | const ( 23 | FieldMask_Paths_field_name protoreflect.Name = "paths" 24 | 25 | FieldMask_Paths_field_fullname protoreflect.FullName = "google.protobuf.FieldMask.paths" 26 | ) 27 | 28 | // Field numbers for google.protobuf.FieldMask. 29 | const ( 30 | FieldMask_Paths_field_number protoreflect.FieldNumber = 1 31 | ) 32 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/init_opaque.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package internal_gengo 6 | 7 | import "google.golang.org/protobuf/types/gofeaturespb" 8 | 9 | func (m *messageInfo) isOpen() bool { 10 | return m.Message.APILevel == gofeaturespb.GoFeatures_API_OPEN 11 | } 12 | 13 | func (m *messageInfo) isHybrid() bool { 14 | return m.Message.APILevel == gofeaturespb.GoFeatures_API_HYBRID 15 | } 16 | 17 | func (m *messageInfo) isOpaque() bool { 18 | return m.Message.APILevel == gofeaturespb.GoFeatures_API_OPAQUE 19 | } 20 | 21 | func opaqueNewEnumInfoHook(f *fileInfo, e *enumInfo) { 22 | if f.File.APILevel != gofeaturespb.GoFeatures_API_OPEN { 23 | e.genJSONMethod = false 24 | e.genRawDescMethod = false 25 | } 26 | } 27 | 28 | func opaqueNewMessageInfoHook(f *fileInfo, m *messageInfo) { 29 | if !m.isOpen() { 30 | m.genRawDescMethod = false 31 | m.genExtRangeMethod = false 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/controller.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/tile" 5 | "github.com/dnovikoff/tenhou/tbase" 6 | ) 7 | 8 | type Answer int 9 | 10 | const ( 11 | AnswerSkip Answer = iota 12 | AnswerPon // 1 13 | AnswerOpenedKan // 2 14 | AnswerChi // 3 15 | AnswerClosedKan // 4 16 | AnswerChankan // 5 17 | AnswerRon // 6 18 | AnswerTsumo // 7 19 | Answer8 // What is 8??? 20 | AnswerDraw // 9 21 | AnswerSanmaDora // 10 22 | ) 23 | 24 | // This is how server looks from client point of view 25 | type Controller interface { 26 | Hello(name string, tid string, sex tbase.Sex) 27 | Auth(value string) 28 | // TODO: research values 29 | // Could be both big and small 30 | RequestLobbyStatus(v, V int) // PXR 31 | Join(lobbyNumber int, lobbyType int, rejoin bool) 32 | CancelJoin() 33 | Drop(t tile.Instance) 34 | Call(a Answer, tiles tile.Instances) 35 | Reach(t tile.Instance) 36 | Ping() // Z 37 | GoOK() 38 | NextReady() 39 | Bye() 40 | Chat(message string) 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/score/rules.go: -------------------------------------------------------------------------------- 1 | package score 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/yaku" 5 | ) 6 | 7 | type Money int 8 | 9 | type Rules interface { 10 | ManganRound() bool 11 | KazoeYakuman() bool 12 | IsDoubleYakuman(yaku.Yakuman) bool 13 | YakumanSum() bool 14 | 15 | Honba() Money 16 | } 17 | 18 | type RulesStruct struct { 19 | IsManganRound bool 20 | IsKazoeYakuman bool 21 | DoubleYakumans map[yaku.Yakuman]bool 22 | IsYakumanSum bool 23 | 24 | HonbaValue Money 25 | } 26 | 27 | var _ Rules = &RulesStruct{} 28 | 29 | func (r *RulesStruct) ManganRound() bool { 30 | return r.IsManganRound 31 | } 32 | 33 | func (r *RulesStruct) KazoeYakuman() bool { 34 | return r.IsKazoeYakuman 35 | } 36 | 37 | func (r *RulesStruct) IsDoubleYakuman(y yaku.Yakuman) bool { 38 | return r.DoubleYakumans[y] 39 | } 40 | 41 | func (r *RulesStruct) YakumanSum() bool { 42 | return r.IsYakumanSum 43 | } 44 | 45 | func (r *RulesStruct) Honba() Money { 46 | return r.HonbaValue 47 | } 48 | 49 | func GetHonbaMoney(r Rules, honba Honba) Money { 50 | return Money(honba) * r.Honba() 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/win.go: -------------------------------------------------------------------------------- 1 | package yaku 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/compact" 5 | "github.com/dnovikoff/tempai-core/hand/calc" 6 | "github.com/dnovikoff/tempai-core/hand/tempai" 7 | ) 8 | 9 | func Win(results *tempai.TempaiResults, ctx *Context, declaredTiles compact.Instances) *Result { 10 | isRon := ctx.isRon() 11 | top := 0 12 | var ret *Result 13 | for _, v := range results.Results { 14 | win := v.Last.Complete(ctx.Tile.Tile()) 15 | if win == nil { 16 | continue 17 | } 18 | if isRon { 19 | win = calc.Open(win) 20 | } 21 | args := &args{ 22 | ctx: ctx, 23 | result: v, 24 | hand: results.Hand, 25 | declared: declared{ 26 | melds: results.Declared, 27 | tiles: declaredTiles, 28 | }, 29 | win: win, 30 | } 31 | res := calculate(args) 32 | if res == nil { 33 | continue 34 | } 35 | if len(res.Yakumans) > 0 { 36 | top = 14 37 | return res 38 | } 39 | sum := int(res.Fus.Sum()) + int(res.Yaku.Sum()*1000) 40 | if sum > top && sum > 1000 { 41 | ret = res 42 | top = sum 43 | } 44 | } 45 | return ret 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Dmitry Novikov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /util/async_writer.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "sync" 7 | ) 8 | 9 | const DefaultChannelSize = 1024 10 | 11 | type AsyncWriter struct { 12 | writeChan chan string 13 | WriteCallback func(context.Context, string) error 14 | } 15 | 16 | func NewAsyncWriter(channelSize int) *AsyncWriter { 17 | return &AsyncWriter{writeChan: make(chan string, channelSize)} 18 | } 19 | 20 | func (w *AsyncWriter) run(ctx context.Context) { 21 | ctx, cancel := context.WithCancel(ctx) 22 | defer cancel() 23 | for message := range w.writeChan { 24 | err := w.WriteCallback(ctx, message) 25 | if err != nil { 26 | return 27 | } 28 | } 29 | } 30 | 31 | func (w *AsyncWriter) Close() { 32 | close(w.writeChan) 33 | } 34 | 35 | func (w *AsyncWriter) Start(ctx context.Context) func() { 36 | var wg sync.WaitGroup 37 | wg.Add(1) 38 | go func() { 39 | w.run(ctx) 40 | wg.Done() 41 | }() 42 | return wg.Wait 43 | } 44 | 45 | func (w *AsyncWriter) WriteString(message string) error { 46 | select { 47 | case w.writeChan <- message: 48 | default: 49 | return errors.New("Channel is full") 50 | } 51 | return nil 52 | } 53 | -------------------------------------------------------------------------------- /tools/tentool/utils/interactive_writer.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "strings" 8 | ) 9 | 10 | type InteractiveWriter struct { 11 | w io.Writer 12 | buf *bytes.Buffer 13 | lastSize int 14 | } 15 | 16 | func NewInteractiveWriter(w io.Writer) *InteractiveWriter { 17 | return &InteractiveWriter{w: w, buf: &bytes.Buffer{}} 18 | } 19 | 20 | func (w *InteractiveWriter) Printf(format string, args ...interface{}) (int, error) { 21 | lastString := w.buf.String() 22 | w.buf.Reset() 23 | fmt.Fprintf(w.buf, format, args...) 24 | if lastString == w.buf.String() { 25 | return w.buf.Len(), nil 26 | } 27 | return fmt.Fprint(w.w, w.fixString(w.buf.String())) 28 | } 29 | 30 | func (w *InteractiveWriter) Println(args ...interface{}) (int, error) { 31 | w.lastSize = 0 32 | return fmt.Fprintln(w.w, args...) 33 | } 34 | 35 | func (w *InteractiveWriter) fixString(str string) string { 36 | size := len(str) 37 | if w.lastSize != 0 { 38 | str = "\r" + str 39 | } 40 | diff := w.lastSize - size 41 | if diff > 0 { 42 | str += strings.Repeat(" ", diff) 43 | } 44 | w.lastSize = size 45 | return str 46 | } 47 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/source_context_gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Code generated by generate-protos. DO NOT EDIT. 6 | 7 | package genid 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | const File_google_protobuf_source_context_proto = "google/protobuf/source_context.proto" 14 | 15 | // Names for google.protobuf.SourceContext. 16 | const ( 17 | SourceContext_message_name protoreflect.Name = "SourceContext" 18 | SourceContext_message_fullname protoreflect.FullName = "google.protobuf.SourceContext" 19 | ) 20 | 21 | // Field names for google.protobuf.SourceContext. 22 | const ( 23 | SourceContext_FileName_field_name protoreflect.Name = "file_name" 24 | 25 | SourceContext_FileName_field_fullname protoreflect.FullName = "google.protobuf.SourceContext.file_name" 26 | ) 27 | 28 | // Field numbers for google.protobuf.SourceContext. 29 | const ( 30 | SourceContext_FileName_field_number protoreflect.FieldNumber = 1 31 | ) 32 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/calc/counter_block.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | type counterBlock int64 4 | 5 | func (b *counterBlock) set(i uint, c int) { 6 | *b = (*b) & (^(counterBlock(7) << (i * 3))) 7 | *b = (*b) | counterBlock((c&7)<<(i*3)) 8 | } 9 | 10 | func (b *counterBlock) get(i uint) int { 11 | return (int(*b) >> (i * 3)) & 7 12 | } 13 | 14 | func (b *counterBlock) invert(cnt uint) { 15 | for i := uint(0); i < cnt; i++ { 16 | b.set(i, 4-b.get(i)) 17 | } 18 | } 19 | 20 | func (b *counterBlock) dec(i uint, c int) bool { 21 | c = b.get(i) - c 22 | if c < 0 { 23 | return false 24 | } 25 | b.set(i, c) 26 | return true 27 | } 28 | 29 | func (b *counterBlock) dec2(i uint, shift uint) bool { 30 | x1 := b.get(i) 31 | x2 := b.get(i + shift) 32 | if x1 < 1 || x2 < 1 { 33 | return false 34 | } 35 | b.set(i, x1-1) 36 | b.set(i+shift, x2-1) 37 | return true 38 | } 39 | 40 | func (b *counterBlock) dec3(i uint) bool { 41 | x1 := b.get(i) 42 | x2 := b.get(i + 1) 43 | x3 := b.get(i + 2) 44 | if x1 < 1 || x2 < 1 || x3 < 1 { 45 | return false 46 | } 47 | b.set(i, x1-1) 48 | b.set(i+1, x2-1) 49 | b.set(i+2, x3-1) 50 | return true 51 | } 52 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2021 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/github.com/satori/go.uuid/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013-2018 by Maxim Bublis 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /tools/tentool/logs/cmd_get.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "archive/zip" 5 | "compress/gzip" 6 | "io" 7 | "log" 8 | "os" 9 | 10 | "github.com/dnovikoff/tenhou/tools/tentool/utils" 11 | ) 12 | 13 | func cmdGet(id string) { 14 | parsedIds := ParseIDs(id) 15 | if len(parsedIds) == 1 { 16 | id = parsedIds[0] 17 | } 18 | index, err := LoadIndex() 19 | utils.Check(err) 20 | info := index.Get(id) 21 | if info.IsInsideZip() { 22 | zf, err := zip.OpenReader(fileName(info.parent.File)) 23 | utils.Check(err) 24 | defer zf.Close() 25 | for _, v := range zf.File { 26 | if v.Name != info.File { 27 | continue 28 | } 29 | f, err := v.Open() 30 | utils.Check(err) 31 | defer f.Close() 32 | io.Copy(os.Stdout, f) 33 | return 34 | } 35 | log.Fatalf("File '%v' not found in archive '%v'", info.File, info.parent.File) 36 | } else if info.File != "" { 37 | f, err := os.Open(fileName(info.File)) 38 | utils.Check(err) 39 | gz, err := gzip.NewReader(f) 40 | utils.Check(err) 41 | io.Copy(os.Stdout, gz) 42 | utils.Check(gz.Close()) 43 | utils.Check(f.Close()) 44 | } else { 45 | log.Fatalf("Log with id '%v' not found in database", id) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Dmitry Novikov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/c2h5oh/datasize/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Maciej Lisiewski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /network/examples/f5182_2018-01-22_12_36_49.log: -------------------------------------------------------------------------------- 1 | Send: 2 | Get: 3 | Send: 4 | Send: 5 | Get: 6 | Send: 7 | Send: 8 | Send: 9 | Get: 10 | Send: 11 | Get: 12 | Send: 13 | Send: 14 | -------------------------------------------------------------------------------- /tools/tentool/utils/options.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "compress/gzip" 5 | "io" 6 | "net/http" 7 | ) 8 | 9 | const ( 10 | UserAgent = "TenToolBot (+https://github.com/dnovikoff/tenhou/tools/tentool)" 11 | ) 12 | 13 | type downloader struct { 14 | tracker *writeTracker 15 | compressor func(io.Writer) io.WriteCloser 16 | client *http.Client 17 | userAgent string 18 | } 19 | 20 | type Option func(*downloader) 21 | 22 | func AddTracker(f Tracker) Option { 23 | return func(x *downloader) { 24 | x.tracker.add(f) 25 | } 26 | } 27 | 28 | func Client(c *http.Client) Option { 29 | return func(x *downloader) { 30 | x.client = c 31 | } 32 | } 33 | 34 | func Compressor(f func(io.Writer) io.WriteCloser) Option { 35 | return func(x *downloader) { 36 | x.compressor = f 37 | } 38 | } 39 | 40 | func GZIP() Option { 41 | return Compressor(func(w io.Writer) io.WriteCloser { 42 | return gzip.NewWriter(w) 43 | }) 44 | } 45 | 46 | func NewDownloader(opts ...Option) *downloader { 47 | x := &downloader{ 48 | client: &http.Client{}, 49 | tracker: newWriteTracker(), 50 | userAgent: UserAgent, 51 | } 52 | for _, v := range opts { 53 | v(x) 54 | } 55 | return x 56 | } 57 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/score/rules_prefefined.go: -------------------------------------------------------------------------------- 1 | package score 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/yaku" 5 | ) 6 | 7 | func RulesEMA() *RulesStruct { 8 | return &RulesStruct{ 9 | IsManganRound: false, 10 | IsKazoeYakuman: false, 11 | IsYakumanSum: false, 12 | HonbaValue: 100, 13 | } 14 | } 15 | 16 | func RulesTenhou() *RulesStruct { 17 | return &RulesStruct{ 18 | IsManganRound: false, 19 | IsKazoeYakuman: true, 20 | IsYakumanSum: true, 21 | HonbaValue: 100, 22 | } 23 | } 24 | 25 | func RulesJPMLA() *RulesStruct { 26 | return &RulesStruct{ 27 | IsManganRound: false, 28 | IsKazoeYakuman: false, 29 | IsYakumanSum: false, 30 | HonbaValue: 100, 31 | } 32 | } 33 | 34 | func RulesJPMLB() *RulesStruct { 35 | return &RulesStruct{ 36 | IsManganRound: true, 37 | IsKazoeYakuman: false, 38 | IsYakumanSum: false, 39 | HonbaValue: 100, 40 | } 41 | } 42 | 43 | func DefaultDoubleYakumans() map[yaku.Yakuman]bool { 44 | return map[yaku.Yakuman]bool{ 45 | yaku.YakumanChuurenpooto9: true, 46 | yaku.YakumanKokushi13: true, 47 | yaku.YakumanSuuankouTanki: true, 48 | yaku.YakumanDaisuushi: true, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/any_gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Code generated by generate-protos. DO NOT EDIT. 6 | 7 | package genid 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | const File_google_protobuf_any_proto = "google/protobuf/any.proto" 14 | 15 | // Names for google.protobuf.Any. 16 | const ( 17 | Any_message_name protoreflect.Name = "Any" 18 | Any_message_fullname protoreflect.FullName = "google.protobuf.Any" 19 | ) 20 | 21 | // Field names for google.protobuf.Any. 22 | const ( 23 | Any_TypeUrl_field_name protoreflect.Name = "type_url" 24 | Any_Value_field_name protoreflect.Name = "value" 25 | 26 | Any_TypeUrl_field_fullname protoreflect.FullName = "google.protobuf.Any.type_url" 27 | Any_Value_field_fullname protoreflect.FullName = "google.protobuf.Any.value" 28 | ) 29 | 30 | // Field numbers for google.protobuf.Any. 31 | const ( 32 | Any_TypeUrl_field_number protoreflect.FieldNumber = 1 33 | Any_Value_field_number protoreflect.FieldNumber = 2 34 | ) 35 | -------------------------------------------------------------------------------- /log/null_controller.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "github.com/dnovikoff/tenhou/client" 5 | "github.com/dnovikoff/tenhou/tbase" 6 | ) 7 | 8 | type NullController struct{} 9 | 10 | var _ Controller = NullController{} 11 | 12 | func (NullController) Open(Info) bool { return true } 13 | func (NullController) Close() {} 14 | func (NullController) Shuffle(Shuffle) {} 15 | func (NullController) Go(client.WithLobby) {} 16 | func (NullController) Start(client.WithDealer) {} 17 | func (NullController) Init(Init) {} 18 | func (NullController) Draw(WithOpponentAndInstance) {} 19 | func (NullController) Discard(WithOpponentAndInstance) {} 20 | func (NullController) Declare(Declare) {} 21 | func (NullController) Ryuukyoku(tbase.Ryuukyoku) {} 22 | func (NullController) Reach(client.Reach) {} 23 | func (NullController) Agari(tbase.Agari) {} 24 | func (NullController) Indicator(client.WithInstance) {} 25 | func (NullController) Disconnect(client.WithOpponent) {} 26 | func (NullController) UserList(client.UserList) {} 27 | func (NullController) Reconnect(client.Reconnect) {} 28 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/calc/meld.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/compact" 5 | "github.com/dnovikoff/tempai-core/tile" 6 | ) 7 | 8 | type Meld interface { 9 | Tile() tile.Tile 10 | Tags() Tags 11 | Waits() tile.Tiles 12 | CompactWaits() compact.Tiles 13 | // For debug 14 | Tiles() tile.Tiles 15 | Complete(t tile.Tile) Meld 16 | Extract(Counters) bool 17 | } 18 | 19 | type meld struct { 20 | tags Tags 21 | waits tile.Tiles 22 | cwaits compact.Tiles 23 | t tile.Tile 24 | tiles tile.Tiles 25 | } 26 | 27 | func (m *meld) Tags() Tags { 28 | return m.tags 29 | } 30 | 31 | func (m *meld) Complete(t tile.Tile) Meld { 32 | return nil 33 | } 34 | 35 | func (m *meld) Tile() tile.Tile { 36 | return m.t 37 | } 38 | 39 | func (m *meld) Waits() tile.Tiles { 40 | return m.waits 41 | } 42 | 43 | func (m *meld) Tiles() tile.Tiles { 44 | return m.tiles 45 | } 46 | 47 | func (m *meld) CompactWaits() compact.Tiles { 48 | return m.cwaits 49 | } 50 | 51 | type openWrapper struct { 52 | Meld 53 | } 54 | 55 | func (w openWrapper) Tags() Tags { 56 | return w.Meld.Tags() | TagOpened 57 | } 58 | 59 | func Open(m Meld) Meld { 60 | return openWrapper{m} 61 | } 62 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/flags/flags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package flags provides a set of flags controlled by build tags. 6 | package flags 7 | 8 | // ProtoLegacy specifies whether to enable support for legacy functionality 9 | // such as MessageSets, and various other obscure behavior 10 | // that is necessary to maintain backwards compatibility with proto1 or 11 | // the pre-release variants of proto2 and proto3. 12 | // 13 | // This is disabled by default unless built with the "protolegacy" tag. 14 | // 15 | // WARNING: The compatibility agreement covers nothing provided by this flag. 16 | // As such, functionality may suddenly be removed or changed at our discretion. 17 | const ProtoLegacy = protoLegacy 18 | 19 | // LazyUnmarshalExtensions specifies whether to lazily unmarshal extensions. 20 | // 21 | // Lazy extension unmarshaling validates the contents of message-valued 22 | // extension fields at unmarshal time, but defers creating the message 23 | // structure until the extension is first accessed. 24 | const LazyUnmarshalExtensions = ProtoLegacy 25 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/context.go: -------------------------------------------------------------------------------- 1 | package yaku 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/base" 5 | "github.com/dnovikoff/tempai-core/tile" 6 | ) 7 | 8 | // Context is createed to avoid using other game objects in calculations 9 | type Context struct { 10 | Tile tile.Instance 11 | SelfWind base.Wind 12 | RoundWind base.Wind 13 | DoraTiles tile.Tiles 14 | UraTiles tile.Tiles 15 | Rules Rules 16 | IsTsumo bool 17 | IsRiichi bool 18 | IsIpatsu bool 19 | IsDaburi bool 20 | IsLastTile bool 21 | IsRinshan bool 22 | IsFirstTake bool 23 | IsChankan bool 24 | } 25 | 26 | func (c *Context) shouldAddUras() bool { 27 | return c.IsRiichi && c.Rules.Ura() 28 | } 29 | 30 | func (c *Context) shouldAddIpatsu() bool { 31 | return c.IsIpatsu && c.Rules.Ipatsu() 32 | } 33 | 34 | func (c *Context) isRon() bool { 35 | return !c.IsTsumo 36 | } 37 | 38 | func IndicatorsToDoraTiles(in tile.Instances) tile.Tiles { 39 | return TileIndicatorsToDoraTiles(in.Tiles()) 40 | } 41 | 42 | func TileIndicatorsToDoraTiles(in tile.Tiles) tile.Tiles { 43 | out := make(tile.Tiles, len(in)) 44 | for k, v := range in { 45 | out[k] = v.Indicates() 46 | } 47 | return out 48 | } 49 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/proto/reset.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package proto 6 | 7 | import ( 8 | "fmt" 9 | 10 | "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | // Reset clears every field in the message. 14 | // The resulting message shares no observable memory with its previous state 15 | // other than the memory for the message itself. 16 | func Reset(m Message) { 17 | if mr, ok := m.(interface{ Reset() }); ok && hasProtoMethods { 18 | mr.Reset() 19 | return 20 | } 21 | resetMessage(m.ProtoReflect()) 22 | } 23 | 24 | func resetMessage(m protoreflect.Message) { 25 | if !m.IsValid() { 26 | panic(fmt.Sprintf("cannot reset invalid %v message", m.Descriptor().FullName())) 27 | } 28 | 29 | // Clear all known fields. 30 | fds := m.Descriptor().Fields() 31 | for i := 0; i < fds.Len(); i++ { 32 | m.Clear(fds.Get(i)) 33 | } 34 | 35 | // Clear extension fields. 36 | m.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool { 37 | m.Clear(fd) 38 | return true 39 | }) 40 | 41 | // Clear unknown fields. 42 | m.SetUnknown(nil) 43 | } 44 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/proto/wrappers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package proto 6 | 7 | // Bool stores v in a new bool value and returns a pointer to it. 8 | func Bool(v bool) *bool { return &v } 9 | 10 | // Int32 stores v in a new int32 value and returns a pointer to it. 11 | func Int32(v int32) *int32 { return &v } 12 | 13 | // Int64 stores v in a new int64 value and returns a pointer to it. 14 | func Int64(v int64) *int64 { return &v } 15 | 16 | // Float32 stores v in a new float32 value and returns a pointer to it. 17 | func Float32(v float32) *float32 { return &v } 18 | 19 | // Float64 stores v in a new float64 value and returns a pointer to it. 20 | func Float64(v float64) *float64 { return &v } 21 | 22 | // Uint32 stores v in a new uint32 value and returns a pointer to it. 23 | func Uint32(v uint32) *uint32 { return &v } 24 | 25 | // Uint64 stores v in a new uint64 value and returns a pointer to it. 26 | func Uint64(v uint64) *uint64 { return &v } 27 | 28 | // String stores v in a new string value and returns a pointer to it. 29 | func String(v string) *string { return &v } 30 | -------------------------------------------------------------------------------- /network/xml_connection_debug.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "sync" 8 | ) 9 | 10 | type xmlDebugger struct { 11 | impl XMLConnection 12 | log func(format string, args ...interface{}) 13 | } 14 | 15 | func NewMutexLogger(w io.Writer) func(format string, args ...interface{}) { 16 | var m sync.Mutex 17 | return func(format string, args ...interface{}) { 18 | m.Lock() 19 | defer m.Unlock() 20 | fmt.Fprintf(w, format+"\n", args...) 21 | } 22 | } 23 | 24 | func NewXMLConnectionDebugger(impl XMLConnection, log func(format string, args ...interface{})) XMLConnection { 25 | return &xmlDebugger{impl, log} 26 | } 27 | 28 | func (d *xmlDebugger) Read(ctx context.Context) (str string, err error) { 29 | str, err = d.impl.Read(ctx) 30 | if err != nil { 31 | d.log("Get error: %v", err) 32 | } else { 33 | d.log("Get: %v", str) 34 | } 35 | return 36 | } 37 | 38 | func (d *xmlDebugger) Close() error { 39 | d.log("Close") 40 | return d.impl.Close() 41 | } 42 | 43 | // Not thread safe 44 | func (d *xmlDebugger) Write(ctx context.Context, str string) error { 45 | d.log("Send: %v", str) 46 | err := d.impl.Write(ctx, str) 47 | if err != nil { 48 | d.log("Write error: %v", err) 49 | } 50 | return err 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/command_win.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2023 The Cobra Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build windows 16 | // +build windows 17 | 18 | package cobra 19 | 20 | import ( 21 | "fmt" 22 | "os" 23 | "time" 24 | 25 | "github.com/inconshreveable/mousetrap" 26 | ) 27 | 28 | var preExecHookFn = preExecHook 29 | 30 | func preExecHook(c *Command) { 31 | if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { 32 | c.Print(MousetrapHelpText) 33 | if MousetrapDisplayDuration > 0 { 34 | time.Sleep(MousetrapDisplayDuration) 35 | } else { 36 | c.Println("Press return to continue...") 37 | fmt.Scanln() 38 | } 39 | os.Exit(1) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/pragma/pragma.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package pragma provides types that can be embedded into a struct to 6 | // statically enforce or prevent certain language properties. 7 | package pragma 8 | 9 | import "sync" 10 | 11 | // NoUnkeyedLiterals can be embedded in a struct to prevent unkeyed literals. 12 | type NoUnkeyedLiterals struct{} 13 | 14 | // DoNotImplement can be embedded in an interface to prevent trivial 15 | // implementations of the interface. 16 | // 17 | // This is useful to prevent unauthorized implementations of an interface 18 | // so that it can be extended in the future for any protobuf language changes. 19 | type DoNotImplement interface{ ProtoInternal(DoNotImplement) } 20 | 21 | // DoNotCompare can be embedded in a struct to prevent comparability. 22 | type DoNotCompare [0]func() 23 | 24 | // DoNotCopy can be embedded in a struct to help prevent shallow copies. 25 | // This does not rely on a Go language feature, but rather a special case 26 | // within the vet checker. 27 | // 28 | // See https://golang.org/issues/8005. 29 | type DoNotCopy [0]sync.Mutex 30 | -------------------------------------------------------------------------------- /network/auth.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | var translationTable = []int{63006, 9570, 49216, 45888, 9822, 23121, 59830, 51114, 54831, 4189, 580, 5203, 42174, 59972, 10 | 55457, 59009, 59347, 64456, 8673, 52710, 49975, 2006, 62677, 3463, 17754, 5357} 11 | 12 | func AuthAnswer(input string) (ret string, err error) { 13 | parts := strings.Split(input, "-") 14 | if len(parts) != 2 { 15 | err = fmt.Errorf("Wrong parts") 16 | return 17 | } 18 | first := parts[0] 19 | second := parts[1] 20 | 21 | if len(first) != 8 || len(second) != 8 { 22 | err = fmt.Errorf("Wrong size") 23 | return 24 | } 25 | 26 | i1, err := strconv.ParseInt("2"+first[2:8], 10, 64) 27 | if err != nil { 28 | return 29 | } 30 | i2, err := strconv.ParseInt("2"+first[7:8], 10, 64) 31 | if err != nil { 32 | return 33 | } 34 | index := i1 % (12 - i2) * 2 35 | 36 | a16, err := strconv.ParseUint(second[0:4], 16, 64) 37 | if err != nil { 38 | return 39 | } 40 | b16, err := strconv.ParseUint(second[4:8], 16, 64) 41 | if err != nil { 42 | return 43 | } 44 | 45 | a := translationTable[index] ^ int(a16) 46 | b := translationTable[index+1] ^ int(b16) 47 | 48 | ret = first + "-" + fmt.Sprintf("%2x%2x", a, b) 49 | return 50 | } 51 | -------------------------------------------------------------------------------- /log/test_data/README.txt: -------------------------------------------------------------------------------- 1 | shuffle.xml 2 | 00a1/2009/03/17/2009031702gm-00a1-0000-336ee82a.mjlog 3 | shuffle inside INIT 4 | 5 | bye.xml 6 | File 00a1/2009/06/18/2009061806gm-00a1-0000-6d13c207.mjlog 7 | Error: Unexpected node BYE 8 | File 00a1/2009/06/18/2009061806gm-00a1-0000-6d13c207.mjlog 9 | Error: Unprocessed attributes [n1] for UN 10 | 11 | pao.xml 12 | File 00a9/2010/01/22/2010012206gm-00a9-0000-5414f3c4.mjlog 13 | Error: Unprocessed attributes [paoWho] for AGARI [&{AGARI map[paoWho:0]}] 14 | 15 | ratio.xml 16 | File 0841/2013/03/11/2013031109gm-0841-0000-0fde62c3.mjlog 17 | Error: Unprocessed attributes [ratio] for AGARI [&{AGARI map[ratio:0,1]}] 18 | 19 | TODO: find log with ron pao 20 | 21 | bug1.xml 22 | 2009022022gm-00a9-0000-cd94aac8 23 | 24 | bug2.xml 25 | 2009022103gm-00a9-0000-74c37deb 26 | 27 | bug3.xml 28 | 2009022116gm-00a9-0000-77155835 29 | 30 | bug4.xml 31 | 2009022314gm-00a9-0000-9f619d34 32 | 33 | bug5.xml 34 | 2009040322gm-00a9-0000-a911cae1 35 | 36 | bug6.xml 37 | 2009040902gm-00a9-0000-89c396a2 38 | 39 | bug7.xml 40 | 2009071622gm-00a9-0000-a6056eb1 41 | 42 | bug8.xml 43 | 2009082902gm-00a9-0000-df6a8b53 44 | 45 | bug9.xml 46 | 2009091515gm-00a9-0000-1753da1d 47 | 48 | chip.xml, ratio1.xml 49 | Seems like different calculation rules (like kiriyage mangan) -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // TestingT is an interface wrapper around *testing.T 4 | type TestingT interface { 5 | Errorf(format string, args ...interface{}) 6 | FailNow() 7 | } 8 | 9 | type tHelper = interface { 10 | Helper() 11 | } 12 | 13 | // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful 14 | // for table driven tests. 15 | type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) 16 | 17 | // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful 18 | // for table driven tests. 19 | type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) 20 | 21 | // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful 22 | // for table driven tests. 23 | type BoolAssertionFunc func(TestingT, bool, ...interface{}) 24 | 25 | // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful 26 | // for table driven tests. 27 | type ErrorAssertionFunc func(TestingT, error, ...interface{}) 28 | 29 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" 30 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/duration_gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Code generated by generate-protos. DO NOT EDIT. 6 | 7 | package genid 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | const File_google_protobuf_duration_proto = "google/protobuf/duration.proto" 14 | 15 | // Names for google.protobuf.Duration. 16 | const ( 17 | Duration_message_name protoreflect.Name = "Duration" 18 | Duration_message_fullname protoreflect.FullName = "google.protobuf.Duration" 19 | ) 20 | 21 | // Field names for google.protobuf.Duration. 22 | const ( 23 | Duration_Seconds_field_name protoreflect.Name = "seconds" 24 | Duration_Nanos_field_name protoreflect.Name = "nanos" 25 | 26 | Duration_Seconds_field_fullname protoreflect.FullName = "google.protobuf.Duration.seconds" 27 | Duration_Nanos_field_fullname protoreflect.FullName = "google.protobuf.Duration.nanos" 28 | ) 29 | 30 | // Field numbers for google.protobuf.Duration. 31 | const ( 32 | Duration_Seconds_field_number protoreflect.FieldNumber = 1 33 | Duration_Nanos_field_number protoreflect.FieldNumber = 2 34 | ) 35 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/compact/constants.go: -------------------------------------------------------------------------------- 1 | package compact 2 | 3 | import "github.com/dnovikoff/tempai-core/tile" 4 | 5 | const ( 6 | Man1 Tiles = 1 << iota 7 | Man2 8 | Man3 9 | Man4 10 | Man5 11 | Man6 12 | Man7 13 | Man8 14 | Man9 15 | 16 | Pin1 17 | Pin2 18 | Pin3 19 | Pin4 20 | Pin5 21 | Pin6 22 | Pin7 23 | Pin8 24 | Pin9 25 | 26 | Sou1 27 | Sou2 28 | Sou3 29 | Sou4 30 | Sou5 31 | Sou6 32 | Sou7 33 | Sou8 34 | Sou9 35 | 36 | East 37 | South 38 | West 39 | North 40 | 41 | White 42 | Green 43 | Red 44 | 45 | TileEnd 46 | ) 47 | 48 | const ( 49 | Terminal = Sou1 | Sou9 | Man1 | Man9 | Pin1 | Pin9 50 | Wind = East | South | West | North 51 | Dragon = White | Green | Red 52 | 53 | Man = Man1 | Man2 | Man3 | Man4 | Man5 | Man6 | Man7 | Man8 | Man9 54 | Pin = Pin1 | Pin2 | Pin3 | Pin4 | Pin5 | Pin6 | Pin7 | Pin8 | Pin9 55 | Sou = Sou1 | Sou2 | Sou3 | Sou4 | Sou5 | Sou6 | Sou7 | Sou8 | Sou9 56 | 57 | Sequence = Man | Pin | Sou 58 | 59 | Honor = Wind | Dragon 60 | TerminalOrHonor = Terminal | Honor 61 | 62 | AllTiles = TileEnd - 1 63 | Middle = (AllTiles ^ TerminalOrHonor) & AllTiles 64 | 65 | GreenYakuman = Sou2 | Sou3 | Sou4 | Sou6 | Sou8 | Green 66 | ) 67 | 68 | // 53 is js limit for int64 69 | const _ = uint(53 - tile.TileEnd) 70 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/genid/timestamp_gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Code generated by generate-protos. DO NOT EDIT. 6 | 7 | package genid 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | const File_google_protobuf_timestamp_proto = "google/protobuf/timestamp.proto" 14 | 15 | // Names for google.protobuf.Timestamp. 16 | const ( 17 | Timestamp_message_name protoreflect.Name = "Timestamp" 18 | Timestamp_message_fullname protoreflect.FullName = "google.protobuf.Timestamp" 19 | ) 20 | 21 | // Field names for google.protobuf.Timestamp. 22 | const ( 23 | Timestamp_Seconds_field_name protoreflect.Name = "seconds" 24 | Timestamp_Nanos_field_name protoreflect.Name = "nanos" 25 | 26 | Timestamp_Seconds_field_fullname protoreflect.FullName = "google.protobuf.Timestamp.seconds" 27 | Timestamp_Nanos_field_fullname protoreflect.FullName = "google.protobuf.Timestamp.nanos" 28 | ) 29 | 30 | // Field numbers for google.protobuf.Timestamp. 31 | const ( 32 | Timestamp_Seconds_field_number protoreflect.FieldNumber = 1 33 | Timestamp_Nanos_field_number protoreflect.FieldNumber = 2 34 | ) 35 | -------------------------------------------------------------------------------- /tools/tentool/stats/parse.go: -------------------------------------------------------------------------------- 1 | package stats 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "sort" 7 | "strings" 8 | 9 | yaml "gopkg.in/yaml.v2" 10 | ) 11 | 12 | var reg = regexp.MustCompile(``) 13 | 14 | // ParseMain parses tenhou main page http://tenhou.net/sc/raw/ 15 | // and returns list of year index archives. Like scraw2017.zip 16 | func ParseMain(data string) []string { 17 | sub := reg.FindAllStringSubmatch(data, -1) 18 | res := make([]string, len(sub)) 19 | for k, v := range sub { 20 | res[k] = v[1] 21 | } 22 | sort.Strings(res) 23 | return res 24 | } 25 | 26 | type ListItem struct { 27 | File string `yaml:"file"` 28 | Size int `yaml:"size"` 29 | } 30 | 31 | func MustParseList(data string) []ListItem { 32 | out, err := ParseList(data) 33 | if err != nil { 34 | panic(err) 35 | } 36 | return out 37 | } 38 | 39 | func ParseList(data string) ([]ListItem, error) { 40 | var out []ListItem 41 | first := strings.Index(data, "[") 42 | last := strings.LastIndex(data, "]") 43 | if first == -1 || last == -1 { 44 | return nil, fmt.Errorf("Incorrect string") 45 | } 46 | data = data[first : last+1] 47 | data = strings.Replace(data, ":", ": ", -1) 48 | err := yaml.Unmarshal([]byte(data), &out) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return out, nil 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/rules_predefined.go: -------------------------------------------------------------------------------- 1 | package yaku 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/tile" 5 | ) 6 | 7 | func RulesEMA() *RulesStruct { 8 | return &RulesStruct{ 9 | IsOpenTanyao: true, 10 | IsHaiteiFromLiveOnly: true, 11 | RenhouLimit: LimitMangan, 12 | IsIpatsu: true, 13 | IsUra: true, 14 | IsGreenRequired: false, 15 | IsRinshanFu: true, 16 | } 17 | } 18 | 19 | func RulesJPMPLA() *RulesStruct { 20 | return &RulesStruct{ 21 | IsOpenTanyao: true, 22 | IsHaiteiFromLiveOnly: true, 23 | RenhouLimit: LimitMangan, 24 | IsIpatsu: false, 25 | IsUra: false, 26 | IsGreenRequired: true, 27 | IsRinshanFu: false, 28 | } 29 | } 30 | 31 | func RulesJPMPLB() *RulesStruct { 32 | return RulesEMA() 33 | } 34 | 35 | func RulesTenhouRed() *RulesStruct { 36 | return &RulesStruct{ 37 | IsOpenTanyao: true, 38 | IsHaiteiFromLiveOnly: true, 39 | RenhouLimit: LimitNone, 40 | AkaDoras: []tile.Instance{ 41 | tile.Man5.Instance(0), 42 | tile.Pin5.Instance(0), 43 | tile.Sou5.Instance(0), 44 | }, 45 | IsIpatsu: true, 46 | IsUra: true, 47 | IsGreenRequired: false, 48 | IsRinshanFu: true, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/impl/pointer_unsafe_opaque.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package impl 6 | 7 | import ( 8 | "sync/atomic" 9 | "unsafe" 10 | ) 11 | 12 | func (p pointer) AtomicGetPointer() pointer { 13 | return pointer{p: atomic.LoadPointer((*unsafe.Pointer)(p.p))} 14 | } 15 | 16 | func (p pointer) AtomicSetPointer(v pointer) { 17 | atomic.StorePointer((*unsafe.Pointer)(p.p), v.p) 18 | } 19 | 20 | func (p pointer) AtomicSetNilPointer() { 21 | atomic.StorePointer((*unsafe.Pointer)(p.p), unsafe.Pointer(nil)) 22 | } 23 | 24 | func (p pointer) AtomicSetPointerIfNil(v pointer) pointer { 25 | if atomic.CompareAndSwapPointer((*unsafe.Pointer)(p.p), unsafe.Pointer(nil), v.p) { 26 | return v 27 | } 28 | return pointer{p: atomic.LoadPointer((*unsafe.Pointer)(p.p))} 29 | } 30 | 31 | type atomicV1MessageInfo struct{ p Pointer } 32 | 33 | func (mi *atomicV1MessageInfo) Get() Pointer { 34 | return Pointer(atomic.LoadPointer((*unsafe.Pointer)(&mi.p))) 35 | } 36 | 37 | func (mi *atomicV1MessageInfo) SetIfNil(p Pointer) Pointer { 38 | if atomic.CompareAndSwapPointer((*unsafe.Pointer)(&mi.p), nil, unsafe.Pointer(p)) { 39 | return p 40 | } 41 | return mi.Get() 42 | } 43 | -------------------------------------------------------------------------------- /tools/tentool/logs/parse_test.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "io/ioutil" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestParseIDs(t *testing.T) { 12 | assert.Equal(t, []string{ 13 | "2018092823gm-00a9-0000-2735720b", 14 | "2018092823gm-00a9-0000-3e233540", 15 | "2018092823gm-00a9-0000-445a08e4", 16 | "2018092823gm-00a9-0000-5fc2633e", 17 | "2018092823gm-00a9-0000-64b7a22b", 18 | "2018092823gm-00a9-0000-9b1b0e33", 19 | "2018092823gm-00a9-0000-c10a110c", 20 | "2018092823gm-00b9-0000-a2899a33", 21 | "2018092823gm-00b9-0000-c5512392", 22 | "2018092823gm-00e1-0000-af14e5c0"}, ParseIDs(loadTestData(t, "scc.html"))) 23 | } 24 | 25 | func TestParseIDs2(t *testing.T) { 26 | assert.Equal(t, []string{ 27 | "2018052202gm-0029-0000-4d37104e", 28 | "2018052202gm-0029-0000-5337edec", 29 | "2018052203gm-0029-0000-e57c0825", 30 | }, ParseIDs(` 31 | http://tenhou.net/0/?log=2018052202gm-0029-0000-5337edec&tw=0 32 | http://tenhou.net/0/?log=2018052202gm-0029-0000-4d37104e&tw=2 33 | http://tenhou.net/0/?log=2018052203gm-0029-0000-e57c0825&tw=0 34 | `)) 35 | } 36 | 37 | func loadTestData(t require.TestingT, filename string) string { 38 | data, err := ioutil.ReadFile("test_data/" + filename) 39 | require.NoError(t, err) 40 | return string(data) 41 | } 42 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/descopts/options.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package descopts contains the nil pointers to concrete descriptor options. 6 | // 7 | // This package exists as a form of reverse dependency injection so that certain 8 | // packages (e.g., internal/filedesc and internal/filetype can avoid a direct 9 | // dependency on the descriptor proto package). 10 | package descopts 11 | 12 | import "google.golang.org/protobuf/reflect/protoreflect" 13 | 14 | // These variables are set by the init function in descriptor.pb.go via logic 15 | // in internal/filetype. In other words, so long as the descriptor proto package 16 | // is linked in, these variables will be populated. 17 | // 18 | // Each variable is populated with a nil pointer to the options struct. 19 | var ( 20 | File protoreflect.ProtoMessage 21 | Enum protoreflect.ProtoMessage 22 | EnumValue protoreflect.ProtoMessage 23 | Message protoreflect.ProtoMessage 24 | Field protoreflect.ProtoMessage 25 | Oneof protoreflect.ProtoMessage 26 | ExtensionRange protoreflect.ProtoMessage 27 | Service protoreflect.ProtoMessage 28 | Method protoreflect.ProtoMessage 29 | ) 30 | -------------------------------------------------------------------------------- /vendor/github.com/inconshreveable/mousetrap/trap_windows.go: -------------------------------------------------------------------------------- 1 | package mousetrap 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { 9 | snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) 10 | if err != nil { 11 | return nil, err 12 | } 13 | defer syscall.CloseHandle(snapshot) 14 | var procEntry syscall.ProcessEntry32 15 | procEntry.Size = uint32(unsafe.Sizeof(procEntry)) 16 | if err = syscall.Process32First(snapshot, &procEntry); err != nil { 17 | return nil, err 18 | } 19 | for { 20 | if procEntry.ProcessID == uint32(pid) { 21 | return &procEntry, nil 22 | } 23 | err = syscall.Process32Next(snapshot, &procEntry) 24 | if err != nil { 25 | return nil, err 26 | } 27 | } 28 | } 29 | 30 | // StartedByExplorer returns true if the program was invoked by the user double-clicking 31 | // on the executable from explorer.exe 32 | // 33 | // It is conservative and returns false if any of the internal calls fail. 34 | // It does not guarantee that the program was run from a terminal. It only can tell you 35 | // whether it was launched from explorer.exe 36 | func StartedByExplorer() bool { 37 | pe, err := getProcessEntry(syscall.Getppid()) 38 | if err != nil { 39 | return false 40 | } 41 | return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) 42 | } 43 | -------------------------------------------------------------------------------- /tbase/meld.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/tile" 5 | ) 6 | 7 | type Meld int 8 | type Melds []Meld 9 | type MeldKan Meld 10 | type MeldPon Meld 11 | type MeldChi Meld 12 | 13 | type MeldType int 14 | 15 | const ( 16 | MeldTypeBad MeldType = iota 17 | MeldTypeChi 18 | MeldTypePon 19 | MeldTypeKan 20 | ) 21 | 22 | func (m Meld) Extract(first, last int) int { 23 | shift := uint(16 - last) 24 | mask := 0 25 | for k := first; k < last; k++ { 26 | mask = mask*2 + 1 27 | } 28 | val := int(m>>shift) & mask 29 | return val 30 | } 31 | 32 | func (m Meld) Decode() *Called { 33 | return DecodeCalled(m) 34 | } 35 | 36 | func (m Melds) Decode() CalledList { 37 | x := make(CalledList, len(m)) 38 | for k, v := range m { 39 | x[k] = v.Decode() 40 | } 41 | return x 42 | } 43 | 44 | func (m Meld) Type() MeldType { 45 | if m.Extract(13, 14) == 1 { 46 | return MeldTypeChi 47 | } 48 | if m.Extract(8, 13) == 0 { 49 | return MeldTypeKan 50 | } 51 | return MeldTypePon 52 | } 53 | 54 | func (m Meld) Who() Opponent { 55 | return Opponent(m.Extract(14, 16)) 56 | } 57 | 58 | func (m Meld) Instance(f, l int) tile.Instance { 59 | return tile.Instance(m.Extract(f, l)) 60 | } 61 | 62 | func getBase(base int) tile.Instance { 63 | t := tile.Tile(base/4) + tile.TileBegin 64 | copyId := tile.CopyID(base % 4) 65 | return t.Instance(copyId) 66 | } 67 | -------------------------------------------------------------------------------- /tools/tentool/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | func MakeDirForFile(filename string) error { 10 | dir := filepath.Dir(filename) 11 | return os.MkdirAll(dir, os.ModePerm) 12 | } 13 | 14 | type FileWriter struct { 15 | path string 16 | tmpPath string 17 | file *os.File 18 | } 19 | 20 | var _ io.Writer = &FileWriter{} 21 | 22 | func CreateFile(name string) (*FileWriter, error) { 23 | err := MakeDirForFile(name) 24 | if err != nil { 25 | return nil, err 26 | } 27 | w := &FileWriter{ 28 | path: name, 29 | tmpPath: name + ".tmp", 30 | } 31 | w.file, err = os.Create(w.tmpPath) 32 | if err != nil { 33 | return nil, err 34 | } 35 | return w, nil 36 | } 37 | 38 | func (w *FileWriter) Write(data []byte) (int, error) { 39 | return w.file.Write(data) 40 | } 41 | 42 | func (w *FileWriter) CommitOnSuccess(err *error) { 43 | w.Close() 44 | if *err != nil { 45 | return 46 | } 47 | *err = w.Commit() 48 | } 49 | 50 | func (w *FileWriter) Commit() error { 51 | return os.Rename(w.tmpPath, w.path) 52 | } 53 | 54 | func (w *FileWriter) Close() error { 55 | return w.file.Close() 56 | } 57 | 58 | func FileExists(path string) (bool, error) { 59 | _, err := os.Stat(path) 60 | if err == nil { 61 | return true, nil 62 | } 63 | if os.IsNotExist(err) { 64 | return false, nil 65 | } 66 | return false, err 67 | } 68 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/effective/sort.go: -------------------------------------------------------------------------------- 1 | package effective 2 | 3 | import "github.com/dnovikoff/tempai-core/tile" 4 | 5 | type sSortId uint32 6 | 7 | func newSortId(uCount, tCount, value int) sSortId { 8 | val := (13 - sSortId(value)) 9 | val = (val << 8) | sSortId(uCount) 10 | val = (val << 8) | sSortId(tCount) 11 | 12 | return val 13 | } 14 | 15 | func (id sSortId) betterThan(other sSortId) bool { 16 | return id > other 17 | } 18 | 19 | type ResultsSorted []*Result 20 | 21 | func (r ResultsSorted) Best() *Result { 22 | if len(r) == 0 { 23 | return nil 24 | } 25 | return r[0] 26 | } 27 | 28 | func (r ResultsSorted) Len() int { 29 | return len(r) 30 | } 31 | 32 | func (r ResultsSorted) Swap(i, j int) { 33 | r[i], r[j] = r[j], r[i] 34 | } 35 | 36 | func tileSortId(t tile.Tile) int { 37 | return (tilePriority(t) << 8) | int(t) 38 | } 39 | 40 | func tileLess(l, r tile.Tile) bool { 41 | return tileSortId(l) < tileSortId(r) 42 | } 43 | 44 | func effLess(l, r *Result) bool { 45 | lhs, rhs := l.sortId, r.sortId 46 | if lhs.betterThan(rhs) { 47 | return true 48 | } else if rhs.betterThan(lhs) { 49 | return false 50 | } 51 | return tileLess(l.Tile, r.Tile) 52 | } 53 | 54 | func (r ResultsSorted) Less(i, j int) bool { 55 | return effLess(r[i], r[j]) 56 | } 57 | 58 | func (r ResultsSorted) First() *Result { 59 | if len(r) == 0 { 60 | return nil 61 | } 62 | return r[0] 63 | } 64 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/LICENSE.libyaml: -------------------------------------------------------------------------------- 1 | The following files were ported to Go from C files of libyaml, and thus 2 | are still covered by their original copyright and license: 3 | 4 | apic.go 5 | emitterc.go 6 | parserc.go 7 | readerc.go 8 | scannerc.go 9 | writerc.go 10 | yamlh.go 11 | yamlprivateh.go 12 | 13 | Copyright (c) 2006 Kirill Simonov 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | this software and associated documentation files (the "Software"), to deal in 17 | the Software without restriction, including without limitation the rights to 18 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 19 | of the Software, and to permit persons to whom the Software is furnished to do 20 | so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | -------------------------------------------------------------------------------- /log/info_test.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestLobbyDecode(t *testing.T) { 11 | decode := func(in string) string { 12 | res, err := DecodeLobby(in) 13 | require.NoError(t, err) 14 | return res.DebugString() 15 | } 16 | assert.Equal(t, "AKT4fX", decode("00a1")) 17 | assert.Equal(t, "AKH4fX", decode("00a9")) 18 | assert.Equal(t, "AKT4F0", decode("0841")) 19 | } 20 | 21 | func TestInfoParse(t *testing.T) { 22 | parse := func(in string) string { 23 | ret, err := ParseLogInfo(in) 24 | require.NoError(t, err) 25 | return ret.DebugString() 26 | } 27 | 28 | assert.Equal(t, "[2009-06-18 06:00:00 +0000 UTC][AKT4fX][0][6d13c207]", parse("2009061806gm-00a1-0000-6d13c207")) 29 | assert.Equal(t, "[2009-03-17 02:00:00 +0000 UTC][AKT4fX][0][336ee82a]", parse("00a1/2009/03/17/2009031702gm-00a1-0000-336ee82a.mjlog")) 30 | assert.Equal(t, "[2009-09-15 15:00:00 +0000 UTC][AKH4fX][0][1753da1d]", parse("http://tenhou.net/0/?log=2009091515gm-00a9-0000-1753da1d")) 31 | } 32 | 33 | func TestInfoParsefilename(t *testing.T) { 34 | ret, err := ParseLogInfo("http://tenhou.net/0/?log=2017022002gm-000b-2873-xc0294a92421e&tw=3") 35 | require.NoError(t, err) 36 | assert.Equal(t, "http://tenhou.net/0/?log=2017022002gm-000b-2873-xc0294a92421e", ret.LogUrl) 37 | assert.Equal(t, "https://tenhou.net/0/log/?2017022002gm-000b-2873-fb28df66", ret.XmlUrl) 38 | } 39 | -------------------------------------------------------------------------------- /util/util_test/xml_test.go: -------------------------------------------------------------------------------- 1 | package util_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | 9 | "github.com/dnovikoff/tenhou/parser" 10 | ) 11 | 12 | func TestParseXML(t *testing.T) { 13 | ret, err := parser.ParseXML(``) 14 | require.NoError(t, err) 15 | require.Equal(t, 1, len(ret)) 16 | assert.Equal(t, parser.Node{ 17 | Name: "N", 18 | Attributes: map[string]string{ 19 | "type": "1", 20 | "hai0": "132", 21 | "hai1": "134", 22 | }, 23 | }, ret[0]) 24 | } 25 | 26 | func TestParseXMLList(t *testing.T) { 27 | ret, err := parser.ParseXML(``) 28 | require.NoError(t, err) 29 | assert.Equal(t, parser.Nodes{ 30 | parser.Node{Name: "A"}, 31 | parser.Node{Name: "B"}, 32 | }, ret) 33 | } 34 | 35 | func TestParseXMLStrictCheck(t *testing.T) { 36 | ret, err := parser.ParseXML(``) 37 | require.NoError(t, err) 38 | require.Equal(t, 1, len(ret)) 39 | assert.Equal(t, parser.Node{ 40 | Name: "HELO", 41 | Attributes: map[string]string{ 42 | "ratingscale": "PF3=1.000000&PF4=1.000000&PF01C=0.582222&PF02C=0.501632&PF03C=0.414869&PF11C=0.823386&PF12C=0.709416&PF13C=0.586714&PF23C=0.378722&PF33C=0.535594&PF1C00=8.000000", 43 | }, 44 | }, ret[0]) 45 | } 46 | -------------------------------------------------------------------------------- /tools/tentool/utils/interactive_tracker.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/c2h5oh/datasize" 7 | ) 8 | 9 | type InteractiveTracker struct { 10 | u, p string 11 | total int64 12 | progress int64 13 | interactive bool 14 | w *InteractiveWriter 15 | } 16 | 17 | func NewInteractiveTracker(u, p string, i bool) *InteractiveTracker { 18 | return &InteractiveTracker{u: u, p: p, interactive: i, w: NewInteractiveWriter(os.Stdout)} 19 | } 20 | 21 | func (t *InteractiveTracker) SetPath(p string) { 22 | t.p = p 23 | } 24 | 25 | func (t *InteractiveTracker) Start(total int64) { 26 | t.total = total 27 | t.writeHeader() 28 | } 29 | 30 | func (t *InteractiveTracker) writeHeader() { 31 | if t.p == "" { 32 | t.w.Printf("Downloading %v", t.u) 33 | } else { 34 | t.w.Printf("Downloading %v to %v", t.u, t.p) 35 | } 36 | t.w.Println() 37 | } 38 | 39 | func (t *InteractiveTracker) Write(bytes int) { 40 | if !t.interactive { 41 | return 42 | } 43 | t.progress += int64(bytes) 44 | if t.total == 0 { 45 | t.w.Printf("%v of unknown total size", datasize.ByteSize(t.progress)) 46 | } else { 47 | t.w.Printf("%s/%s (%v%%)", 48 | datasize.ByteSize(t.progress).HumanReadable(), 49 | datasize.ByteSize(t.total).HumanReadable(), 50 | t.progress*100/t.total, 51 | ) 52 | } 53 | } 54 | 55 | func (t *InteractiveTracker) Done(total int64, err error) { 56 | if !t.interactive { 57 | return 58 | } 59 | t.w.Println() 60 | } 61 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/scb.log: -------------------------------------------------------------------------------- 1 | 00:00 | 17 | 三般南喰赤- | petshop(+56.0) NoName(+1.0) 役満役満(-57.0) 2 | 00:00 | 12 | 三特南喰赤- | とらぽ(+56.0) クガツハズカム(-16.0) 古墳(-40.0) 3 | 00:00 | 25 | 四般南喰赤- | m9(-Д-)(+52.0) insigne(+6.0) Rocks12(-24.0) ちっつー(-34.0) 4 | 00:00 | 31 | 四上南喰赤- | beside(+46.0) CAT777(+8.0) 758dagay(-15.0) silveraq(-39.0) 5 | 00:00 | 19 | 三般南喰赤- | シャボーズ(+41.0) 090(-7.0) NoName(-34.0) 6 | 00:00 | 06 | 四上東喰赤- | シエスタ410(+46.0) taiwanco(+3.0) expressJ(-18.0) 佳太郎(-31.0) 7 | 00:00 | 38 | 四特南喰赤- | 荒巻すかる(+51.0) Pin(+8.0) 牢人(-21.0) 名脇役(-38.0) 8 | 00:00 | 33 | 四般南喰赤- | sphinx*(+43.0) NoName(+8.0) kazkum(-17.0) lassi(-34.0) 9 | 00:00 | 08 | 三般南喰赤- | か・す共が(+80.0) Akkari~n(-17.0) NoName(-63.0) 10 | 00:00 | 11 | 三上東喰赤- | deku(+78.0) みらい☆彡(-2.0) akibo528(-76.0) 11 | 00:00 | 05 | 三般東喰赤- | 龍真(+47.0) りんご1529(-8.0) NoName(-39.0) 12 | 00:00 | 16 | 四般東喰赤- | NoName(+43.0) iatw(+7.0) faweff(-18.0) supa-ku(-32.0) 13 | 00:00 | 12 | 四上東喰赤- | どかーん(+65.0) マイヤー(+9.0) hhmmhh(-29.0) lsrlzy(-45.0) 14 | 00:00 | 31 | 四上南喰赤- | らじこ(+42.0) アイガッチャ(+8.0) rt224689(-16.0) lz73(-34.0) 15 | 00:00 | 12 | 四般東--- | 蛍のケイぼん(+55.0) snowmous(+13.0) NoName(-23.0) shirou55(-45.0) 16 | 00:00 | 11 | 四特東喰赤- | 石戸明星(+53.0) ブルーカミカゼ(+9.0) birdman(-15.0) 鮫島(-47.0) 17 | 00:00 | 13 | 三上南喰赤- | バクシン(+80.0) 今日もだめだった(-8.0) p7(-72.0) 18 | 00:00 | 27 | 四般南喰赤- | ほめ777(+49.0) ZaneTrue(+10.0) とよすけ31(-13.0) あぐー(-46.0) 19 | 00:00 | 22 | 四特南喰赤- | 炎炎炎(+47.0) よしぞー(+4.0) Saki-san(-20.0) ふがいないや(-31.0) 20 | 00:00 | 03 | 三般東喰赤- | らおさん(+38.0) Overmind(-9.0) しょうゆん!(-29.0) 21 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/set/ints.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package set provides simple set data structures for uint64s. 6 | package set 7 | 8 | import "math/bits" 9 | 10 | // int64s represents a set of integers within the range of 0..63. 11 | type int64s uint64 12 | 13 | func (bs *int64s) Len() int { 14 | return bits.OnesCount64(uint64(*bs)) 15 | } 16 | func (bs *int64s) Has(n uint64) bool { 17 | return uint64(*bs)&(uint64(1)< 0 18 | } 19 | func (bs *int64s) Set(n uint64) { 20 | *(*uint64)(bs) |= uint64(1) << n 21 | } 22 | func (bs *int64s) Clear(n uint64) { 23 | *(*uint64)(bs) &^= uint64(1) << n 24 | } 25 | 26 | // Ints represents a set of integers within the range of 0..math.MaxUint64. 27 | type Ints struct { 28 | lo int64s 29 | hi map[uint64]struct{} 30 | } 31 | 32 | func (bs *Ints) Len() int { 33 | return bs.lo.Len() + len(bs.hi) 34 | } 35 | func (bs *Ints) Has(n uint64) bool { 36 | if n < 64 { 37 | return bs.lo.Has(n) 38 | } 39 | _, ok := bs.hi[n] 40 | return ok 41 | } 42 | func (bs *Ints) Set(n uint64) { 43 | if n < 64 { 44 | bs.lo.Set(n) 45 | return 46 | } 47 | if bs.hi == nil { 48 | bs.hi = make(map[uint64]struct{}) 49 | } 50 | bs.hi[n] = struct{}{} 51 | } 52 | func (bs *Ints) Clear(n uint64) { 53 | if n < 64 { 54 | bs.lo.Clear(n) 55 | return 56 | } 57 | delete(bs.hi, n) 58 | } 59 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/compact/generator.go: -------------------------------------------------------------------------------- 1 | package compact 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/dnovikoff/tempai-core/tile" 7 | ) 8 | 9 | type Generator struct { 10 | instances Instances 11 | } 12 | 13 | func NewTileGenerator() *Generator { 14 | return &Generator{AllInstances()} 15 | } 16 | 17 | func (g *Generator) TilesLeft() tile.Instances { 18 | return g.instances.Instances() 19 | } 20 | 21 | func (g *Generator) Instance(t tile.Tile) tile.Instance { 22 | m := g.instances.GetMask(t) 23 | if m.IsEmpty() { 24 | return tile.InstanceNull 25 | } 26 | ret := m.First() 27 | g.instances.Remove(ret) 28 | return ret 29 | } 30 | 31 | func (g *Generator) CompactFromString(str string) (Instances, error) { 32 | tiles, err := g.InstancesFromString(str) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return NewInstances().Add(tiles), nil 37 | } 38 | 39 | func (g *Generator) InstancesFromString(str string) (tile.Instances, error) { 40 | tiles, err := tile.NewTilesFromString(str) 41 | if err != nil { 42 | return nil, err 43 | } 44 | ret := g.Tiles(tiles) 45 | if ret == nil { 46 | return nil, errors.New("Incorrect input string") 47 | } 48 | return ret, nil 49 | } 50 | 51 | func (g *Generator) Tiles(tiles tile.Tiles) tile.Instances { 52 | ret := make(tile.Instances, len(tiles)) 53 | for i, t := range tiles { 54 | r := g.Instance(t) 55 | if r == tile.InstanceNull { 56 | return nil 57 | } 58 | ret[i] = r 59 | } 60 | return ret 61 | } 62 | -------------------------------------------------------------------------------- /client/controller.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/dnovikoff/tenhou/tbase" 5 | ) 6 | 7 | type Suggest int 8 | 9 | const ( 10 | SuggestNone Suggest = 0 11 | ) 12 | 13 | const ( 14 | SuggestKan Suggest = 1 << iota 15 | SuggestPon // 2 16 | SuggestChi // 4 17 | SuggestRon // 8 18 | SuggestTsumo // 16 19 | SuggestRiichi // 32 20 | SuggestDraw // 64 21 | SuggetSanmaDora // 128 22 | ) 23 | 24 | func (s Suggest) Check(x Suggest) bool { 25 | return (s & x) == x 26 | } 27 | 28 | type UNController interface { 29 | UserList(UserList) 30 | Reconnect(Reconnect) 31 | } 32 | 33 | // This is how client looks from server's point of view 34 | type Controller interface { 35 | UNController 36 | 37 | Drop(Drop) 38 | Take(Take) 39 | Reach(Reach) 40 | Declare(Declare) 41 | Init(Init) 42 | Reinit(Reinit) 43 | LogInfo(LogInfo) 44 | Go(Go) 45 | Hello(Hello) 46 | 47 | // TODO: research 48 | LobbyStats(LobbyStats) 49 | Agari(tbase.Agari) 50 | Indicator(WithInstance) 51 | // TODO: research add 52 | EndButton(EndButton) 53 | Furiten(Furiten) 54 | Ryuukyoku(tbase.Ryuukyoku) 55 | Rejoin(Rejoin) 56 | Disconnect(WithOpponent) 57 | Chat(Chat) 58 | // TODO: research 59 | Ranking(Ranking) 60 | Recover(Recover) 61 | } 62 | 63 | const DefaultRatingScale = "PF3=1.000000&PF4=1.000000&PF01C=0.582222&PF02C=0.501632&PF03C=0.414869&PF11C=0.823386&PF12C=0.709416&PF13C=0.586714&PF23C=0.378722&PF33C=0.535594&PF1C00=8.000000" 64 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/calc/options.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/compact" 5 | ) 6 | 7 | type Form int 8 | 9 | const ( 10 | Regular Form = 1 << iota 11 | Pairs 12 | Kokushi 13 | ) 14 | 15 | func (f Form) Check(x Form) bool { 16 | return (f & x) == x 17 | } 18 | 19 | type Options struct { 20 | Opened int 21 | Used compact.Instances 22 | Results Results 23 | Declared Melds 24 | Forms Form 25 | 26 | StartMelds Melds 27 | } 28 | 29 | type Option func(*Options) 30 | 31 | func GetOptions(opts ...Option) *Options { 32 | r := Options{ 33 | Forms: Kokushi | Pairs | Regular, 34 | } 35 | for _, opt := range opts { 36 | opt(&r) 37 | } 38 | return &r 39 | } 40 | 41 | func Opened(x int) Option { 42 | return func(c *Options) { 43 | c.Opened = x 44 | } 45 | } 46 | 47 | func Used(x compact.Instances) Option { 48 | return func(c *Options) { 49 | if c.Used == nil { 50 | c.Used = x 51 | } else { 52 | c.Used = c.Used.Merge(x) 53 | } 54 | } 55 | } 56 | 57 | func SetResults(x Results) Option { 58 | return func(c *Options) { 59 | c.Results = x 60 | } 61 | } 62 | 63 | func Declared(melds Melds) Option { 64 | opened := len(melds) 65 | return func(c *Options) { 66 | c.Declared = melds 67 | c.Opened += opened 68 | } 69 | } 70 | 71 | func Forms(x Form) Option { 72 | return func(c *Options) { 73 | c.Forms = x 74 | } 75 | } 76 | 77 | func StartMelds(m Melds) Option { 78 | return func(c *Options) { 79 | c.StartMelds = m 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/scd.log: -------------------------------------------------------------------------------- 1 | 00:02 | 08 | 三若東喰赤祝5 | cruyff(+70.0,+5枚) akahiro(-20.0,-3枚) qzc(-50.0,-2枚) 2 | 00:05 | 09 | 三若東喰赤祝5 | ブルース・リー(+55.0,+2枚) HUNTER(-5.0,-1枚) NoName(-50.0,-1枚) 3 | 00:10 | 02 | 三若東喰赤祝5 | rassunn(+76.0,+4枚) qzc(-5.0,0枚) 福音(-71.0,-4枚) 4 | 00:13 | 06 | 三若東喰赤祝5 | rassunn(+69.0,+2枚) cruyff(-7.0,0枚) ケスラー(-62.0,-2枚) 5 | 00:15 | 05 | 三若東喰赤祝5 | qzc(+51.0,+2枚) HUNTER(-9.0,-1枚) ブルース・リー(-42.0,-1枚) 6 | 00:20 | 05 | 三若東喰赤祝5 | NoName(+65.0,0枚) ケスラー(+7.0,+1枚) cruyff(-72.0,-1枚) 7 | 00:21 | 05 | 三若東喰赤祝5 | qzc(+46.0,-1枚) HUNTER(-5.0,+1枚) asd(-41.0,0枚) 8 | 00:26 | 04 | 三若東喰赤祝5 | ケスラー(+60.0,+1枚) ロトの刀(-3.0,+2枚) asd(-57.0,-3枚) 9 | 00:26 | 05 | 三若東喰赤祝5 | シロウー(+58.0,+13枚) cruyff(+3.0,-4枚) qzc(-61.0,-9枚) 10 | 00:31 | 06 | 三若東喰赤祝5 | ロトの刀(+68.0,+10枚) ケスラー(-16.0,-6枚) No--Name(-52.0,-4枚) 11 | 00:32 | 13 | 三若東喰赤祝5 | cruyff(+82.0,+3枚) シロウー(-4.0,0枚) asd(-78.0,-3枚) 12 | 00:46 | 03 | 三若東喰赤祝5 | ケスラー(+54.0,0枚) ユーダイクス(-3.0,0枚) NoName(-51.0,0枚) 13 | 00:52 | 08 | 三若東喰赤祝5 | ケスラー(+61.0,+4枚) akahiro(-11.0,-3枚) ユーダイクス(-50.0,-1枚) 14 | 00:52 | 04 | 三若東喰赤祝5 | simapuro(+51.0,0枚) itoyan(-4.0,0枚) NoName(-47.0,0枚) 15 | 01:01 | 10 | 三若東喰赤祝5 | ケスラー(+64.0,+1枚) fu-ka(+4.0,+2枚) ユーダイクス(-68.0,-3枚) 16 | 02:35 | 04 | 三若東喰赤祝5 | ロトの刀(+50.0,-1枚) 訓練生ユウ(-6.0,0枚) Ikkey(-44.0,+1枚) 17 | 10:57 | 07 | 三若東喰赤祝5 | 訓練生ユウ(+60.0,+7枚) 藤枝(-9.0,-3枚) ラザニア21(-51.0,-4枚) 18 | 11:06 | 08 | 三若東喰赤祝5 | 藤枝(+91.0,+8枚) 訓練生ユウ(-23.0,-3枚) すべては牌操作(-68.0,-5枚) 19 | 11:15 | 07 | 三若東喰赤祝5 | corius(+93.0,+4枚) モノのじ(-21.0,-2枚) 藤枝(-72.0,-2枚) 20 | 11:22 | 06 | 三若東喰赤祝5 | 藤枝(+50.0,0枚) モノのじ(-9.0,-1枚) 訓練生ユウ(-41.0,+1枚) 21 | -------------------------------------------------------------------------------- /tbase/meld_test.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | import ( 4 | "strconv" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | 9 | "github.com/dnovikoff/tempai-core/tile" 10 | ) 11 | 12 | func TestMeldsBase(t *testing.T) { 13 | for _, v := range []struct { 14 | expected tile.Tile 15 | m Meld 16 | }{ 17 | {tile.North, 46633}, 18 | {tile.White, 47690}, 19 | {tile.Green, 49705}, 20 | } { 21 | t.Run(v.expected.String()+strconv.Itoa(int(v.m)), func(t *testing.T) { 22 | assert.Equal(t, v.expected, v.m.Decode().Core.Tile()) 23 | }) 24 | } 25 | } 26 | 27 | func TestMelds(t *testing.T) { 28 | for _, v := range []struct { 29 | expected string 30 | m Meld 31 | }{ 32 | {"444z Right", 46633}, 33 | {"555z Front", 47690}, 34 | {"666z Right", 49705}, 35 | // Upgraded 36 | {"5555z Front", 47666}, 37 | {"2222m Left", 1539}, 38 | {"1111z Front", 27906}, 39 | {"1111p Right", 9217}, 40 | {"444s Front", 33354}, 41 | } { 42 | t.Run(v.expected, func(t *testing.T) { 43 | d := v.m.Decode() 44 | actual := d.Core.Tiles().String() + " " + d.Opponent.String() 45 | assert.Equal(t, v.expected, actual) 46 | }) 47 | } 48 | } 49 | 50 | func TestMeldsReconvert(t *testing.T) { 51 | for _, v := range []Meld{ 52 | // chi [6]78p 53 | 37199, 54 | 33354, 55 | // Closed green kan with copyId = 1 56 | 33024, 57 | // Closed green kan with copyId = 0 58 | 32768, 59 | } { 60 | t.Run(strconv.Itoa(int(v)), func(t *testing.T) { 61 | assert.Equal(t, v, v.Decode().Encode()) 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/rules.go: -------------------------------------------------------------------------------- 1 | package yaku 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/tile" 5 | ) 6 | 7 | type Rules interface { 8 | OpenTanyao() bool 9 | CheckAka(i tile.Instance) bool 10 | Renhou() Limit 11 | HaiteiFromLiveOnly() bool 12 | Ura() bool 13 | Ipatsu() bool 14 | GreenRequired() bool 15 | RinshanFu() bool 16 | } 17 | 18 | type RulesStruct struct { 19 | IsOpenTanyao bool 20 | AkaDoras []tile.Instance 21 | RenhouLimit Limit 22 | IsHaiteiFromLiveOnly bool 23 | IsUra bool 24 | IsIpatsu bool 25 | IsGreenRequired bool 26 | IsRinshanFu bool 27 | } 28 | 29 | var _ Rules = &RulesStruct{} 30 | 31 | func (r *RulesStruct) GreenRequired() bool { 32 | return r.IsGreenRequired 33 | } 34 | 35 | func (r *RulesStruct) RinshanFu() bool { 36 | return r.IsRinshanFu 37 | } 38 | 39 | func (r *RulesStruct) OpenTanyao() bool { 40 | return r.IsOpenTanyao 41 | } 42 | 43 | func (r *RulesStruct) Renhou() Limit { 44 | return r.RenhouLimit 45 | } 46 | 47 | func (r *RulesStruct) HaiteiFromLiveOnly() bool { 48 | return r.IsHaiteiFromLiveOnly 49 | } 50 | 51 | func (r *RulesStruct) Ura() bool { 52 | return r.IsUra 53 | } 54 | 55 | func (r *RulesStruct) Ipatsu() bool { 56 | return r.IsIpatsu 57 | } 58 | 59 | func (r *RulesStruct) CheckAka(i tile.Instance) bool { 60 | if len(r.AkaDoras) == 0 { 61 | return false 62 | } 63 | for _, v := range r.AkaDoras { 64 | if v == i { 65 | return true 66 | } 67 | } 68 | return false 69 | } 70 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // # Example Usage 4 | // 5 | // The following is a complete example using assert in a standard test function: 6 | // 7 | // import ( 8 | // "testing" 9 | // "github.com/stretchr/testify/assert" 10 | // ) 11 | // 12 | // func TestSomething(t *testing.T) { 13 | // 14 | // var a string = "Hello" 15 | // var b string = "Hello" 16 | // 17 | // assert.Equal(t, a, b, "The two words should be the same.") 18 | // 19 | // } 20 | // 21 | // if you assert many times, use the format below: 22 | // 23 | // import ( 24 | // "testing" 25 | // "github.com/stretchr/testify/assert" 26 | // ) 27 | // 28 | // func TestSomething(t *testing.T) { 29 | // assert := assert.New(t) 30 | // 31 | // var a string = "Hello" 32 | // var b string = "Hello" 33 | // 34 | // assert.Equal(a, b, "The two words should be the same.") 35 | // } 36 | // 37 | // # Assertions 38 | // 39 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 40 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 41 | // testing framework. This allows the assertion funcs to write the failings and other details to 42 | // the correct place. 43 | // 44 | // Every assertion function also takes an optional string message as the final argument, 45 | // allowing custom error messages to be appended to the message the assertion method outputs. 46 | package assert 47 | -------------------------------------------------------------------------------- /log/test_data/example.txt: -------------------------------------------------------------------------------- 1 | http://tenhou.net/0/?log=2016090816gm-0019-0000-c1eeb04f&tw=0 2 | http://e.mjv.jp/0/log/plainfiles.cgi?2016090816gm-0019-0000-c1eeb04f 3 | https://github.com/NegativeMjark/tenhou-log 4 | 5 | 6 | http://tenhou.net/0/?log=2016112620gm-0029-0000-41174e3d&tw=3 7 | http://e.mjv.jp/0/log/plainfiles.cgi?2016112620gm-0029-0000-41174e3d 8 | 9 | 10 | Тестовые данные для исправления ссылок: 11 | http://tenhou.net/0/?log=2017020203gm-000b-2873-e6b557e5&tw=0 12 | http://tenhou.net/0/?log=2017020203gm-000b-2873-x84f6522d33b4&tw=2 13 | http://tenhou.net/0/?log=2017020203gm-000b-2873-xecf8fa3f92ec&tw=3 14 | http://tenhou.net/0/?log=2017020204gm-000b-2873-a1135a18&tw=1 15 | http://tenhou.net/0/?log=2017020204gm-000b-2873-xb0418c5ccc31&tw=2 16 | http://tenhou.net/0/?log=2017020206gm-000b-2873-77e86420&tw=3 17 | http://tenhou.net/0/?log=2017020903gm-000b-2873-86bb1b01&tw=3 18 | http://tenhou.net/0/?log=2017020904gm-000b-2873-d6dd0bce&tw=2 19 | http://tenhou.net/0/?log=2017021603gm-000b-2873-x2f283b1b40bf&tw=0 20 | http://tenhou.net/0/?log=2017021604gm-000b-2873-x530c7852a15e&tw=3 21 | http://tenhou.net/0/?log=2017022002gm-000b-2873-xc0294a92421e&tw=3 22 | http://tenhou.net/0/?log=2017022003gm-000b-2873-xf96d95ed7ca6&tw=1 23 | http://tenhou.net/0/?log=2017022003gm-000b-2873-b6fe8101&tw=3 24 | http://tenhou.net/0/?log=2017022505gm-000b-17959-8f97ed43&tw=3 25 | http://tenhou.net/0/?log=2017022504gm-000b-17959-793cea5a&tw=2 26 | http://tenhou.net/0/?log=2017022503gm-000b-17959-06e70d10&tw=1 27 | http://tenhou.net/0/?log=2017022502gm-000b-17959-28dd0098&tw=0 28 | 29 | -------------------------------------------------------------------------------- /tools/tentool/logs/test_data/scc.html: -------------------------------------------------------------------------------- 1 | 23:00 | 30 | 四鳳南喰赤- | 牌譜 | =Jam(+59.0) とびまこ(+11.0) アル中@テンパ(-14.0) mineral2(-56.0)
2 | 23:01 | 08 | 三鳳南喰赤- | 牌譜 | まじきち(+42.0) しめじん(-4.0) 湾奥アングラー(-38.0)
3 | 23:02 | 28 | 四鳳南喰赤- | 牌譜 | ドジャース(+42.0) tori0612(+9.0) ゆきさん。(-12.0) 4 | たくじろう(-39.0)
5 | 23:03 | 29 | 四鳳南喰赤- | 牌譜 | 鉄稚魚カモ養分(+54.0) sAgaさん(+14.0) 東京電力(-18.0) G.Y.M(-50.0)
6 | 23:05 | 44 | 四鳳南喰赤- | 牌譜 | ち'んぽっぽ(+41.0) 時を刻む唄(+5.0) ほーりー(-16.0)ふたば(-30.0)
7 | 23:05 | 15 | 四鳳東喰赤- | 牌譜 | kiyopin(+40.0) 六分儀ゲンドウ(+5.0) みみず(-15.0) pinpin6(-30.0)
8 | 23:08 | 31 | 四鳳南喰赤- | 牌譜 | salaman(+59.0) \(^o^)/★(+7.0) たがやす(-19.0) めんたんo(-47.0)
9 | 23:09 | 40 | 四鳳南喰赤- | 牌譜 | 嫌んなった(+74.0) 遊び心(+9.0) jijii-e(-31.0) ちょりお(-52.0)
10 | 23:09 | 14 | 三鳳南喰赤- | 牌譜 | テイラーヒル(+66.0) のーし(-12.0) 遙遠的他。(-54.0)
11 | 23:09 | 31 | 四鳳南喰赤- | 牌譜 | フツウの恋の結末(+57.0) fm44(+6.0) akaaka(-26.0) 眼 12 | 科医(-37.0)
-------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/yaku/yakuman_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Yakuman"; DO NOT EDIT. 2 | 3 | package yaku 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[YakumanNone-0] 12 | _ = x[YakumanKokushi-1] 13 | _ = x[YakumanKokushi13-2] 14 | _ = x[YakumanSuukantsu-3] 15 | _ = x[YakumanSuuankou-4] 16 | _ = x[YakumanSuuankouTanki-5] 17 | _ = x[YakumanDaisangen-6] 18 | _ = x[YakumanShousuushi-7] 19 | _ = x[YakumanDaisuushi-8] 20 | _ = x[YakumanRyuuiisou-9] 21 | _ = x[YakumanTsuiisou-10] 22 | _ = x[YakumanChinrouto-11] 23 | _ = x[YakumanChuurenpooto-12] 24 | _ = x[YakumanChuurenpooto9-13] 25 | _ = x[YakumanTenhou-14] 26 | _ = x[YakumanChihou-15] 27 | _ = x[YakumanRenhou-16] 28 | } 29 | 30 | const _Yakuman_name = "YakumanNoneYakumanKokushiYakumanKokushi13YakumanSuukantsuYakumanSuuankouYakumanSuuankouTankiYakumanDaisangenYakumanShousuushiYakumanDaisuushiYakumanRyuuiisouYakumanTsuiisouYakumanChinroutoYakumanChuurenpootoYakumanChuurenpooto9YakumanTenhouYakumanChihouYakumanRenhou" 31 | 32 | var _Yakuman_index = [...]uint16{0, 11, 25, 41, 57, 72, 92, 108, 125, 141, 157, 172, 188, 207, 227, 240, 253, 266} 33 | 34 | func (i Yakuman) String() string { 35 | if i < 0 || i >= Yakuman(len(_Yakuman_index)-1) { 36 | return "Yakuman(" + strconv.FormatInt(int64(i), 10) + ")" 37 | } 38 | return _Yakuman_name[_Yakuman_index[i]:_Yakuman_index[i+1]] 39 | } 40 | -------------------------------------------------------------------------------- /tools/tentool/utils/donwload_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | "time" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestDetectFilename(t *testing.T) { 15 | var handler func(w http.ResponseWriter, req *http.Request) 16 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 17 | handler(w, req) 18 | })) 19 | defer server.Close() 20 | c := server.Client() 21 | d := NewDownloader(Client(c)) 22 | ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 23 | defer cancel() 24 | t.Run("Disposition", func(t *testing.T) { 25 | handler = func(w http.ResponseWriter, req *http.Request) { 26 | w.Header().Set("Content-Disposition", `attachment;filename="foo.png"`) 27 | w.Write([]byte(`Some content`)) 28 | } 29 | filename, err := d.Filename(ctx, server.URL+"/folder/other-folder/bar.jpg") 30 | require.NoError(t, err) 31 | assert.Equal(t, "foo.png", filename) 32 | }) 33 | t.Run("NoDisposition", func(t *testing.T) { 34 | var userAgent string 35 | handler = func(w http.ResponseWriter, req *http.Request) { 36 | userAgent = req.UserAgent() 37 | w.Write([]byte(`Some content`)) 38 | } 39 | filename, err := d.Filename(ctx, server.URL+"/folder/other-folder/bar.jpg") 40 | require.NoError(t, err) 41 | assert.Equal(t, "bar.jpg", filename) 42 | assert.Equal(t, "TenToolBot (+https://github.com/dnovikoff/tenhou/tools/tentool)", userAgent) 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/calc/meld_kokushi.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | import ( 4 | "sort" 5 | 6 | "github.com/dnovikoff/tempai-core/compact" 7 | "github.com/dnovikoff/tempai-core/tile" 8 | ) 9 | 10 | type kokushi struct { 11 | meld 12 | hole tile.Tile 13 | } 14 | 15 | var kokushi13waits = compact.TerminalOrHonor.Tiles() 16 | 17 | var kokushi13meld = &kokushi{meld{ 18 | tags: TagKoksuhi13 | TagKokushi, 19 | waits: kokushi13waits, 20 | cwaits: compact.TerminalOrHonor, 21 | tiles: kokushi13waits, 22 | }, tile.TileNull} 23 | 24 | func KokushiComplete(p tile.Tile) Meld { 25 | hand := kokushi13waits.Clone() 26 | hand = append(hand, p) 27 | sort.Sort(hand) 28 | return &kokushi{meld{ 29 | t: p, 30 | tags: TagKokushi | TagComplete, 31 | tiles: hand, 32 | }, tile.TileNull} 33 | } 34 | 35 | func Kokushi13() Meld { 36 | return kokushi13meld 37 | } 38 | 39 | func KokushiMeld(pair tile.Tile, wait tile.Tile) Meld { 40 | x := kokushi13waits.Clone() 41 | for k, v := range x { 42 | if v == wait { 43 | x[k] = pair 44 | } 45 | } 46 | sort.Sort(x) 47 | return &kokushi{meld{ 48 | tags: TagKokushi, 49 | waits: tile.Tiles{wait}, 50 | cwaits: compact.FromTile(wait), 51 | t: pair, 52 | tiles: x, 53 | }, wait} 54 | } 55 | 56 | func (*kokushi) Extract(Counters) bool { 57 | panic("kokushi.Extract not implemented") 58 | } 59 | 60 | func (k *kokushi) Complete(t tile.Tile) Meld { 61 | if !k.cwaits.Check(t) { 62 | return nil 63 | } 64 | if k.hole == t { 65 | return KokushiComplete(k.t) 66 | } 67 | return KokushiComplete(t) 68 | } 69 | -------------------------------------------------------------------------------- /parser/agari.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/dnovikoff/tempai-core/score" 7 | "github.com/dnovikoff/tempai-core/yaku" 8 | "github.com/dnovikoff/tenhou/tbase" 9 | ) 10 | 11 | func ParseAgari(node *Node) (result *tbase.Agari, err error) { 12 | agari := &tbase.Agari{} 13 | agari.Who = node.GetWho() 14 | agari.Status, err = node.GetTableStatus() 15 | if err != nil { 16 | return 17 | } 18 | agari.From = node.GetOpponent("fromWho") 19 | if node.Check("paoWho") { 20 | x := node.GetOpponent("paoWho") 21 | agari.Pao = &x 22 | } 23 | ints := node.IntList("ten") 24 | if len(ints) != 3 { 25 | err = fmt.Errorf("ten length for agari should be 3 != %v", len(ints)) 26 | return 27 | } 28 | agari.Score = tbase.Score{ 29 | yaku.FuPoints(ints[0]), 30 | score.Money(ints[1]), 31 | score.RiichiSticks(ints[2])} 32 | agari.Changes = node.GetScoreChanges() 33 | agari.Hand = node.GetHai("hai") 34 | agari.DoraIndicators = node.GetHai("doraHai") 35 | agari.UraIndicators = node.GetHai("doraHaiUra") 36 | 37 | agari.WinTile = node.GetInstance("machi") 38 | agari.FinalScores = node.GetFinalScores() 39 | 40 | agari.Yakumans = tbase.YakumansFromInts(node.IntList("yakuman")) 41 | agari.Yakus = tbase.YakusFromInts(node.IntList("yaku")) 42 | 43 | ints = node.IntList("m") 44 | if len(ints) > 0 { 45 | melds := make(tbase.Melds, len(ints)) 46 | for k, v := range ints { 47 | melds[k] = tbase.Meld(v) 48 | } 49 | agari.Melds = melds 50 | } 51 | agari.Ratio = node.String("ratio") 52 | agari.Chips = node.IntList("chip") 53 | result = agari 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /cmd/pimboo-server/game/player.go: -------------------------------------------------------------------------------- 1 | package game 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/compact" 5 | "github.com/dnovikoff/tempai-core/hand/calc" 6 | "github.com/dnovikoff/tempai-core/hand/tempai" 7 | "github.com/dnovikoff/tempai-core/score" 8 | "github.com/dnovikoff/tempai-core/tile" 9 | "github.com/dnovikoff/tempai-core/yaku" 10 | "github.com/dnovikoff/tenhou/tbase" 11 | ) 12 | 13 | type Player struct { 14 | Hand compact.Instances 15 | Melds tbase.CalledList 16 | Discard compact.Instances 17 | Score score.Money 18 | tempai *tempai.TempaiResults 19 | furiten bool 20 | first bool 21 | } 22 | 23 | func NewPlayer(x score.Money) *Player { 24 | return &Player{Score: x} 25 | } 26 | 27 | func (p *Player) Waits() compact.Tiles { 28 | return tempai.GetWaits(p.tempai) 29 | } 30 | 31 | func (p *Player) update() { 32 | p.tempai = tempai.Calculate(p.Hand, calc.Declared(p.Melds.Core())) 33 | 34 | checker := p.Discard.UniqueTiles() 35 | p.furiten = (checker & p.Waits()) != 0 36 | } 37 | 38 | func (p *Player) win(ctx *yaku.Context) *yaku.Result { 39 | ctx.IsFirstTake = p.first 40 | ctx.Rules = rules 41 | return yaku.Win(p.tempai, ctx, nil) 42 | } 43 | 44 | func (p *Player) drop(t tile.Instance) { 45 | p.first = false 46 | p.Hand.Remove(t) 47 | p.Discard.Set(t) 48 | p.update() 49 | } 50 | 51 | func (p *Player) take(t tile.Instance) bool { 52 | p.Hand.Set(t) 53 | return p.Waits().Check(t.Tile()) 54 | } 55 | 56 | func (p *Player) Init(hand compact.Instances) { 57 | p.Hand = hand 58 | p.Melds = nil 59 | p.first = true 60 | p.Discard = compact.NewInstances() 61 | p.update() 62 | } 63 | -------------------------------------------------------------------------------- /tbase/lobby.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | type LobbyRules int 9 | 10 | const ( 11 | FlagOnline LobbyRules = 1 << iota 12 | FlagNoAkkas 13 | FlagNoKuitan 14 | FlagHanchan 15 | Flag3Man 16 | FlagDan1 17 | FlagFast 18 | FlagDan2 19 | FlagEnd 20 | ) 21 | 22 | const ( 23 | MaskDanAll LobbyRules = FlagDan1 | FlagDan2 24 | MaskDanKu LobbyRules = 0 25 | MaskDan1 = FlagDan1 26 | MaskDan2 = FlagDan2 27 | MaskDanPhoenix = MaskDan1 | MaskDan2 28 | 29 | RulesDzjanso LobbyRules = 0x0841 30 | ) 31 | 32 | func (r LobbyRules) Extract(mask LobbyRules) LobbyRules { 33 | return r & mask 34 | } 35 | 36 | func (r LobbyRules) Check(f LobbyRules) bool { 37 | return (f & r) == f 38 | } 39 | 40 | func (r LobbyRules) String() string { 41 | return fmt.Sprintf("%04x", int(r)) 42 | } 43 | 44 | func (r LobbyRules) DebugString() string { 45 | buf := &bytes.Buffer{} 46 | w := func(x LobbyRules, t string, f string) { 47 | if r.Check(x) { 48 | fmt.Fprint(buf, t) 49 | } else { 50 | fmt.Fprint(buf, f) 51 | } 52 | } 53 | w(FlagNoAkkas, "a", "A") 54 | w(FlagNoKuitan, "k", "K") 55 | w(FlagHanchan, "H", "T") 56 | w(Flag3Man, "3", "4") 57 | w(FlagFast, "F", "f") 58 | dan := r.Extract(MaskDanAll) 59 | switch dan { 60 | case MaskDanKu: 61 | fmt.Fprintf(buf, "0") 62 | case MaskDan1: 63 | fmt.Fprintf(buf, "D") 64 | case MaskDan2: 65 | fmt.Fprintf(buf, "U") 66 | case MaskDanPhoenix: 67 | fmt.Fprintf(buf, "X") 68 | default: 69 | fmt.Fprintf(buf, "[Strange value %b]", dan) 70 | } 71 | return string(buf.Bytes()) 72 | } 73 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/encoding/text/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package text implements the text format for protocol buffers. 6 | // This package has no semantic understanding for protocol buffers and is only 7 | // a parser and composer for the format. 8 | // 9 | // There is no formal specification for the protobuf text format, as such the 10 | // C++ implementation (see google::protobuf::TextFormat) is the reference 11 | // implementation of the text format. 12 | // 13 | // This package is neither a superset nor a subset of the C++ implementation. 14 | // This implementation permits a more liberal grammar in some cases to be 15 | // backwards compatible with the historical Go implementation. 16 | // Future parsings unique to Go should not be added. 17 | // Some grammars allowed by the C++ implementation are deliberately 18 | // not implemented here because they are considered a bug by the protobuf team 19 | // and should not be replicated. 20 | // 21 | // The Go implementation should implement a sufficient amount of the C++ 22 | // grammar such that the default text serialization by C++ can be parsed by Go. 23 | // However, just because the C++ parser accepts some input does not mean that 24 | // the Go implementation should as well. 25 | // 26 | // The text format is almost a superset of JSON except: 27 | // - message keys are not quoted strings, but identifiers 28 | // - the top-level value must be a message without the delimiters 29 | package text 30 | -------------------------------------------------------------------------------- /parser/node_reader.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "sync" 7 | ) 8 | 9 | type readResult struct { 10 | node Node 11 | err error 12 | } 13 | 14 | type NodeReader struct { 15 | resultCh chan readResult 16 | ReadCallback func(context.Context) (string, error) 17 | } 18 | 19 | func NewNodeReader() *NodeReader { 20 | ch := make(chan readResult) 21 | // Create with closed channel for correct errors 22 | close(ch) 23 | return &NodeReader{resultCh: ch} 24 | 25 | } 26 | 27 | func (r *NodeReader) run(ctx context.Context) { 28 | ctx, cancel := context.WithCancel(ctx) 29 | defer func() { 30 | cancel() 31 | close(r.resultCh) 32 | }() 33 | for { 34 | message, err := r.ReadCallback(ctx) 35 | if err != nil { 36 | r.resultCh <- readResult{err: err} 37 | return 38 | } 39 | select { 40 | case <-ctx.Done(): 41 | return 42 | default: 43 | } 44 | nodes, err := ParseXML(message) 45 | if err != nil { 46 | r.resultCh <- readResult{err: err} 47 | return 48 | } 49 | for _, v := range nodes { 50 | r.resultCh <- readResult{v, nil} 51 | } 52 | } 53 | } 54 | 55 | func (r *NodeReader) Start(ctx context.Context) func() { 56 | r.resultCh = make(chan readResult, 1024) 57 | var wg sync.WaitGroup 58 | wg.Add(1) 59 | go func() { 60 | r.run(ctx) 61 | wg.Done() 62 | }() 63 | return wg.Wait 64 | } 65 | 66 | func (r *NodeReader) Next() (node *Node, err error) { 67 | res, ok := <-r.resultCh 68 | if !ok { 69 | err = errors.New("NodeReader stopped") 70 | return 71 | } 72 | if res.err != nil { 73 | err = res.err 74 | return 75 | } 76 | node = &res.node 77 | return 78 | } 79 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/proto/proto.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package proto 6 | 7 | import ( 8 | "google.golang.org/protobuf/internal/errors" 9 | "google.golang.org/protobuf/reflect/protoreflect" 10 | ) 11 | 12 | // Message is the top-level interface that all messages must implement. 13 | // It provides access to a reflective view of a message. 14 | // Any implementation of this interface may be used with all functions in the 15 | // protobuf module that accept a Message, except where otherwise specified. 16 | // 17 | // This is the v2 interface definition for protobuf messages. 18 | // The v1 interface definition is [github.com/golang/protobuf/proto.Message]. 19 | // 20 | // - To convert a v1 message to a v2 message, 21 | // use [google.golang.org/protobuf/protoadapt.MessageV2Of]. 22 | // - To convert a v2 message to a v1 message, 23 | // use [google.golang.org/protobuf/protoadapt.MessageV1Of]. 24 | type Message = protoreflect.ProtoMessage 25 | 26 | // Error matches all errors produced by packages in the protobuf module 27 | // according to [errors.Is]. 28 | // 29 | // Example usage: 30 | // 31 | // if errors.Is(err, proto.Error) { ... } 32 | var Error error 33 | 34 | func init() { 35 | Error = errors.Error 36 | } 37 | 38 | // MessageName returns the full name of m. 39 | // If m is nil, it returns an empty string. 40 | func MessageName(m Message) protoreflect.FullName { 41 | if m == nil { 42 | return "" 43 | } 44 | return m.ProtoReflect().Descriptor().FullName() 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stack/license: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For stack software 4 | 5 | Copyright (c) 2015, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/.golangci.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2023 The Cobra Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | run: 16 | deadline: 5m 17 | 18 | linters: 19 | disable-all: true 20 | enable: 21 | #- bodyclose 22 | # - deadcode ! deprecated since v1.49.0; replaced by 'unused' 23 | #- depguard 24 | #- dogsled 25 | #- dupl 26 | - errcheck 27 | #- exhaustive 28 | #- funlen 29 | #- gochecknoinits 30 | - goconst 31 | - gocritic 32 | #- gocyclo 33 | - gofmt 34 | - goimports 35 | #- gomnd 36 | #- goprintffuncname 37 | - gosec 38 | - gosimple 39 | - govet 40 | - ineffassign 41 | #- lll 42 | - misspell 43 | #- nakedret 44 | #- noctx 45 | - nolintlint 46 | #- rowserrcheck 47 | #- scopelint 48 | - staticcheck 49 | #- structcheck ! deprecated since v1.49.0; replaced by 'unused' 50 | - stylecheck 51 | #- typecheck 52 | - unconvert 53 | #- unparam 54 | - unused 55 | # - varcheck ! deprecated since v1.49.0; replaced by 'unused' 56 | #- whitespace 57 | fast: false 58 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Alex Ogier. All rights reserved. 2 | Copyright (c) 2012 The Go Authors. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /protoc.mk: -------------------------------------------------------------------------------- 1 | protoc_version := 30.2 2 | protoc_dir := gobin/protoc/v$(protoc_version) 3 | protoc_bin := $(protoc_dir)/bin/protoc 4 | protoc_gen_go := gobin/protoc-gen-go 5 | 6 | ifeq ($(OS),Windows_NT) 7 | protoc_bin := $(protoc_bin).exe 8 | ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) 9 | protocarch := win64 10 | else 11 | protocarch := win32 12 | endif 13 | else 14 | uname_s := $(shell uname) 15 | uname_m := $(shell uname -m) 16 | ifeq ($(uname_s),Linux) 17 | pos := linux 18 | else ifeq ($(uname_s),Darwin) 19 | pos := osx 20 | else 21 | $(error Unknown os $(uname_s)) 22 | endif 23 | ifeq ($(uname_m),x86_64) 24 | protocarch := $(pos)-x86_64 25 | else 26 | protocarch := $(pos)-x86_32 27 | endif 28 | endif 29 | 30 | protoc_include := $(protoc_dir)/include 31 | protoc_zip_name := protoc-$(protoc_version)-$(protocarch).zip 32 | protoc_url := https://github.com/google/protobuf/releases/download/v$(protoc_version)/$(protoc_zip_name) 33 | protoc_zip_output := gobin/$(protoc_zip_name) 34 | 35 | $(protoc_bin): 36 | rm -rf $(protoc_dir) 37 | mkdir -p $(protoc_dir) 38 | curl --retry 5 -L $(protoc_url) -o $(protoc_zip_output) 39 | unzip $(protoc_zip_output) -d $(protoc_dir) 40 | rm $(protoc_zip_output) 41 | touch $(protoc_bin) # override time from zip 42 | 43 | # Ignore timestamp 44 | protoc-bin: | $(protoc_bin) 45 | 46 | $(protoc_gen_go): $(protoc_bin) 47 | go build -mod vendor -o $@ ./vendor/github.com/golang/protobuf/protoc-gen-go 48 | 49 | protoc_cmd := $(protoc_bin) -I $(protoc_include) -I ./proto 50 | protoc_go_cmd := $(protoc_cmd) --plugin=protoc-gen-go=$(protoc_gen_go) 51 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stackerr/license: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For stackerr software 4 | 5 | Copyright (c) 2015, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /parser/xml.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "encoding/xml" 5 | 6 | "github.com/facebookgo/stackerr" 7 | 8 | "github.com/dnovikoff/tenhou/tbase" 9 | ) 10 | 11 | type Nodes []Node 12 | 13 | type Root struct { 14 | XMLName xml.Name `xml:"mjloggm"` 15 | Nodes Nodes `xml:",any"` 16 | } 17 | 18 | func (node *Node) GetInit() (x tbase.Init, err error) { 19 | x.Seed, err = ParseSeed(node.String("seed")) 20 | if err != nil { 21 | return 22 | } 23 | x.Dealer = node.GetDealer() 24 | x.Scores = node.GetScores() 25 | x.Chip = node.IntList("chip") 26 | return 27 | } 28 | 29 | func ParseRyuukyoku(node *Node) (r *tbase.Ryuukyoku, err error) { 30 | t := node.String("type") 31 | dt := tbase.DrawMap[t] 32 | if dt == tbase.DrawUnknown { 33 | err = stackerr.Newf("Unknown draw type '%s'", t) 34 | return 35 | } 36 | status, err := node.GetTableStatus() 37 | if err != nil { 38 | return 39 | } 40 | r = &tbase.Ryuukyoku{} 41 | r.ScoreChanges = node.GetScoreChanges() 42 | r.Hands = node.GetHands() 43 | r.Finals = node.GetFinalScores() 44 | r.TableStatus = status 45 | r.DrawType = dt 46 | r.Ratio = node.IntList("ratio") 47 | return 48 | } 49 | 50 | func (node *Node) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 51 | t, err := d.Token() 52 | if err != nil { 53 | return err 54 | } 55 | switch t.(type) { 56 | case xml.EndElement: 57 | default: 58 | return stackerr.Newf("Unexpected element %v", t) 59 | } 60 | 61 | node.Name = start.Name.Local 62 | attrs := make(map[string]string, len(start.Attr)) 63 | for _, x := range start.Attr { 64 | attrs[x.Name.Local] = x.Value 65 | } 66 | node.Attributes = attrs 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/calc/melds.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/tile" 5 | ) 6 | 7 | type Melds []Meld 8 | 9 | func (m Melds) Clone() Melds { 10 | x := make(Melds, len(m)) 11 | for k, v := range m { 12 | x[k] = v 13 | } 14 | return x 15 | } 16 | 17 | func createAllPon() Melds { 18 | x := make(Melds, 0, tile.TileCount) 19 | for i := tile.TileBegin; i < tile.TileEnd; i++ { 20 | x = append(x, Pon(i)) 21 | } 22 | return x 23 | } 24 | 25 | func createAllPonParts() Melds { 26 | x := make(Melds, 0, tile.TileCount) 27 | for i := tile.TileBegin; i < tile.TileEnd; i++ { 28 | x = append(x, PonPart(i)) 29 | } 30 | return x 31 | } 32 | 33 | func createAllChi() Melds { 34 | x := make(Melds, 0, int(tile.SequenceEnd-tile.SequenceBegin)) 35 | for i := tile.SequenceBegin; i < tile.SequenceEnd; i++ { 36 | c := Chi(i) 37 | if c == nil { 38 | continue 39 | } 40 | x = append(x, c) 41 | } 42 | return x 43 | } 44 | 45 | func createAllChiParts() Melds { 46 | x := make(Melds, 0, int(tile.SequenceEnd-tile.SequenceBegin)*3) 47 | for i := tile.SequenceBegin; i < tile.SequenceEnd; i++ { 48 | m := ChiPart1(i) 49 | if m != nil { 50 | x = append(x, m) 51 | } 52 | m = ChiPart2(i) 53 | if m != nil { 54 | x = append(x, m) 55 | } 56 | } 57 | return x 58 | } 59 | 60 | func CreateComplete() Melds { 61 | return append(createAllChi(), 62 | createAllPon()...) 63 | } 64 | 65 | func CreateParts() Melds { 66 | return append( 67 | createAllChiParts(), 68 | createAllPonParts()...) 69 | } 70 | 71 | func CreateAll() Melds { 72 | return append( 73 | CreateParts(), 74 | CreateComplete()...) 75 | } 76 | -------------------------------------------------------------------------------- /tools/tentool/utils/scheduler.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | type Task interface { 4 | // Called on one of worker routine 5 | Run() error 6 | // Called on single routine 7 | Save(blocked bool) error 8 | } 9 | 10 | type Scheduler struct { 11 | routines Routines 12 | bgRoutines Routines 13 | tasks chan Task 14 | save chan Task 15 | } 16 | 17 | func (s *Scheduler) Start(cnt, saveSize int) { 18 | s.tasks = make(chan Task, cnt) 19 | s.save = make(chan Task, saveSize) 20 | for i := 0; i < cnt; i++ { 21 | s.routines.Start(func() error { 22 | for t := range s.tasks { 23 | err := t.Run() 24 | if err != nil { 25 | return err 26 | } 27 | } 28 | return nil 29 | }) 30 | } 31 | s.bgRoutines.Start(s.saveRoutine) 32 | } 33 | 34 | func (s *Scheduler) saveRoutine() error { 35 | for { 36 | t, blocked := s.readForSave() 37 | if t == nil { 38 | return nil 39 | } 40 | err := t.Save(blocked) 41 | if err != nil { 42 | return err 43 | } 44 | } 45 | return nil 46 | } 47 | 48 | func (s *Scheduler) readForSave() (Task, bool) { 49 | var t Task 50 | blocked := false 51 | select { 52 | case t = <-s.save: 53 | default: 54 | t = <-s.save 55 | blocked = true 56 | } 57 | return t, blocked 58 | } 59 | 60 | func (s *Scheduler) Stop() error { 61 | close(s.tasks) 62 | err := s.routines.Wait() 63 | close(s.save) 64 | bgErr := s.bgRoutines.Wait() 65 | if err != nil { 66 | return err 67 | } 68 | return bgErr 69 | } 70 | 71 | func (s *Scheduler) Push(t Task) { 72 | s.tasks <- t 73 | } 74 | 75 | func (s *Scheduler) Error() error { 76 | err := s.routines.Error() 77 | if err != nil { 78 | return err 79 | } 80 | return s.bgRoutines.Error() 81 | } 82 | -------------------------------------------------------------------------------- /tools/tentool/stats/index.go: -------------------------------------------------------------------------------- 1 | package stats 2 | 3 | import ( 4 | "os" 5 | "sort" 6 | 7 | "go.uber.org/multierr" 8 | 9 | "github.com/dnovikoff/tenhou/tools/tentool/utils" 10 | ) 11 | 12 | type FileIndex struct { 13 | utils.JSONGZFile 14 | data map[string]string 15 | } 16 | 17 | func NewFileIndex(p string) *FileIndex { 18 | x := &FileIndex{data: map[string]string{}} 19 | x.Path = p 20 | return x 21 | } 22 | 23 | func (i *FileIndex) Load() error { 24 | return i.JSONGZFile.Load(&i.data) 25 | } 26 | 27 | func (i *FileIndex) Save() (err error) { 28 | return i.JSONGZFile.Save(i.data) 29 | } 30 | 31 | func (i *FileIndex) JustAdd(url, path string) { 32 | i.data[url] = path 33 | } 34 | 35 | func (i *FileIndex) Add(url, path string) error { 36 | i.JustAdd(url, path) 37 | return i.Save() 38 | } 39 | 40 | func (i *FileIndex) Check(url string) bool { 41 | _, found := i.data[url] 42 | return found 43 | } 44 | 45 | func (i *FileIndex) Len() int { 46 | return len(i.data) 47 | } 48 | 49 | func (i *FileIndex) Files() []string { 50 | out := make([]string, 0, len(i.data)) 51 | for _, v := range i.data { 52 | out = append(out, v) 53 | } 54 | sort.Strings(out) 55 | return out 56 | } 57 | 58 | func (i *FileIndex) Validate() error { 59 | var total error 60 | checked := make(map[string]bool, len(i.data)) 61 | for k, v := range i.data { 62 | found, ok := checked[v] 63 | if !ok { 64 | _, err := os.Stat(v) 65 | if err != nil { 66 | total = multierr.Append(total, err) 67 | checked[v] = false 68 | found = false 69 | } else { 70 | checked[v] = true 71 | found = true 72 | } 73 | } 74 | if !found { 75 | delete(i.data, k) 76 | } 77 | } 78 | return total 79 | } 80 | -------------------------------------------------------------------------------- /network/xml_connection.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "errors" 7 | "io" 8 | "net" 9 | "strings" 10 | ) 11 | 12 | const terminator = byte(0) 13 | 14 | type XMLConnection interface { 15 | io.Closer 16 | Read(context.Context) (string, error) 17 | Write(context.Context, string) error 18 | } 19 | 20 | type xmlConnection struct { 21 | impl net.Conn 22 | reader *bufio.Reader 23 | } 24 | 25 | var _ XMLConnection = &xmlConnection{} 26 | 27 | func NewXMLConnection(impl net.Conn) *xmlConnection { 28 | return &xmlConnection{ 29 | impl: impl, 30 | reader: bufio.NewReader(impl), 31 | } 32 | } 33 | 34 | // Not thread safe 35 | func (c *xmlConnection) Read(ctx context.Context) (str string, err error) { 36 | type result struct { 37 | str string 38 | err error 39 | } 40 | ch := make(chan *result, 1) 41 | go func() { 42 | var r result 43 | r.str, r.err = c.reader.ReadString(terminator) 44 | r.str = strings.TrimRight(r.str, string([]byte{terminator})) 45 | ch <- &r 46 | }() 47 | select { 48 | case <-ctx.Done(): 49 | err = errors.New("Read timeout exceded") 50 | c.impl.Close() 51 | case r := <-ch: 52 | str, err = r.str, r.err 53 | } 54 | return 55 | } 56 | 57 | func (c *xmlConnection) Close() error { 58 | return c.impl.Close() 59 | } 60 | 61 | // Not thread safe 62 | func (c *xmlConnection) Write(ctx context.Context, str string) (err error) { 63 | ch := make(chan error, 1) 64 | go func() { 65 | _, writeError := c.impl.Write(append([]byte(str), terminator)) 66 | ch <- writeError 67 | }() 68 | select { 69 | case <-ctx.Done(): 70 | err = errors.New("Write timeout exceded") 71 | c.impl.Close() 72 | case err = <-ch: 73 | } 74 | return 75 | } 76 | -------------------------------------------------------------------------------- /tools/tentool/stats/test_data/sce.log: -------------------------------------------------------------------------------- 1 | 00:10 | 02 | 四技-喰赤- | 牌譜 | DERESUKE(+3.7) 放銃王4(-0.7) 豪雪地帯(-1.3) 〓アナスタシア〓(-1.7)
2 | 00:13 | 01 | 四技-喰赤- | 牌譜 | 豪雪地帯(+8.0) 放銃王4(0.0) 〓アナスタシア〓(0.0) DERESUKE(-8.0)
3 | 00:14 | 01 | 四技-喰赤- | 牌譜 | 豪雪地帯(+1.5) DERESUKE(0.0) 〓アナスタシア〓(0.0) 放銃王4(-1.5)
4 | 00:16 | 01 | 四技-喰赤- | 牌譜 | 豪雪地帯(+18.0) DERESUKE(0.0) 放銃王4(0.0) 〓アナスタシア〓(-18.0)
5 | 00:18 | 03 | 四技-喰赤- | 牌譜 | 豪雪地帯(+3.0) 〓アナスタシア〓(-1.0) DERESUKE(-1.0) 放銃王4(-1.0)
6 | 00:21 | 01 | 四技-喰赤- | 牌譜 | 初心者です(+2.6) 〓アナスタシア〓(0.0) 放銃王4(0.0) DERESUKE(-2.6)
7 | 00:23 | 02 | 四技-喰赤- | 牌譜 | 〓アナスタシア〓(+1.3) 放銃王4(0.0) DERESUKE(0.0) 初心者です(-1.3)
8 | 00:26 | 02 | 四技-喰赤- | 牌譜 | 〓アナスタシア〓(+2.9) 放銃王4(0.0) 初心者です(0.0) DERESUKE(-2.9)
9 | 00:28 | 01 | 四技-喰赤- | 牌譜 | 〓アナスタシア〓(+2.9) DERESUKE(0.0) 初心者です(0.0) 放銃王4(-2.9)
10 | 00:29 | 02 | 四技-喰赤- | 牌譜 | 〓アナスタシア〓(+8.7) DERESUKE(0.0) 放銃王4(0.0) 初心者です(-8.7)
11 | 00:33 | 01 | 四技-喰赤- | 牌譜 | ライジンファイト(+2.6) みやこん10歳(0.0) DERESUKE(0.0) 〓アナスタシア〓(-2.6)
-------------------------------------------------------------------------------- /network/examples/second.log: -------------------------------------------------------------------------------- 1 | Send: 2 | Get: 3 | Send: 4 | Get: 5 | Get: 6 | Send: 7 | Get: 8 | Get: 9 | Get: 10 | Get: 11 | Send: 12 | Get: 13 | Get: 14 | Get: 15 | Get: 16 | Get: 17 | Send: 18 | Get: 19 | Get: 20 | Get: 21 | Get: 22 | Send: 23 | Get: 24 | Get: 25 | Get: 26 | Get: 27 | Send: 28 | Get: 29 | Send: 30 | Get: 31 | Get: 32 | Get: 33 | Get: 34 | Send: 35 | Get: 36 | Get: 37 | Get: 38 | Get: 39 | Get: 40 | Get: 41 | Send: 42 | Get: 43 | Get: 44 | Get: 45 | Get: 46 | Get: 47 | Get: 48 | Get: 49 | Send: -------------------------------------------------------------------------------- /tbase/meld_encode.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/dnovikoff/tempai-core/tile" 7 | ) 8 | 9 | func EncodeCalled(in *Called) Meld { 10 | switch in.Type { 11 | case Kan, ClosedKan: 12 | return encodeKan(in) 13 | case Pon, UpgrdedKan: 14 | return encodeSame(in) 15 | case Chi: 16 | return encodeChi(in) 17 | } 18 | panic(fmt.Sprintf("Unexpected type %v", in.Type)) 19 | } 20 | 21 | func EncodeCalledList(in CalledList) Melds { 22 | x := make(Melds, len(in)) 23 | for k, v := range in { 24 | x[k] = EncodeCalled(v) 25 | } 26 | return x 27 | } 28 | 29 | func encodeSame(in *Called) Meld { 30 | cp := in.Called.CopyID() 31 | if cp > in.Upgraded.CopyID() { 32 | cp-- 33 | } 34 | base := in.Called.Tile() - tile.TileBegin 35 | m := Meld(base)*3 + Meld(cp) 36 | m = (m << 2) 37 | m = (m << 2) | Meld(in.Upgraded.CopyID()) 38 | m = (m << 1) 39 | if in.Type == UpgrdedKan { 40 | m |= 1 41 | } 42 | m = (m << 1) 43 | if in.Type != UpgrdedKan { 44 | m |= 1 45 | } 46 | m = (m << 1) 47 | m = (m << 2) | Meld(in.Opponent) 48 | return m 49 | } 50 | 51 | func encodeKan(in *Called) Meld { 52 | m := Meld(in.Called.Tile()-tile.TileBegin)*4 + Meld(in.Called.CopyID()) 53 | m = (m << 6) 54 | m = (m << 2) | Meld(in.Opponent) 55 | return m 56 | } 57 | 58 | func encodeChi(in *Called) Meld { 59 | base := in.Core.Tile() - tile.TileBegin 60 | calledIndex := int(in.Called.Tile() - in.Core.Tile()) 61 | tiles := in.Tiles 62 | 63 | m := Meld(int((base/9)*7+base%9)*3 + calledIndex) 64 | m = (m << 1) 65 | m = (m << 2) | Meld(tiles[2].CopyID()) 66 | m = (m << 2) | Meld(tiles[1].CopyID()) 67 | m = (m << 2) | Meld(tiles[0].CopyID()) 68 | m = (m << 1) | 1 69 | m = (m << 2) | Meld(in.Opponent) 70 | return m 71 | } 72 | -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/compact/totals.go: -------------------------------------------------------------------------------- 1 | package compact 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/tile" 5 | ) 6 | 7 | type Totals []int 8 | 9 | func NewTotals() Totals { 10 | return make(Totals, tile.TileCount) 11 | } 12 | 13 | func (ts Totals) Merge(in Instances) Totals { 14 | if in == nil { 15 | return ts 16 | } 17 | in.Each(func(mask Mask) bool { 18 | ts.Add(mask.Tile(), mask.Count()) 19 | return true 20 | }) 21 | return ts 22 | } 23 | 24 | func (ts Totals) Count() int { 25 | c := 0 26 | for _, v := range ts { 27 | c += v 28 | } 29 | return c 30 | } 31 | 32 | func (ts Totals) Get(t tile.Tile) int { 33 | return ts[shift(t)] 34 | } 35 | 36 | func (ts Totals) Clone() Totals { 37 | x := NewTotals() 38 | for k, v := range ts { 39 | x[k] = v 40 | } 41 | return x 42 | } 43 | 44 | func (ts Totals) UniqueCount() int { 45 | c := 0 46 | for _, v := range ts { 47 | if v > 0 { 48 | c++ 49 | } 50 | } 51 | return c 52 | } 53 | 54 | func (ts Totals) IsFull(t tile.Tile) bool { 55 | return ts[shift(t)] > 3 56 | } 57 | 58 | func (ts Totals) Set(t tile.Tile, d int) { 59 | ts[shift(t)] = d 60 | } 61 | 62 | func (ts Totals) Add(t tile.Tile, d int) { 63 | ts[shift(t)] += d 64 | } 65 | 66 | func (ts Totals) UniqueTiles() Tiles { 67 | ret := Tiles(0) 68 | for t, c := range ts { 69 | if c > 0 { 70 | ret = ret.Set(tile.Tile(t) + tile.TileBegin) 71 | } 72 | } 73 | return ret 74 | } 75 | 76 | func (ts Totals) FullTiles() Tiles { 77 | ret := Tiles(0) 78 | for t, c := range ts { 79 | if c > 3 { 80 | ret = ret.Set(tile.Tile(t) + tile.TileBegin) 81 | } 82 | } 83 | return ret 84 | } 85 | 86 | func (ts Totals) FreeTiles() Tiles { 87 | return (^ts.FullTiles()).Normalize() 88 | } 89 | -------------------------------------------------------------------------------- /tbase/called.go: -------------------------------------------------------------------------------- 1 | package tbase 2 | 3 | import ( 4 | "github.com/dnovikoff/tempai-core/compact" 5 | "github.com/dnovikoff/tempai-core/hand/calc" 6 | "github.com/dnovikoff/tempai-core/tile" 7 | ) 8 | 9 | type Called struct { 10 | Type CallType 11 | Opponent Opponent 12 | Tiles tile.Instances 13 | Called tile.Instance 14 | Upgraded tile.Instance 15 | // Core representation of meld for tempai calculator 16 | Core calc.Meld 17 | } 18 | 19 | type CalledList []*Called 20 | 21 | func (cl CalledList) Core() calc.Melds { 22 | melds := make(calc.Melds, len(cl)) 23 | for k, v := range cl { 24 | melds[k] = v.Core 25 | } 26 | return melds 27 | } 28 | 29 | func (cl CalledList) Add(x compact.Instances) { 30 | for _, v := range cl { 31 | v.Add(x) 32 | } 33 | } 34 | 35 | func (c *Called) Encode() Meld { 36 | return EncodeCalled(c) 37 | } 38 | 39 | func (c *Called) IsKan() bool { 40 | switch c.Type { 41 | case Kan, UpgrdedKan, ClosedKan: 42 | return true 43 | } 44 | return false 45 | } 46 | 47 | func (c *Called) Add(x compact.Instances) { 48 | x.Add(c.Tiles) 49 | if c.Called != tile.InstanceNull { 50 | x.Set(c.Called) 51 | } 52 | if c.Type == UpgrdedKan && c.Upgraded != tile.InstanceNull { 53 | x.Set(c.Upgraded) 54 | } 55 | } 56 | 57 | type CallType int 58 | 59 | const ( 60 | Chi CallType = iota + 1 61 | Pon 62 | Kan 63 | ClosedKan 64 | UpgrdedKan 65 | ) 66 | 67 | type Opponent int 68 | 69 | const ( 70 | Self Opponent = iota 71 | Right 72 | Front 73 | Left 74 | ) 75 | 76 | func (o Opponent) String() string { 77 | switch o { 78 | case Self: 79 | return "Self" 80 | case Right: 81 | return "Right" 82 | case Front: 83 | return "Front" 84 | case Left: 85 | return "Left" 86 | } 87 | return "Unknown" 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go: -------------------------------------------------------------------------------- 1 | //go:build !testify_yaml_fail && !testify_yaml_custom 2 | // +build !testify_yaml_fail,!testify_yaml_custom 3 | 4 | // Package yaml is just an indirection to handle YAML deserialization. 5 | // 6 | // This package is just an indirection that allows the builder to override the 7 | // indirection with an alternative implementation of this package that uses 8 | // another implementation of YAML deserialization. This allows to not either not 9 | // use YAML deserialization at all, or to use another implementation than 10 | // [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]). 11 | // 12 | // Alternative implementations are selected using build tags: 13 | // 14 | // - testify_yaml_fail: [Unmarshal] always fails with an error 15 | // - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it 16 | // before calling any of [github.com/stretchr/testify/assert.YAMLEq] or 17 | // [github.com/stretchr/testify/assert.YAMLEqf]. 18 | // 19 | // Usage: 20 | // 21 | // go test -tags testify_yaml_fail 22 | // 23 | // You can check with "go list" which implementation is linked: 24 | // 25 | // go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 26 | // go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 27 | // go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 28 | // 29 | // [PR #1120]: https://github.com/stretchr/testify/pull/1120 30 | package yaml 31 | 32 | import goyaml "gopkg.in/yaml.v3" 33 | 34 | // Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal]. 35 | func Unmarshal(in []byte, out interface{}) error { 36 | return goyaml.Unmarshal(in, out) 37 | } 38 | -------------------------------------------------------------------------------- /vendor/google.golang.org/protobuf/internal/impl/bitmap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build !race 6 | 7 | package impl 8 | 9 | // There is no additional data as we're not running under race detector. 10 | type RaceDetectHookData struct{} 11 | 12 | // Empty stubs for when not using the race detector. Calls to these from index.go should be optimized away. 13 | func (presence) raceDetectHookPresent(num uint32) {} 14 | func (presence) raceDetectHookSetPresent(num uint32, size presenceSize) {} 15 | func (presence) raceDetectHookClearPresent(num uint32) {} 16 | func (presence) raceDetectHookAllocAndCopy(src presence) {} 17 | 18 | // raceDetectHookPresent is called by the generated file interface 19 | // (*proto.internalFuncs) Present to optionally read an unprotected 20 | // shadow bitmap when race detection is enabled. In regular code it is 21 | // a noop. 22 | func raceDetectHookPresent(field *uint32, num uint32) {} 23 | 24 | // raceDetectHookSetPresent is called by the generated file interface 25 | // (*proto.internalFuncs) SetPresent to optionally write an unprotected 26 | // shadow bitmap when race detection is enabled. In regular code it is 27 | // a noop. 28 | func raceDetectHookSetPresent(field *uint32, num uint32, size presenceSize) {} 29 | 30 | // raceDetectHookClearPresent is called by the generated file interface 31 | // (*proto.internalFuncs) ClearPresent to optionally write an unprotected 32 | // shadow bitmap when race detection is enabled. In regular code it is 33 | // a noop. 34 | func raceDetectHookClearPresent(field *uint32, num uint32) {} 35 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/README.md: -------------------------------------------------------------------------------- 1 | # multierr [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] 2 | 3 | `multierr` allows combining one or more Go `error`s together. 4 | 5 | ## Features 6 | 7 | - **Idiomatic**: 8 | multierr follows best practices in Go, and keeps your code idiomatic. 9 | - It keeps the underlying error type hidden, 10 | allowing you to deal in `error` values exclusively. 11 | - It provides APIs to safely append into an error from a `defer` statement. 12 | - **Performant**: 13 | multierr is optimized for performance: 14 | - It avoids allocations where possible. 15 | - It utilizes slice resizing semantics to optimize common cases 16 | like appending into the same error object from a loop. 17 | - **Interoperable**: 18 | multierr interoperates with the Go standard library's error APIs seamlessly: 19 | - The `errors.Is` and `errors.As` functions *just work*. 20 | - **Lightweight**: 21 | multierr comes with virtually no dependencies. 22 | 23 | ## Installation 24 | 25 | ```bash 26 | go get -u go.uber.org/multierr@latest 27 | ``` 28 | 29 | ## Status 30 | 31 | Stable: No breaking changes will be made before 2.0. 32 | 33 | ------------------------------------------------------------------------------- 34 | 35 | Released under the [MIT License]. 36 | 37 | [MIT License]: LICENSE.txt 38 | [doc-img]: https://pkg.go.dev/badge/go.uber.org/multierr 39 | [doc]: https://pkg.go.dev/go.uber.org/multierr 40 | [ci-img]: https://github.com/uber-go/multierr/actions/workflows/go.yml/badge.svg 41 | [cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg 42 | [ci]: https://github.com/uber-go/multierr/actions/workflows/go.yml 43 | [cov]: https://codecov.io/gh/uber-go/multierr 44 | -------------------------------------------------------------------------------- /cmd/tenhou-proxy/README.md: -------------------------------------------------------------------------------- 1 | ## Howto use proxy server 2 | I've made this small proxy for researching tenhou.net flash client protocol content. 3 | 4 | Download application 5 | ``` 6 | go get -u github.com/dnovikoff/tenhou/cmd/tenhou-proxy 7 | ``` 8 | 9 | Run application 10 | ``` 11 | $GOPATH/bin/tenhou-proxy 12 | ``` 13 | 14 | Add to your `hosts` file 15 | ``` 16 | 127.0.0.1 b.mjv.jp 17 | ``` 18 | 19 | Login into flash client http://tenhou.net/0/ . 20 | Application output would look like 21 | ``` 22 | 2018/01/27 00:26:42 Started server on addr ':10080'. Sequence id is 'baab75ab' 23 | 2018/01/27 00:26:55 File for new connection is 'baab75ab_0001.log' 24 | 2018/01/27 00:26:55 Error: EOF 25 | 2018/01/27 00:26:55 Error: Read context done 26 | 2018/01/27 00:26:55 Done with 1 27 | 2018/01/27 00:26:55 File for new connection is 'baab75ab_0002.log' 28 | 2018/01/27 00:26:56 Error: EOF 29 | 2018/01/27 00:26:56 Error: Read context done 30 | 2018/01/27 00:26:56 Done with 2 31 | 2018/01/27 00:26:57 File for new connection is 'baab75ab_0003.log' 32 | ``` 33 | 34 | Protocol logs will appear in workdir. 35 | Short example of log result. 36 | ``` 37 | Send: 38 | Send: 39 | Get: 40 | Send: 41 | Send: 42 | Send: 43 | Get: 44 | Send: 45 | Get: 46 | Send: 47 | ``` -------------------------------------------------------------------------------- /proto/stats/stats.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package stats; 3 | 4 | import "google/protobuf/timestamp.proto"; 5 | import "google/protobuf/duration.proto"; 6 | 7 | option go_package = "github.com/dnovikoff/tenhou/genproto/stats"; 8 | 9 | enum LobbyType { 10 | LOBBY_TYPE_KU = 0; // 般 11 | LOBBY_TYPE_DAN = 1; // 上 12 | LOBBY_TYPE_UPPERDAN = 2; // 特 13 | LOBBY_TYPE_PHOENIX = 3; // 鳳 14 | LOBBY_TYPE_DZ = 4; // 技 15 | LOBBY_TYPE_X1 = 5; // 若 16 | LOBBY_TYPE_X2 = 6; // 銀 17 | LOBBY_TYPE_X3 = 7; // 琥 18 | LOBBY_TYPE_EXTERNAL = 8; // - 19 | } 20 | 21 | enum GameLength { 22 | GAME_LENGTH_SOUTH = 0; 23 | GAME_LENGTH_EAST = 1; 24 | GAME_LENGTH_ONE = 2; 25 | } 26 | 27 | enum GameType { 28 | GAME_TYPE_4 = 0; 29 | GAME_TYPE_3 = 1; 30 | } 31 | 32 | enum GameSpeed { 33 | GAME_SPEED_NORMAL = 0; 34 | GAME_SPEED_FAST = 1; 35 | } 36 | 37 | enum Akkas { 38 | AKKAS_YES = 0; 39 | AKKAS_NO = 1; 40 | } 41 | 42 | enum Tanyao { 43 | TANYAO_YES = 0; 44 | TANYAO_NO = 1; 45 | } 46 | 47 | enum NumberType { 48 | NO_NUMBER = 0; 49 | NUMBER_2 = 2; 50 | NUMBER_5 = 5; 51 | NUMBER_0 = 10; 52 | } 53 | 54 | message Player { 55 | string name = 1; 56 | int64 score = 2; 57 | int64 coins = 3; 58 | } 59 | 60 | message Record { 61 | google.protobuf.Timestamp time = 1; 62 | google.protobuf.Duration duration = 2; 63 | 64 | int64 number = 3; 65 | LobbyType lobby = 4; 66 | GameLength length = 5; 67 | GameType type = 6; 68 | Akkas akkas = 7; 69 | Tanyao tanyao = 8; 70 | // Some strange numbers, that are not ascii numbers like '5' or '2' 71 | NumberType number_type = 9; 72 | 73 | repeated Player players = 10; 74 | string id = 11; 75 | bool is_dz = 12; 76 | bool is_champion_lobby = 13; 77 | } -------------------------------------------------------------------------------- /vendor/github.com/dnovikoff/tempai-core/hand/effective/effective.go: -------------------------------------------------------------------------------- 1 | package effective 2 | 3 | import ( 4 | "sort" 5 | 6 | "github.com/dnovikoff/tempai-core/compact" 7 | "github.com/dnovikoff/tempai-core/hand/calc" 8 | "github.com/dnovikoff/tempai-core/hand/shanten" 9 | "github.com/dnovikoff/tempai-core/tile" 10 | ) 11 | 12 | type Results map[tile.Tile]shanten.Results 13 | 14 | type Result struct { 15 | Tile tile.Tile 16 | Shanten shanten.Results 17 | sortId sSortId 18 | } 19 | 20 | func Calculate(closed compact.Instances, options ...calc.Option) Results { 21 | results := make(Results, len(closed)) 22 | cp := closed.Clone() 23 | last := tile.TileNull 24 | options = append(options, shanten.StartMelds(closed)) 25 | for _, i := range cp.Instances() { 26 | if i.Tile() == last { 27 | continue 28 | } 29 | last = i.Tile() 30 | cp.Remove(i) 31 | results[last] = shanten.Calculate(cp, options...) 32 | cp.CopyFrom(closed) 33 | } 34 | return results 35 | } 36 | 37 | //wd98765 38 | func tilePriority(t tile.Tile) int { 39 | if compact.Honor.Check(t) { 40 | return 0 41 | } 42 | 43 | switch t.Number() { 44 | case 1, 9: 45 | return 1 46 | case 2, 8: 47 | return 2 48 | case 3, 7: 49 | return 3 50 | case 4, 6: 51 | return 5 52 | case 5: 53 | return 6 54 | } 55 | // Unreachable 56 | return 7 57 | } 58 | 59 | func (r Results) Sorted(used compact.Instances) ResultsSorted { 60 | ret := make(ResultsSorted, 0, len(r)) 61 | uq := used.UniqueTiles().Invert() 62 | for k, v := range r { 63 | t := (uq & v.Total.Improves).Count() 64 | u := used.CountFree(v.Total.Improves) 65 | id := newSortId(u, t, v.Total.Value) 66 | ret = append(ret, &Result{ 67 | Tile: k, 68 | Shanten: v, 69 | sortId: id, 70 | }) 71 | } 72 | 73 | sort.Sort(ret) 74 | return ret 75 | } 76 | -------------------------------------------------------------------------------- /tools/tentool/README.md: -------------------------------------------------------------------------------- 1 | ## Tenhou stats and log downloader 2 | Download stat files and log files to work with them on your local computer. 3 | 4 | Download tool by typing: 5 | ``` 6 | go get github.com/dnovikoff/tenhou/tools/tentool 7 | ``` 8 | 9 | Initialize the stats repo in current working dir. 10 | ``` 11 | tentool stats init 12 | ``` 13 | 14 | I suggest that you first download some archives from my [Yandex.Disk](https://yadi.sk/d/uOv87aVsd-l-3A). 15 | The files will be downloaded to `./tenhou/stats` folder. 16 | That could you reduce you downloading time. 17 | Do this by typing: 18 | ``` 19 | tentool stats yadisk 20 | ``` 21 | 22 | Download stat files from tenhou.net. 23 | The files will be downloaded to `./tenhou/stats` folder. 24 | Repeat this action when you need to get updates. 25 | ``` 26 | tentool stats download 27 | ``` 28 | 29 | Initialize the logs repo in current working dir. 30 | ``` 31 | tentool logs init 32 | ``` 33 | 34 | I suggest that you first download some prebuild zip files with logs from my [Yandex.Disk](https://yadi.sk/d/FIIkaucSNjR3Kw). 35 | That would be sure times faster, than downloading all logs from tenhou one by one. 36 | The files will be downloaded to `./tenhou/logs` folder. 37 | ``` 38 | tentool logs yadisk 39 | ``` 40 | 41 | Collect all log ids from stat files by typing. 42 | Repeat this action, after next call of `tentool stats download`. 43 | ``` 44 | tentool logs update 45 | ``` 46 | 47 | Download log files from collected log ids by typing 48 | ``` 49 | tentool logs download 50 | ``` 51 | 52 | Alternatevly you can init with makefile 53 | ``` 54 | make init 55 | ``` 56 | 57 | And update with 58 | ``` 59 | make download 60 | ``` 61 | 62 | Now you have full database of phoenix logs on your machine. 63 | Consider reading `tentool stats --help` and `tentool logs --help` on more commands and flags. --------------------------------------------------------------------------------