Не каждая стартовая рука хороша. Некоторым новичкам для развития нужна одна или несколько других конкретных карт в руке. Оптимизировать колоду для комбинаций из двух карт (комбо) сложно.
Я пишу программу для оценки шансов на составление комбинаций. Это работает, но 40 секунд для маленькой колоды в 42 карты — это не очень эффективно. Мне нужна оптимизация.
Ввод:
Код карты
Название карты
Количество
Комбо
0
Эффект Вейлера
3
1
Дух Тэньи - Адхара
2
< td>1D
2
Макс "C"3
3Призрачный огр и снежный кролик
1
4
Цветение ясеня и радостная весна
3
5
Невероятная Экклесия, Добродетельная
3
51 56 57 58 5C 5D 5E 5G 5J
6
Душа Меча Мо Йе
3
61 66 67 68 6C 6D 6E 6G 6J< /td>
7
Душа Меча Тайи
2
71 7C 7D
8
Стратегист Души Меча Лунюань
3
81 87 8C 8D 8E 8G 8J
9
Быстиальный Друисвурм
2
А
Бистиал Магнамхут
1
B
Бистиал Болдрейк
1
< td>C
Дух Тэньи - Вишуда
1
< /tr>
D
Дух Тэньи - Ашуна
3
E
Заклятые враги протосов
1
F
Горшок желаний
1
< tr>
G
Появление Души Меча
3
G1 G7 GC GD GE GG GJ
H
Призванный могилой2
ЯБесконечное непостоянство
3
J
Затмение Души Меча
1
Это колода из 42 карт с картами «Душа Меча Теньи». Комбо «1D» означает, что если у игрока есть «Дух Тэни - Адхара» с кодом 1 и «Дух Тэни - Ашуна» с кодом D, рука доступна для игры.
Колодой можно играть. быть закодировано как 0001122234445556667788899ABCDDDEFGGGHHIIIJ .Пояснение: «000», потому что мы используем 3 копии карты «Эффект вуалера» с кодом 0.
Рука с комбо содержит символы в разделе комбо. 04568 содержит числа 56 и 68: это означает, что можно играть в две разные комбинации.
Код: Выделить всё
from itertools import combinations
from collections import Counter
from math import comb
import functools
import operator
import time
import multiprocessing
import concurrent.futures
#multi thread
number_threads = 10
number_process = 6
#cut list into equal size
def chunkify(iterable,n):
lst = list(iterable)
return [lst[i::n] for i in range(n)]
#multi thread stuff END
######INPUT
deck_input = '0001122234445556667788899ABCDDDEFGGGHHIIIJ'
success_input= '1D 51 56 57 58 5C 5D 5E 5G 5J 61 66 67 68 6C 6D 6E 6G 6J 71 7C 7D 81 87 8C 8D 8E 8G 8J G1 G7 GC GD GE GG GJ'
number_card_in_hand = 5
######INPUT END
#process inputs
deck_counter = Counter(deck_input)
all_possible_hand_combination = list(combinations(deck_input, number_card_in_hand))
successes_list_of_counter = []
for combo in success_input.split(' '):
successes_list_of_counter.append(Counter(combo))
successes_set_of_counter = []
#remove duplicates of counter objects
for i in successes_list_of_counter:
if i not in successes_set_of_counter:
successes_set_of_counter.append(i)
#process inputs END
#test if any pattern of success is included in hand, give score depends on the amount of different starters in hand
def is_success_with_score(hand, successes_set_of_counter = successes_set_of_counter):
counter_hand = Counter(hand)
res = 0
for s in successes_set_of_counter:
if counter_hand >= s:
res+=1
res = min (res,len(hand))
return res
def countingWorker(possible_hand_chunk):
return count_successes(hand_combination = possible_hand_chunk)
def count_success_thread_starter():
with concurrent.futures.ThreadPoolExecutor(max_workers=number_threads) as executor:
worker_input = chunkify(all_possible_hand_combination,number_threads)
futures = [executor.submit(countingWorker, chunk) for chunk in worker_input]
res={"hand_with_starter":0, "total_number_starter":0}
for future in futures:
fr = future.result() # block until a result is returned
res["hand_with_starter"] += fr["hand_with_starter"]
res["total_number_starter"] += fr["total_number_starter"]
return res
def count_success_process_starter():
pool = multiprocessing.Pool(processes=number_process)
worker_inputs = chunkify(all_possible_hand_combination,number_threads)
res={"hand_with_starter":0, "total_number_starter":0}
for worker_result in pool.map(countingWorker, worker_inputs):
res["hand_with_starter"] += worker_result["hand_with_starter"]
res["total_number_starter"] += worker_result["total_number_starter"]
return res
def count_successes(hand_combination = all_possible_hand_combination, deck = deck_input, number_card_in_hand = number_card_in_hand, successes_set_of_counter = successes_set_of_counter):
res={"hand_with_starter":0, "total_number_starter":0}
for hand_tuple in hand_combination:
success_score = is_success_with_score(hand_tuple)
if success_score > 0:
res["hand_with_starter"]+=1
res["total_number_starter"] += success_score
return res
def total_hands(deck = deck_input, number_card_in_hand = number_card_in_hand):
return comb(len(deck), number_card_in_hand)
print('Deck:',deck_input)
print('Deck Counter:',deck_counter)
print('Deck Size:',len(deck_input))
print('Hand Size:',number_card_in_hand)
all_possible_hand_combination = list(combinations(deck_input, number_card_in_hand))
time_start = time.time()
c = count_success_thread_starter()
print('Chance to have at least 1 starter',c["hand_with_starter"]/total_hands())
print('average amount of different starters in hand',c["total_number_starter"]/total_hands())
time_end = time.time()
print('time passed:', time_end-time_start)
Код: Выделить всё
Deck: 0001122234445556667788899ABCDDDEFGGGHHIIIJ
Deck Size: 42
Hand Size: 5
Chance to have at least 1 starter 0.8039293825558267
average amount of different starters in hand 1.921834370165564
time passed: 38.807377576828
Я думал, что генератор комбинаций работает медленно, но кэширование списка заняло всего 0,04 секунды.
Я попробовал многопоточность, многопроцессорность.Результаты такие же или хуже.
Должен ли я использовать numpy и умножать тензоры?
Подробнее здесь: https://stackoverflow.com/questions/790 ... developing