目標:四人麻雀22人の対戦組み合わせ
四人麻雀で22に人、5卓、毎回二人休みとして、11回戦の麻雀大会をやることになり、組み合わせ表プログラムをpythonで組んでみました。当初、誰かとの対戦回数を完全に2回以下に抑えるのを目指しましたが、一筋縄ではいかない。あまり時間かけても仕方ないと割り切り、ランダム10万回ループまでは対戦2回以下として、10万回超えて時間がかかるようになったら、対戦3回を許容する形にしてみました。完璧な組み合わせを作る必要もないので、コスパとしてはいい方かと。またこれくらい簡単な方がいろいろなバリエーションに対応しやすいですね。
【汎用化済】22人、5卓、2人休み以外にも対応しました。
Pythonコード
import random
import numpy as np
random.seed(1234)
NUM_PLAYERS = 22 # 人数
NUM_TABLES = 5 # 並列に対戦する卓の数
PERSON_TABLE = 4 # 4人卓(固定)
NUM_REST = NUM_PLAYERS - NUM_TABLES * PERSON_TABLE # 一度に休む人の数
NUM_ROUND = 11 # 対戦回数
NUM_THSHOULD = 3 # 1 vs 1 で見たときの最大対戦回数
print(f"四人麻雀{NUM_PLAYERS}人・{NUM_TABLES}卓・{NUM_REST}人休み:組み合わせ")
print(f"{NUM_ROUND}回戦、同じ人との対戦は{NUM_ROUND}回以内")
if NUM_PLAYERS < NUM_TABLES * PERSON_TABLE:
print(f'エラー:プレイヤー{NUM_PLAYERS}人は{NUM_TABLES}卓×{PERSON_TABLE}人よりすくないです')
quit()
players = list(range(NUM_PLAYERS))
print('players:', players)
# 休む人のパターン作成
rest = []
for i in range(NUM_ROUND):
l = []
for j in range(NUM_REST):
l.append(players[(i*NUM_REST + j)%NUM_PLAYERS])
rest.append(l)
print(f'{NUM_ROUND}回線中、休む人のパターン', rest)
def check_max_match(match, candidate) :
m = 0
for j in range(int(len(candidate)/4)):
d = candidate[j*PERSON_TABLE:j*PERSON_TABLE+PERSON_TABLE]
for x in range(PERSON_TABLE):
for y in range(PERSON_TABLE):
if x == y :
continue
m = max(m, match[d[x]][d[y]] + 1)
return m
def update_match(match, candidate) :
for j in range(int(len(candidate)/4)):
# 4人卓ごとに切り出し
d = candidate[j*PERSON_TABLE:j*PERSON_TABLE+PERSON_TABLE]
# 4人卓の二人ペアごとにmatch回数をupdate
for x in range(PERSON_TABLE):
for y in range(PERSON_TABLE):
if x == y :
continue
match[d[x]][d[y]] += 1
return match
def count_match(match) :
nar = np.zeros(NUM_ROUND, dtype=int)
for x in range(len(match)):
for y in range(len(match[x])):
if x >= y:
continue
nar[match[x][y]] += 1
return nar
def create_candidate(playsers, rest, loop) :
candidate = list(set(players) - set(rest[loop]))
random.shuffle(candidate)
return candidate
#================
r = []
n_retry = 0
match_th = 1 # 極力同じ人との対戦回数をこの数字以下にするLOOP_MAXまでretryしたら +1
LOOP_MAX = 100000 # 時間がかかりすぎるので、このretry回数以上になると match_thを緩める
match = np.zeros((len(players), len(players)), dtype=int)
for i in range(NUM_ROUND):
random_loop = True
loop_c = 0
while random_loop :
if n_retry > LOOP_MAX:
match_th += 1
n_retry = 0
#print('***', loop_c)
candidate = create_candidate(players, rest, i)
m = check_max_match(match, candidate)
#print('m:', m)
if m > match_th :
n_retry += 1
else:
match = update_match(match, candidate)
random_loop = False
loop_c += 1
r.append(candidate)
n_match = count_match(match)
print(f'Done! loop:{i}, match max: {match_th}, Retry: {n_retry}, Remaining ', end='')
for i in range(match_th):
print(f'{i}:{n_match[i]} ', end='')
print('')
#================
print(f'マッチ回数表:{match_th}回以下')
#print(match)
for x in range(len(match)):
for y in range(len(match[x])):
if x >= y:
print(' ', end='')
else:
print(f'{match[x][y]} ', end='')
print('')
#================
print('対戦組み合わせ')
for i in range(len(r)): # 11回戦ループ
print(f'{i+1:02}回', end='')
for j in range(len(r[i])): # 20人ループ
if not j % 4:
print('|', end='')
else:
print(' ', end='')
print(f'{r[i][j]:02}', end='')
print('|', end='')
if NUM_REST:
print(f'休|', end='')
for j in range(NUM_REST):
print(f'{rest[i][j]:02}', end='')
if j != NUM_REST-1:
print(' ', end='')
else:
print('|')
else:
print('')
出力例
四人麻雀22人・5卓・2人休み:組み合わせ
11回戦、同じ人との対戦は11回以内
players: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
11回線中、休む人のパターン [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13], [14, 15], [16, 17], [18, 19], [20, 21]]
Done! loop:0, match max: 1, Retry: 0, Remaining 0:201
Done! loop:1, match max: 1, Retry: 118, Remaining 0:171
Done! loop:2, match max: 1, Retry: 55843, Remaining 0:141
Done! loop:3, match max: 2, Retry: 0, Remaining 0:125 1:92
Done! loop:4, match max: 2, Retry: 29, Remaining 0:110 1:92
Done! loop:5, match max: 2, Retry: 69, Remaining 0:96 1:90
Done! loop:6, match max: 2, Retry: 960, Remaining 0:82 1:88
Done! loop:7, match max: 2, Retry: 28700, Remaining 0:66 1:90
Done! loop:8, match max: 2, Retry: 32087, Remaining 0:51 1:90
Done! loop:9, match max: 3, Retry: 0, Remaining 0:46 1:84 2:87
Done! loop:10, match max: 3, Retry: 11, Remaining 0:40 1:78 2:87
マッチ回数表:3回以下
2 2 2 1 0 2 0 0 1 3 2 3 3 1 1 1 2 1 2 0 1
1 0 3 2 1 1 1 3 1 2 1 1 3 0 1 0 2 2 1 2
2 2 3 1 0 3 0 2 1 1 1 1 3 1 2 2 0 0 2
1 2 2 1 0 1 2 2 1 2 2 2 0 2 2 1 1 2
2 1 2 1 1 2 1 2 1 2 1 2 0 2 1 1 1
1 2 3 1 1 2 0 1 2 1 2 2 2 1 0 0
2 0 1 2 3 1 2 1 3 2 0 1 1 1 2
2 1 2 2 1 2 3 1 2 2 0 2 2 0
1 2 1 1 2 0 2 0 3 3 2 1 2
1 3 2 0 3 1 2 1 2 1 3 1
0 0 3 1 0 2 2 2 2 0 0
2 0 1 1 0 1 1 1 3 1
2 0 0 1 3 2 2 3 2
0 1 2 1 0 3 1 2
3 2 0 0 1 2 2
2 0 2 2 2 2
3 0 0 2 3
1 2 2 1
1 2 2
2 1
1
対戦組み合わせ
01回|21 15 06 11|18 09 08 10|19 20 07 14|17 13 12 03|04 02 05 16|休|00 01|
02回|16 15 14 09|10 00 06 13|18 05 19 11|17 08 21 20|07 04 12 01|休|02 03|
03回|16 17 07 10|03 14 02 21|12 18 06 20|01 09 00 11|15 08 19 13|休|04 05|
04回|05 18 17 03|21 16 15 14|10 02 04 08|12 20 11 09|13 01 00 19|休|06 07|
05回|02 03 05 15|00 18 12 04|01 11 14 20|07 10 17 19|21 13 06 16|休|08 09|
06回|16 13 20 07|15 06 02 00|12 17 19 08|04 05 01 14|09 21 03 18|休|10 11|
07回|15 19 03 20|10 05 16 06|21 08 18 01|11 00 02 17|14 07 04 09|休|12 13|
08回|18 01 02 10|05 13 08 07|20 16 09 17|12 19 00 21|11 06 04 03|休|14 15|
09回|00 03 10 14|12 02 21 13|06 01 19 09|05 08 07 11|04 15 18 20|休|16 17|
10回|11 09 20 12|17 05 02 08|14 06 15 07|04 21 01 16|00 13 10 03|休|18 19|
11回|03 07 11 06|13 19 10 04|08 18 02 15|16 17 00 12|01 05 09 14|休|20 21|
四人麻雀13人・3卓・1人休み:組み合わせ
13回戦、同じ人との対戦は13回以内
players: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
13回線中、休む人のパターン [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]]
Done! loop:0, match max: 1, Retry: 0, Remaining 0:60
Done! loop:1, match max: 2, Retry: 0, Remaining 0:44 1:32
Done! loop:2, match max: 2, Retry: 0, Remaining 0:32 1:38
Done! loop:3, match max: 2, Retry: 12, Remaining 0:20 1:44
Done! loop:4, match max: 2, Retry: 44, Remaining 0:15 1:36
Done! loop:5, match max: 2, Retry: 2980, Remaining 0:9 1:30
Done! loop:6, match max: 3, Retry: 0, Remaining 0:8 1:25 2:34
Done! loop:7, match max: 3, Retry: 8, Remaining 0:6 1:22 2:28
Done! loop:8, match max: 4, Retry: 0, Remaining 0:3 1:20 2:27 3:24
Done! loop:9, match max: 4, Retry: 1, Remaining 0:1 1:18 2:25 3:24
Done! loop:10, match max: 4, Retry: 3, Remaining 0:1 1:12 2:26 3:22
Done! loop:11, match max: 4, Retry: 107, Remaining 0:0 1:8 2:22 3:28
Done! loop:12, match max: 4, Retry: 521, Remaining 0:0 1:7 2:13 3:31
マッチ回数表:4回以下
3 3 4 3 1 3 4 2 2 4 4 3
4 1 3 4 3 1 2 4 3 4 4
4 3 4 2 2 3 3 1 4 3
3 4 4 3 3 3 3 3 1
4 3 3 3 3 3 2 3
2 3 2 4 4 2 2
4 4 3 3 1 4
2 4 4 4 2
4 3 4 4
2 1 3
3 3
4
対戦組み合わせ
01回|03 04 09 05|12 07 06 10|11 01 02 08|休|00|
02回|06 05 02 03|00 08 09 10|07 12 11 04|休|01|
03回|04 09 06 08|07 03 10 00|12 11 01 05|休|02|
04回|05 07 08 11|02 09 12 00|10 06 04 01|休|03|
05回|02 10 03 11|07 00 08 06|05 12 01 09|休|04|
06回|11 06 00 03|04 08 12 10|02 07 01 09|休|05|
07回|02 01 09 05|08 10 12 11|03 07 04 00|休|06|
08回|05 03 04 02|11 00 10 01|09 06 08 12|休|07|
09回|02 12 01 06|03 05 10 00|07 09 11 04|休|08|
10回|01 05 10 04|08 03 12 06|07 11 02 00|休|09|
11回|06 07 09 03|11 01 12 00|04 05 02 08|休|10|
12回|10 07 06 05|02 00 04 12|01 08 03 09|休|11|
13回|11 03 08 02|00 01 04 06|07 05 09 10|休|12|
コメント