Files
2024-04-13 02:40:32 +00:00

207 lines
5.3 KiB
Go

package tiles
import (
"errors"
"fmt"
"log"
"reflect"
"sort"
)
var TileTypes []string = []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 []string = []string{"ME", "LA", "ZU", "JU", "CH", "XA", "QI", "DN"}
// Given two tiles, return if first tile is smaller the second tile, functions used as comparator for ordering
// Default order is: 万 < 条 < 饼 < 字(东西南北中发白)
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)
}
}
_, _ = CheckXushuTile(wan)
_, _ = CheckXushuTile(tiao)
_, _ = CheckXushuTile(bing)
log.Println(zi)
return nil
}