It is not an algorithm to find the number of listenings, which checks whether the completion of 14 Tehai is completed.
ONE-HOT is used for the tile data. ONE-HOT is selected because it is easy to judge the head and engraving if the sum of the ONE-HOT array is taken in the row direction.
# ONE-Tehai of HOT expression
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
]
#Take the sum in the row direction
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 1, 1, 1, 4, 1, 1, 0, 0, 0, 0, 0, 0, 0]
#3 or more parts will be used to judge the engraving
# [1, 1, 1]Fold it in and use 3 or more parts to judge Junko.
#There are advantages such as (I think)
Follow the above procedure to check if the winning is completed.
import itertools
import multiprocessing
import numpy as np
import os
import sys
import time
# m1-m9, p1-p9, s1-s9, dw, dg, dr, we, ww, ws, wn
#Three-element tile = Dragon
#Wind tile = Wind
tileKeyIndex = [
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
"p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9",
"s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9",
"dw", "dg", "dr",
"we", "ww", "ws", "wn",
]
MTileBits = [
1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0, 0
]
PTileBits = [
0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0, 0
]
STileBits = [
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0,
0, 0, 0, 0
]
DTileBits = [
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1,
0, 0, 0, 0
]
WTileBits = [
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
1, 1, 1, 1
]
KokusiBits = [
1, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1,
1, 1, 1, 1
]
KokusiBits = np.array(KokusiBits)
# m1m2m3m4m5m6m7m8m9s1s2s3wnwn
def parseTehai(s):
if len(s) != 28:
print("error in {}, len(s)={}".format(sys._getframe().f_code.co_name, len(s)))
sys.exit()
tileMatrix = np.zeros((14, len(tileKeyIndex)))
for i in range(14):
pos = i * 2
idx = tileKeyIndex.index(s[pos:pos + 2])
tileMatrix[i][idx] = 1
return tileMatrix
def isShuntsuCompleted(tileMatrix):
indexes = []
for tbits in [MTileBits, PTileBits, STileBits]:
target = tileMatrix * tbits
while True:
targetB = (target != 0).astype(int) # [1, 1, 2]Convert all to 1 to avoid arrays like
b = np.convolve(targetB, [1, 1, 1], mode="valid")
if np.max(b) != 3:
break
idxs = np.where(b == 3)[0]
idx = idxs[0]
target[idx:idx + 3] -= 1 #Remove the inspected tiles
indexes = indexes + list(np.arange(idx, idx + 3, 1))
return indexes
def isCompleted(tileMatrix):
rowSum = np.sum(tileMatrix, axis=0)
headerIdxs = np.where(rowSum >= 2)[0]
atama, kotsu, shuntsu = [], [], []
#Cheet Toys
if len(headerIdxs) == 7:
return 1, list(headerIdxs) * 2, [], []
#Kokushi
kokusiCheck = (rowSum != 0).astype(int)
if np.sum(kokusiCheck * KokusiBits) == 13 and np.sum(rowSum * KokusiBits) == 14:
return 1, np.where(np.array(KokusiBits) == 1)[0], [], []
#Fix the head
#All patterns of engraving are put out in advance, and Junko is inspected by fixing each pattern.
for hidx in headerIdxs:
#Make a copy so you don't manipulate the original array
calcBuffer = np.array(rowSum)
#Get rid of the head
calcBuffer[hidx] -= 2
#Detect all possible engraving
kotsuPos = np.where(calcBuffer >= 3)[0]
#Only one of the detected engravings is valid, only two of the detected engravers are valid ... Create all patterns of all detected engravings
kotsuPatterns = []
for i in range(len(kotsuPos)):
comb = list(itertools.combinations(kotsuPos, i + 1))
kotsuPatterns = kotsuPatterns + comb
#Add a pattern for which no engraving is valid
kotsuPatterns.append(None)
for kotsuIndexes in kotsuPatterns:
#Make a copy so you don't manipulate the original array
calcBuffer2 = np.array(calcBuffer)
if isinstance(kotsuIndexes, type(None)):
pass
else:
#Remove the engraving
for kidx in kotsuIndexes:
calcBuffer2[kidx] -= 3
#Junko
shuntsuIndexes = isShuntsuCompleted(calcBuffer2)
for idx in shuntsuIndexes:
#Get rid of Junko
calcBuffer2[idx] -= 1
#If there are no tiles left after removing the head, engraving, and Junko, it is complete.
#print("np.sum(calcBuffer)", np.sum(calcBuffer2))
if np.sum(calcBuffer2) == 0:
atama.append(np.full(2, hidx))
kotsu.append(kotsuIndexes)
shuntsu.append(shuntsuIndexes)
return len(atama), atama, kotsu, shuntsu
def Test1():
#2333345677778
#2333344567888
#2345666777888
#3344455566777
#2223344455677
#1112345556677
#4556677888999
#Waiting for 1425869
#Waiting for 14725869
#Waiting for 1245678
#Waiting for 36258
#Waiting for 6257
#Waiting for 672583
#Waiting for 789436
#tileMatrix = parseTehai("m1m2m3m4m5m6m7m8m9s1s2s3wnwn")
#tileMatrix = parseTehai("wewewewwwwwwwswswsm9m9m9s1s1")
#tileMatrix = parseTehai("s2s3s3s3s3s4s5s6s7s7s7s7s8s9") # s1, s2, s4, s5, s6, s8, s9
#tileMatrix = parseTehai("m2m3m3m3m3m4m4m5m6m7m8m8m8m1") #
#tileMatrix = parseTehai("m2m3m4m5m6m6m6m7m7m7m8m8m8?")
#tileMatrix = parseTehai("m3m3m4m4m4m5m5m5m6m6m7m7m7?")
#tileMatrix = parseTehai("p2p2p2p3p3p4p4p4p5p5p6p7p7?")
#tileMatrix = parseTehai("p1p1p1p2p3p4p5p5p5p6p6p7p7?")
#tileMatrix = parseTehai("p4p5p5p6p6p7p7p8p8p8p9p9p9?")
tileMatrix = parseTehai("m1m9p1p9s1s9wewswwwndwdgdrm1")
completeCount, atama, kotsu, shuntsu = isCompleted(tileMatrix)
if completeCount > 0:
print("OK")
print(atama)
print(kotsu)
print(shuntsu)
else:
print("NG")
def tileMatrixToTehaiString(tileMatrix):
s = ""
for r in tileMatrix:
idx = np.where(r == 1)[0][0]
s += tileKeyIndex[idx]
return s
def appendFile(fileName, data):
with open(fileName, mode="a") as f:
f.write(data + "\n")
def TenhohTestSub(args):
seed = time.time()
seed = int((seed - int(seed)) * 10000000)
np.random.seed(seed)
instanceId, tryCount = args
size = len(tileKeyIndex)
allTile = []
for i in range(size):
tmp = [0] * size
tmp[i] = 1
for n in range(4):
allTile.append(tmp)
for i in range(tryCount):
np.random.shuffle(allTile)
tiles = np.array(allTile[:14])
completeCount, atama, kotsu, shuntsu = isCompleted(tiles)
if completeCount > 0:
tehaiStr = tileMatrixToTehaiString(tiles)
appendFile("tenhoh_{}.txt".format(instanceId), tehaiStr)
def TenhohTest():
#TenhohTestSub(1, 400000)
tryCount = 1000000
args = []
for i in range(4):
args.append([i, tryCount])
with multiprocessing.Pool(4) as p:
p.map(TenhohTestSub, args)
def main():
#Test1()
TenhohTest()
if __name__ == "__main__":
main()
# python main.py
def main():
#Test1()
TenhohTest()
Test1 () inspects the manually prepared score in the source code. In TenhohTest (), 4 cores are used to randomly create a score 1 million times per core, and if it is a winning form, a record is taken. The record is recorded with a number for each core such as "tenhoh_0.txt". ..
Is it Tenwa by using the image conversion program added below? You can visualize the score you have made.
We will publish a program to image text, how to use it will be described later.
import PIL.Image
import os
import sys
tileKeyIndex = [
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
"p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9",
"s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9",
"dw", "dg", "dr",
"we", "ww", "ws", "wn",
]
haiImageNames = [
"p_ms1_1.gif", "p_ms2_1.gif", "p_ms3_1.gif", "p_ms4_1.gif", "p_ms5_1.gif", "p_ms6_1.gif", "p_ms7_1.gif", "p_ms8_1.gif", "p_ms9_1.gif",
"p_ps1_1.gif", "p_ps2_1.gif", "p_ps3_1.gif", "p_ps4_1.gif", "p_ps5_1.gif", "p_ps6_1.gif", "p_ps7_1.gif", "p_ps8_1.gif", "p_ps9_1.gif",
"p_ss1_1.gif", "p_ss2_1.gif", "p_ss3_1.gif", "p_ss4_1.gif", "p_ss5_1.gif", "p_ss6_1.gif", "p_ss7_1.gif", "p_ss8_1.gif", "p_ss9_1.gif",
"p_no_1.gif", "p_ji_h_1.gif", "p_ji_c_1.gif",
"p_ji_e_1.gif", "p_ji_w_1.gif", "p_ji_s_1.gif", "p_ji_n_1.gif",
]
def parseTehai(s):
if len(s) != 28:
print("error in {}, len(s)={}".format(sys._getframe().f_code.co_name, len(s)))
sys.exit()
indexes, tehai = [], []
for i in range(14):
pos = i * 2
idx = tileKeyIndex.index(s[pos:pos + 2])
indexes.append(idx)
tehai.append(s[pos:pos + 2])
return indexes, tehai
def enumFile():
files = []
for v in os.listdir("./"):
if os.path.isfile(v) and v.startswith("tenhoh_"):
files.append(v)
return files
def readFile(fileName):
with open(fileName, "r") as f:
return f.read()
def tileIndexesToImage(indexes):
images = []
for idx in indexes:
imageFile = os.path.join("./images", haiImageNames[idx])
im = PIL.Image.open(imageFile)
images.append(im)
imageWidth = 0
maxHeight = 0
for im in images:
imageWidth += im.width
if im.height > maxHeight:
maxHeight = im.height
dst = PIL.Image.new('RGB', (imageWidth, maxHeight))
for i, im in enumerate(images):
dst.paste(im, (im.width * i, 0))
return dst
def main():
files = enumFile()
for f in files:
lines = readFile(f).split("\n")
basename = os.path.basename(f)
basename, _ = os.path.splitext(basename)
for j, l in enumerate(lines):
if len(l) < 28:
continue
indexes, tehai = parseTehai(l)
indexes = sorted(indexes)
image = tileIndexesToImage(indexes)
destFile = "{}_{:03d}.png ".format(basename, j)
destFile = os.path.join("./dest", destFile)
image.save(destFile)
if __name__ == "__main__":
main()
# https://mj-king.net/sozai/
# python tehai_2_image.py
The "tenhoh_???. Txt" file in the same folder is automatically read and the image is output to ./dest based on the image in ./images.
** m7s5p2p6s7p4m6p7s6p5m5p2p5p6 **
↓
Sort and convert the image in this way.
Unzip the image data downloaded from "Manko 2", "Tsutsuko 2", "Ryoko 2", and "Character tile 2" to ./images.
The folder structure looks like this, D: \ tmp is the program folder.
Create a folder for output in advance
python tehai_2_image.py
If executed normally, the imaged score will be output to ./dest.
that's all.
Recommended Posts