You can also use Combinatorial Optimization to determine whether you can play mahjong. For the sake of simplicity, I'll just consider whether it's a raised shape (one sparrow head, three facets). In addition, Makiko is also excluded.
--Jantou: Two identical tiles --Mentions: Junko, Kiko, or Mako --Shunz: Three tiles of the same type arranged in order --Coats: Three identical tiles --Kants: 4 same tiles --Rise: 1 sparrow head and 4 faces
--There is no objective function because we will consider whether the condition is satisfied. --Using the given tiles, enumerate the combinations that will be the sparrow head, Junko, or engraving, and make them candidates. ――Choose a candidate well so that all tiles appear exactly once. --Choose exactly one sparrow head.
Variable td> | $ x_i \ in \ {0, 1 \} $ td> | $ x_i $: $ i $ Whether to choose the third candidate td > tr> |
Constraints td> | $ \ sum_i {a_ {ij} x_i} = 1 ~ ~ \ forall j \ le 13 $ td> | $ a_ {ij} $: Whether the $ i $ th candidate contains tile $ j $ td> tr> |
$ \ sum_ {i \ in H} {x_i} = 1 $ td> | $ H $: Sparrow head candidate td> tr> |
This problem is a partition of a set problem.
--Mahjong tiles Manz (0-8), Tsutsuko (Pins) (10-18), Swords (20-28), Kazehai (30,32,34, 36), I will represent it with the numbers of Sangenpai (38,40,42). By doing this, Junko is always continuous, and if it is continuous, it becomes Junko. --Define a function calc that takes 14 tiles (variable hai) as input and returns 5 sparrow heads or faces.
python3
def calc(hai):
import pandas as pd
from itertools import combinations, product
from pulp import LpProblem, LpBinary, LpVariable, lpSum, value
cand = [] #Candidate
a = pd.DataFrame(sorted(hai), columns=['v'])
b = a.v.value_counts()
for i in b[b >= 2].index: #Sparrow head candidate creation
cand.extend(combinations(a[a.v == i].index, 2))
n2 = len(cand)
for i in b[b >= 3].index: #Create engraving candidates
cand.extend(combinations(a[a.v == i].index, 3))
c = a.v.unique()
for i in range(len(c)-2): #Junko candidate creation
if c[i+1] - c[i] == c[i+2] - c[i+1] == 1:
cand.extend(product(a.index[a.v==c[i]],
a.index[a.v==c[i+1]],
a.index[a.v==c[i+2]]))
m = LpProblem() #Mathematical model
v = [LpVariable('v%d'%i, cat=LpBinary) for i in range(len(cand))] #variable
m += lpSum(v[:n2]) == 1 #One sparrow head
d = [[] for _ in range(14)] #List of candidate numbers by tile
for i, ca in enumerate(cand):
for j in ca:
d[j].append(v[i])
for i in d:
m += lpSum(i) == 1 #All tiles are one in any candidate
if m.solve() != 1: return None
return [[a.v[j] for j in cand[i]] for i, vv in enumerate(v) if value(vv) > 0.5]
Let's actually calculate.
python3
def show(n):
if n < 30:
return chr(ord('1')+n%10)+'Mantsubo'[n//10]
return 'From east, west, north, south, and white'[n//2-16]
hai = [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8] #14 tiles
for i in calc(hai):
for j in i: print(show(j))
print()
>>>
1 man
1 man
9 Man
9 Man
9 Man
1 man
2 Man
3 Man
4 Man
5 Man
6 Man
7 Man
8 Man
9 Man
I was able to find the sparrow head and face properly.
that's all
Recommended Posts