Python YuGiOh Master Duel, как мне эффективно найти шанс превратиться в хорошую конечную плату? ⇐ Python

Программы на Python
Anonymous
Python YuGiOh Master Duel, как мне эффективно найти шанс превратиться в хорошую конечную плату?

Сообщение Anonymous »

В игре YoGiOh игрок начинает с вытягивания 5 карт из колоды с 40–60 картами, затем игрок может использовать стартовые карты из этих 5 карт, чтобы создать конечную доску, которую противнику трудно сломать .
Не каждая стартовая рука хороша. Некоторым новичкам для развития нужна одна или несколько других конкретных карт в руке. Оптимизировать колоду для комбинаций из двух карт (комбо) сложно.
Я пишу программу для оценки шансов на составление комбинаций. Это работает, но 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

Вернуться в «Python»