262 lines
6.0 KiB
Go
262 lines
6.0 KiB
Go
package pkg
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"reflect"
|
|
"sort"
|
|
)
|
|
|
|
const (
|
|
// 未出场
|
|
tl_notshow = 0
|
|
// 本家状态
|
|
tl_mhand = 1
|
|
tl_mshow = 2
|
|
tl_mdisc = 3
|
|
// 下家状态
|
|
tl_nhand = 4
|
|
tl_nshow = 5
|
|
tl_ndisc = 6
|
|
// 对家状态
|
|
tl_ohand = 7
|
|
tl_oshow = 8
|
|
tl_odisc = 9
|
|
// 上家状态
|
|
tl_phand = 10
|
|
tl_pshow = 11
|
|
tl_pdisc = 12
|
|
)
|
|
|
|
var tileTypes = [34]string{
|
|
"1W", "2W", "3W", "4W", "5W", "6W", "7W", "8W", "9W",
|
|
"1T", "2T", "3T", "4T", "5T", "6T", "7T", "8T", "9T",
|
|
"1B", "2B", "3B", "4B", "5B", "6B", "7B", "8B", "9B",
|
|
"DO", "XI", "NA", "BE", "ZH", "FA", "BA"}
|
|
var tileHuaTypes = [8]string{"ME", "LA", "ZU", "JU", "CH", "XA", "QI", "DN"}
|
|
|
|
type environment struct {
|
|
board [4][34]int
|
|
}
|
|
|
|
func (e environment) Print() {
|
|
for i := 0; i < len(e.board)+1; i++ {
|
|
for j := 0; j < len(e.board[0]); j++ {
|
|
if i == 0 {
|
|
fmt.Printf("|% 3s", tileTypes[j])
|
|
} else {
|
|
fmt.Printf("|% 3d", e.board[i-1][j])
|
|
}
|
|
}
|
|
fmt.Printf("|\n")
|
|
}
|
|
}
|
|
|
|
func (e environment) PatternNormalization() [3][34]int {
|
|
var ret [3][34]int
|
|
for i := 0; i < len(e.board[0]); i++ {
|
|
hand := 0
|
|
disc := 0
|
|
noshow := 0
|
|
for j := 0; j < len(e.board); j++ {
|
|
switch e.board[j][i] {
|
|
case tl_mhand, tl_mshow:
|
|
hand += 1
|
|
case tl_mdisc, tl_ndisc, tl_nshow, tl_odisc, tl_oshow, tl_pdisc, tl_pshow:
|
|
disc += 1
|
|
case tl_notshow:
|
|
noshow += 1
|
|
}
|
|
}
|
|
ret[0][i] = hand
|
|
ret[1][i] = disc
|
|
ret[2][i] = noshow
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func TileComparator(i, j string) (bool, error) {
|
|
if i == j {
|
|
return false, nil
|
|
}
|
|
ii, ij := -1, -1
|
|
for k, v := range tileTypes {
|
|
if i == v {
|
|
ii = k
|
|
}
|
|
if j == v {
|
|
ij = k
|
|
}
|
|
}
|
|
if ii == -1 || ij == -1 {
|
|
return false, errors.New("can't find tile by name")
|
|
}
|
|
return ii < ij, nil
|
|
}
|
|
|
|
func Sort(tiles []string) error {
|
|
sort.Slice(tiles, func(i, j int) bool {
|
|
res, err := TileComparator(tiles[i], tiles[j])
|
|
if err != nil {
|
|
log.Fatalf("Sort tiles has error: %v", err)
|
|
}
|
|
return res
|
|
})
|
|
return nil
|
|
}
|
|
|
|
// Check
|
|
func CheckXushuHelper(tiles [9]int, index int, allCombs [][]int, combTable *[][][]int) {
|
|
if index >= 9 {
|
|
// Check invalid shun/ke/gang with more than 1 pair
|
|
gangAmount := 0
|
|
shunKeAmount := 0
|
|
pairAmount := 0
|
|
for _, combs := range allCombs {
|
|
if len(combs) == 2 {
|
|
pairAmount++
|
|
}
|
|
if len(combs) == 3 {
|
|
shunKeAmount++
|
|
}
|
|
if len(combs) == 4 {
|
|
gangAmount++
|
|
}
|
|
}
|
|
if pairAmount > 1 && (gangAmount > 0 || shunKeAmount > 0) {
|
|
return
|
|
}
|
|
*combTable = append(*combTable, allCombs)
|
|
return
|
|
}
|
|
if tiles[index] == 0 {
|
|
CheckXushuHelper(tiles, index+1, allCombs, combTable)
|
|
return
|
|
}
|
|
if tiles[index] == 4 {
|
|
tiles[index] = 0
|
|
CheckXushuHelper(tiles, index+1, append(allCombs, []int{index, index, index, index}), combTable)
|
|
if index < 7 {
|
|
if tiles[index+1] > 0 && tiles[index+2] > 0 {
|
|
tiles[index] = 3
|
|
tiles[index+1] -= 1
|
|
tiles[index+2] -= 1
|
|
CheckXushuHelper(tiles, index, append(allCombs, []int{index, index + 1, index + 2}), combTable)
|
|
tiles[index+1] += 1
|
|
tiles[index+2] += 1
|
|
}
|
|
}
|
|
tiles[index] = 2
|
|
CheckXushuHelper(tiles, index, append(allCombs, []int{index, index}), combTable)
|
|
} else if tiles[index] == 3 {
|
|
tiles[index] = 0
|
|
CheckXushuHelper(tiles, index+1, append(allCombs, []int{index, index, index}), combTable)
|
|
if index < 7 {
|
|
if tiles[index+1] > 0 && tiles[index+2] > 0 {
|
|
tiles[index] = 2
|
|
tiles[index+1] -= 1
|
|
tiles[index+2] -= 1
|
|
CheckXushuHelper(tiles, index, append(allCombs, []int{index, index + 1, index + 2}), combTable)
|
|
tiles[index+1] += 1
|
|
tiles[index+2] += 1
|
|
}
|
|
}
|
|
} else if tiles[index] == 2 {
|
|
tiles[index] = 0
|
|
CheckXushuHelper(tiles, index+1, append(allCombs, []int{index, index}), combTable)
|
|
if index < 7 {
|
|
if tiles[index+1] > 0 && tiles[index+2] > 0 {
|
|
tiles[index] = 1
|
|
tiles[index+1] -= 1
|
|
tiles[index+2] -= 1
|
|
CheckXushuHelper(tiles, index, append(allCombs, []int{index, index + 1, index + 2}), combTable)
|
|
tiles[index+1] += 1
|
|
tiles[index+2] += 1
|
|
}
|
|
}
|
|
} else {
|
|
if index < 7 {
|
|
if tiles[index+1] > 0 && tiles[index+2] > 0 {
|
|
tiles[index] = 0
|
|
tiles[index+1] -= 1
|
|
tiles[index+2] -= 1
|
|
CheckXushuHelper(tiles, index+1, append(allCombs, []int{index, index + 1, index + 2}), combTable)
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func CheckXushuTile(tiles []string) ([][][]string, error) {
|
|
limit := len(tiles)
|
|
if limit <= 0 {
|
|
return [][][]string{}, nil
|
|
}
|
|
var combTable [][][]int
|
|
if limit <= 3 {
|
|
var tileNumbers []int
|
|
for _, tile := range tiles {
|
|
tileNumbers = append(tileNumbers, int(tile[0])-48)
|
|
}
|
|
// bukao
|
|
isBukao := true
|
|
for _, num := range tileNumbers[1:] {
|
|
if ((num - tileNumbers[0]) != 3) && ((num - tileNumbers[0]) != 6) {
|
|
isBukao = false
|
|
}
|
|
}
|
|
// isbukao + shisanyao
|
|
if isBukao || reflect.DeepEqual(tileNumbers, []int{1, 9}) || reflect.DeepEqual(tileNumbers, []int{1, 1, 9}) || reflect.DeepEqual(tileNumbers, []int{1, 9, 9}) {
|
|
var tmpAllCombs [][]int
|
|
for _, tile := range tiles {
|
|
tmpAllCombs = append(tmpAllCombs, []int{int(tile[0]) - 49})
|
|
}
|
|
combTable = append(combTable, tmpAllCombs)
|
|
}
|
|
}
|
|
var flatTileVector [9]int
|
|
for _, tile := range tiles {
|
|
flatTileVector[int(tile[0])-49] += 1
|
|
}
|
|
CheckXushuHelper(flatTileVector, 0, [][]int{}, &combTable)
|
|
|
|
if len(combTable) <= 0 {
|
|
return [][][]string{}, fmt.Errorf("tiles are not empty, but can't generate a valid pattern(%v)", tiles)
|
|
}
|
|
|
|
strColor := tiles[0][1]
|
|
var readableResult [][][]string
|
|
for _, combs := range combTable {
|
|
readableCombs := [][]string{}
|
|
for _, comb := range combs {
|
|
readableComb := []string{}
|
|
for _, tile := range comb {
|
|
readableComb = append(readableComb, fmt.Sprintf("%d%c", tile+1, strColor))
|
|
}
|
|
readableCombs = append(readableCombs, readableComb)
|
|
}
|
|
readableResult = append(readableResult, readableCombs)
|
|
}
|
|
return readableResult, nil
|
|
}
|
|
|
|
func TilesDividedToPatterns(tiles []string) error {
|
|
Sort(tiles)
|
|
var wan, tiao, bing, zi []string
|
|
for _, tile := range tiles {
|
|
switch tile[1] {
|
|
case 'W':
|
|
wan = append(wan, tile)
|
|
case 'T':
|
|
tiao = append(tiao, tile)
|
|
case 'B':
|
|
bing = append(bing, tile)
|
|
default:
|
|
zi = append(zi, tile)
|
|
}
|
|
}
|
|
return nil
|
|
}
|