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 }