import random import numpy import argparse import yaml TABLEAU_SLOTS = 7 MAX_GAIN = 80.0 RUN_GAIN = 4.0 PASS_GAIN = 8.0 FIRST_PASS = 3 TRIALS = 100000 def run_gain(play_num, base_run_gain): return min(play_num * base_run_gain, MAX_GAIN) def pass_gain(play_num, base_pass_gain, first_pass): if (play_num < first_pass): return 0.0 else: return min((play_num - (first_pass - 1)) * base_pass_gain, MAX_GAIN) def add_tableau_cards(deck, tableau, count): for ii in range(count): tableau.insert(0, deck.pop()) def deal_initial_tableau(deck, tableau_slots): tableau = [] random.shuffle(deck) add_tableau_cards(deck, tableau, tableau_slots) return tableau def test_inner_matches(tableau, start, target_card): for ii in range(start, len(tableau)): match_card = tableau[ii] if (match_card['color'] != target_card['color']) and (abs(match_card['value'] - target_card['value']) == 1): return True, ii return False, 0 def remove_match(tableau): match_found = False for ii in range(len(tableau)): target_index = ii match_found, match_index = test_inner_matches(tableau, ii + 1, tableau[ii]) if (match_found): break if match_found: #make sure to delete the match_index first, it's later in the list del tableau[match_index] del tableau[target_index] return match_found def run(tableau_slots, base_run_gain, base_pass_gain, first_pass, big_plays, max_big_plays): deck = [] for ii in range(2): for jj in range(13): deck.append({'color':0, 'value':jj}) deck.append({'color':1, 'value':jj}) tableau = deal_initial_tableau(deck, tableau_slots) current_play = 0 big_plays_used = 0 while (run_gain(current_play, base_run_gain) < MAX_GAIN) and (pass_gain(current_play, base_pass_gain, first_pass) < MAX_GAIN): match_found = False if not remove_match(tableau): # if we have a big play available, try it if big_plays_used < max_big_plays: failure_rate = big_plays['default'] # see if we have a better rate if big_plays_used < len(big_plays['start_values']): failure_rate = big_plays['start_values'][big_plays_used] # did we succeed? if (random.random() >= failure_rate): # add another tableau card, replacing the last one if we already have a successful one if len(tableau) > tableau_slots: tableau.pop(0) add_tableau_cards(deck, tableau, 1) # finally, check to see if we now have a match match_found = remove_match(tableau) big_plays_used += 1 else: match_found = True if match_found: add_tableau_cards(deck, tableau, 2) current_play += 1 else: break return run_gain(current_play, base_run_gain), pass_gain(current_play, base_pass_gain, first_pass) def run_many(tableau_slots, base_run_gain, base_pass_gain, first_pass, trials, big_plays, max_big_plays): run_results = [] pass_results = [] run_first_down = 0.0 run_score = 0.0 pass_first_down = 0.0 pass_score = 0.0 for ii in range(trials): run_gain, pass_gain = run(tableau_slots, base_run_gain, base_pass_gain, first_pass, big_plays, max_big_plays) run_results.append(run_gain) pass_results.append(pass_gain) if run_gain >= 80.0: run_first_down += 1.0 run_score += 1.0 elif run_gain >= 40.0: run_first_down += 1.0 if pass_gain >= 80.0: pass_first_down += 1.0 pass_score += 1.0 elif pass_gain >= 40.0: pass_first_down += 1.0 run_results_array = numpy.array(run_results) pass_results_array = numpy.array(pass_results) print("Maximum big plays: {0}".format(max_big_plays)) print("Run results:") print("Mean: {0}".format(run_results_array.mean())) print("Median: {0}".format(numpy.median(run_results_array))) print("Standard deviation: {0}".format(run_results_array.std())) print("First down %: {:.2%}".format(run_first_down/trials)) print("Scoring %: {:.2%}".format(run_score/trials)) print("Pass results:") print("Mean: {0}".format(pass_results_array.mean())) print("Median: {0}".format(numpy.median(pass_results_array))) print("Standard deviation: {0}\n".format(pass_results_array.std())) print("First down %: {:.2%}".format(pass_first_down/trials)) print("Scoring %: {:.2%}".format(pass_score/trials)) def load_big_plays(): f = open('big_play.yaml') big_plays = yaml.safe_load(f) f.close() return big_plays def main(): parser = argparse.ArgumentParser() parser.add_argument('-r', '--run-gain', dest='run_gain', type=int, default=RUN_GAIN, help='How many yards are gained per match on a run.') parser.add_argument('-p', '--pass-gain', dest='pass_gain', type=int, default=PASS_GAIN, help='How many yards are gained per match on a pass.') parser.add_argument('-f', '--first-pass', dest='first_pass', type=int, default=FIRST_PASS, help='What is the first pass that counts?') parser.add_argument('-t', '--tableau-slots', dest='tableau_slots', type=int, default=TABLEAU_SLOTS, help='How many slots are open in the tableau.') parser.add_argument('-c', '--count', dest='trials', type=int, default=TRIALS, help='How many trials to run?') args = parser.parse_args() big_plays = load_big_plays() print("Using {0} card slots, run gain is {1}, pass gain is {2} starting on {3} match.".format(args.tableau_slots, args.run_gain, args.pass_gain, args.first_pass)) print("{0} trials.".format(args.trials)) for ii in range(10): run_many(args.tableau_slots, args.run_gain, args.pass_gain, args.first_pass, args.trials, big_plays, ii) if __name__ == '__main__': main()