From dc4079864173828c11394e7542e79d3f44c1346a Mon Sep 17 00:00:00 2001 From: "jakub.salavec" Date: Wed, 23 Apr 2025 16:56:45 +0200 Subject: [PATCH] Added - hobbit live draft (and support for drafting from shared pool and hobbit past games evaluator for draft bots) --- .../draft-table/hobbitTableDraft.json | 434 ++++++++++++++++++ .../draft3/TableDraftDefinitionBuilder.java | 89 +++- .../evaluator/AbstractDraftCardEvaluator.java | 8 +- .../lotro/draft3/evaluator/Evaluator.java | 52 ++- .../evaluator/HobbitDraftCardEvaluator.java | 208 +++++++++ 5 files changed, 769 insertions(+), 22 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-cards/src/main/resources/draft-table/hobbitTableDraft.json create mode 100644 gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/HobbitDraftCardEvaluator.java diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/draft-table/hobbitTableDraft.json b/gemp-lotr/gemp-lotr-cards/src/main/resources/draft-table/hobbitTableDraft.json new file mode 100644 index 000000000..063affb07 --- /dev/null +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/draft-table/hobbitTableDraft.json @@ -0,0 +1,434 @@ +{ + "name": "Hobbit Booster Draft", + "code": "hobbit_table_draft", + "format": "limited_hobbit", + "max-players": 4, + "starting-collection": [ + { + "size": 68, + "card-list": [ + "30_1" , "30_2" , "30_3" , "30_4" , "30_5" , "30_6" , "30_7" , "30_8" , + "30_9" , "30_10", "30_11", "30_12", "30_13", "30_14", "30_15", "30_16", + "30_17", "30_18", "30_19", "30_20", "30_21", "30_22", "30_23", "30_24", + "30_29", "30_30", "30_31", "30_47", "30_48", "30_32", "30_32", "30_32", + "30_33", "30_33", "30_34", "30_34", "30_35", "30_35", "30_35", "30_35", + "30_36", "30_36", "30_37", "30_37", "30_38", "30_38", "30_39", "30_39", + "30_39", "30_40", "30_40", "30_40", "30_41", "30_41", "30_42", "30_42", + "30_42", "30_42", "30_66", "30_49", "30_50", "30_51", "30_52", "30_53", + "30_54", "30_55", "30_56", "30_57" + ] + }, + { "size": 1, "card-list": ["30_25", "30_26", "30_27", "30_28"] }, + { "size": 1, "card-list": ["30_43", "30_44", "30_45", "30_46"] } + ], + "card-sets": [ + { + "set-name": "free-peoples-pack", + "card-set": [ + "30_1" , "30_1" , "30_3" , "30_3" , "30_4" , "30_4" , "30_13", "30_13", + "30_14", "30_14", "30_20", "30_20", "30_23", "30_23", "30_24", "30_24", + "30_30", "30_30", "30_31", "30_31", "30_58", "30_59", "30_60", "30_61", + "30_62", "30_63", "30_64", "30_65" + ] + }, + { + "set-name": "swarm-pack-1", + "card-set": [ + "31_30", "31_30", "31_30", "31_30", "31_31", "31_31", "31_31", "31_31", + "31_32", "31_32", "31_32", "31_32", "31_34", "31_34", "31_35", "31_35", + "31_35", "31_35", "31_36", "31_36", "31_49", "31_49", "31_49", "31_51", + "31_51", "31_51", "31_51", "31_52", "31_52", "31_52", "31_53", "31_53", + "31_53", "31_53", "31_54", "31_54", "31_55", "31_55", "31_55", "31_55" + ] + }, + { + "set-name": "swarm-pack-2", + "card-set": [ + "32_27", "32_27", "32_27", "32_27", "32_28", "32_28", "32_28", "32_28", + "32_31", "32_31", "32_31", "32_32", "32_32", "32_32", "32_33", "32_33", + "32_33", "32_34", "32_34", "32_34", "32_36", "32_36", "32_36", "32_38", + "32_38", "32_40", "32_40", "32_40", "32_41", "32_41", "32_41", "32_41", + "32_42", "32_42", "32_42", "32_42", "32_43", "32_43", "32_43", "32_43" + ] + }, + { + "set-name": "swarm-pack-3", + "card-set": [ + "33_38", "33_38", "33_38", "33_38", "33_39", "33_39", "33_39", "33_39", + "33_40", "33_40", "33_40", "33_41", "33_41", "33_41", "33_43", "33_43", + "33_45", "33_45", "33_45", "33_45", "33_46", "33_46", "33_46", "33_47", + "33_47", "33_47", "33_47", "33_48", "33_48", "33_48", "33_49", "33_49", + "33_49", "33_49", "33_50", "33_50", "33_50", "33_51", "33_51", "33_51" + ] + }, + { + "set-name": "beatdown-pack-1", + "card-set": [ + "31_19", "31_19", "31_19", "31_19", "31_20", "31_20", "31_20", "31_21", + "31_21", "31_21", "31_23", "31_23", "31_23", "31_24", "31_24", "31_26", + "31_26", "31_26", "31_27", "31_27", "31_27", "31_27", "31_28", "31_28", + "31_28", "31_56", "31_56", "31_56", "31_58", "31_58", "31_58", "31_59", + "31_59", "31_59", "31_60", "31_60", "31_60", "31_61", "31_61", "31_61" + ] + }, + { + "set-name": "beatdown-pack-2", + "card-set": [ + "32_37", "32_37", "32_37", "32_37", "32_44", "32_44", "32_45", "32_45", + "32_45", "32_45", "32_50", "32_50", "32_51", "32_51", "32_51", "32_51", + "32_52", "32_52", "32_52", "32_52", "32_54", "32_54", "32_54", "32_55", + "32_55", "32_56", "32_56", "32_56", "32_58", "32_58", "32_58", "32_59", + "32_60", "32_61", "32_62", "32_63", "32_64", "32_65", "32_66", "32_67" + ] + }, + { + "set-name": "beatdown-pack-3", + "card-set": [ + "33_24", "33_24", "33_24", "33_25", "33_25", "33_25", "33_26", "33_26", + "33_26", "33_27", "33_27", "33_27", "33_28", "33_28", "33_28", "33_29", + "33_29", "33_29", "33_30", "33_30", "33_30", "33_31", "33_31", "33_31", + "33_32", "33_32", "33_32", "33_34", "33_34", "33_34", "33_35", "33_35", + "33_35", "33_42", "33_42", "33_42", "33_42", "33_44", "33_44", "33_44" + ] + }, + { + "set-name": "pack-a-bilbo", + "card-set": [ + "31_38", "31_38", "31_38", "31_39", "31_39", "31_40", "31_40", "31_41", + "31_41", "31_41", "31_42", "31_42", "31_42", "31_43", "31_43", "31_22", + "31_22", "31_22", "31_57", "31_57", "31_45", "31_45" + ] + }, + { + "set-name": "pack-b-dain", + "card-set": [ + "32_1" , "32_1" , "32_1" , "32_2" , "32_2" , "32_2" , "32_4" , "32_4" , + "32_5" , "32_5" , "32_6" , "32_6" , "32_8" , "32_8" , "32_8" , "32_26", + "32_26", "32_30", "32_30", "32_30", "32_49", "32_49" + ] + }, + { + "set-name": "pack-c-esgaroth", + "card-set": [ + "32_15", "32_15", "32_15", "32_16", "32_16", "32_17", "32_17", "32_18", + "32_18", "32_19", "32_19", "32_19", "32_20", "32_20", "32_20", "32_25", + "32_25", "32_25", "32_53", "32_53", "32_47", "32_47" + ] + }, + { + "set-name": "pack-d-mirkwood", + "card-set": [ + "31_3" , "31_3" , "31_3" , "31_8" , "31_8" , "31_9" , "31_9" , "31_10", + "31_10", "31_11", "31_11", "31_11", "31_12", "31_12", "31_12", "31_29", + "31_29", "31_37", "31_37", "31_37", "31_46", "31_46" + ] + }, + { + "set-name": "pack-e-thorin", + "card-set": [ + "31_1" , "31_1" , "31_2" , "31_2" , "31_2" , "31_4" , "31_4" , "31_5" , + "31_5" , "31_5" , "31_6" , "31_6" , "31_7" , "31_7" , "31_7" , "31_33", + "31_33", "31_33", "31_48", "31_48", "31_47", "31_47" + ] + }, + { + "set-name": "pack-f-thrain", + "card-set": [ + "32_3" , "32_3" , "32_3" , "32_7" , "32_7" , "32_9" , "32_9" , "32_9" , + "32_10", "32_10", "32_11", "32_11", "32_11", "32_12", "32_12", "32_29", + "32_29", "32_35", "32_35", "32_35", "32_48", "32_48" + ] + }, + { + "set-name": "pack-g-white-council", + "card-set": [ + "32_13", "32_13", "32_13", "32_14", "32_14", "32_21", "32_21", "32_22", + "32_22", "32_23", "32_23", "32_23", "32_24", "32_24", "32_24", "32_39", + "32_39", "32_57", "32_57", "32_57", "32_46", "32_46" + ] + }, + { + "set-name": "pack-h-wizard", + "card-set": [ + "31_13", "31_13", "31_13", "31_14", "31_14", "31_15", "31_15", "31_16", + "31_16", "31_17", "31_17", "31_17", "31_18", "31_18", "31_18", "31_25", + "31_25", "31_25", "31_50", "31_50", "31_44", "31_44" + ] + }, + { + "set-name": "pack-i-balin", + "card-set": [ + "33_1" , "33_1" , "33_3" , "33_3" , "33_3" , "33_4" , "33_4" , "33_10", + "33_10", "33_10", "33_11", "33_11", "33_11", "33_12", "33_12", "33_36", + "33_36", "33_36", "33_59", "33_59", "33_56", "33_56" + ] + }, + { + "set-name": "pack-j-blue-mountains", + "card-set": [ + "33_2" , "33_2" , "33_5" , "33_5" , "33_5" , "33_6" , "33_6" , "33_6" , + "33_7" , "33_7" , "33_8" , "33_8" , "33_9" , "33_9" , "33_9" , "33_37", + "33_37", "33_37", "33_60", "33_60", "33_58", "33_58" + ] + }, + { + "set-name": "pack-k-rivendell", + "card-set": [ + "33_13", "33_13", "33_13", "33_14", "33_14", "33_14", "33_15", "33_15", + "33_16", "33_16", "33_17", "33_17", "33_17", "33_18", "33_18", "33_33", + "33_33", "33_33", "33_61", "33_61", "33_57", "33_57" + ] + }, + { + "set-name": "pack-l-travellers", + "card-set": [ + "33_19", "33_19", "33_20", "33_20", "33_21", "33_21", "33_52", "33_52", + "33_52", "33_53", "33_53", "33_53", "33_54", "33_54", "33_54", "33_22", + "33_22", "33_23", "33_23", "33_23", "33_55", "33_55" + ] + }, + { + "set-name": "chosen-swarm-pack", + "choose": 1, + "set-set": ["swarm-pack-1", "swarm-pack-2", "swarm-pack-3"] + }, + { + "set-name": "chosen-beatdown-pack", + "choose": 1, + "set-set": ["beatdown-pack-1", "beatdown-pack-2", "beatdown-pack-3"] + }, + { + "set-name": "chosen-burglar-pack", + "choose": 1, + "set-set": ["pack-a-bilbo", "pack-i-balin", "pack-l-travellers"] + }, + { + "set-name": "chosen-arming-pack", + "choose": 1, + "set-set": ["pack-e-thorin", "pack-f-thrain", "pack-j-blue-mountains"] + }, + { + "set-name": "chosen-allies-pack", + "choose": 1, + "set-set": ["pack-b-dain", "pack-c-esgaroth", "pack-d-mirkwood"] + }, + { + "set-name": "chosen-wises-pack", + "choose": 1, + "set-set": ["pack-g-white-council", "pack-h-wizard", "pack-k-rivendell"] + }, + { + "set-name": "chosen-supplementary-packs", + "choose": 2, + "set-set": [ + "chosen-burglar-pack", "chosen-arming-pack" , "chosen-allies-pack" , + "chosen-wises-pack" + ] + } + ], + "pools": [ + { + "pool-name": "draft-pool", + "set-set": [ + "chosen-supplementary-packs", + "chosen-swarm-pack" , + "chosen-beatdown-pack" , + "free-peoples-pack" , + "free-peoples-pack" + ] + } + ], + "boosters": [ + { + "rounds": [ 1, 2, 3, 4, 5 ], + "cards" : [ {"count": 9, "set-name": "draft-pool"} ] + } + ], + "card-values": [ + {"card": "33_7" , "value": 1.0 }, + {"card": "33_44", "value": 0.8333787095017696 }, + {"card": "32_67", "value": 0.8203103729921045 }, + {"card": "30_31", "value": 0.7296487884563028 }, + {"card": "32_18", "value": 0.6634903348761231 }, + {"card": "31_6" , "value": 0.6602232507487068 }, + {"card": "31_38", "value": 0.6471549142390417 }, + {"card": "31_5" , "value": 0.6471549142390417 }, + {"card": "33_42", "value": 0.5867138578818405 }, + {"card": "32_24", "value": 0.5513204465014974 }, + {"card": "31_20", "value": 0.5360740539068881 }, + {"card": "32_13", "value": 0.5317179417369997 }, + {"card": "32_40", "value": 0.5273618295671113 }, + {"card": "32_59", "value": 0.5262728015246393 }, + {"card": "32_60", "value": 0.5262728015246393 }, + {"card": "31_1" , "value": 0.5262728015246393 }, + {"card": "31_48", "value": 0.5132044650149742 }, + {"card": "33_37", "value": 0.5099373808875578 }, + {"card": "33_35", "value": 0.5012251565477811 }, + {"card": "33_39", "value": 0.4911516471549142 }, + {"card": "32_23", "value": 0.49033487612306015 }, + {"card": "32_66", "value": 0.4838007078682276 }, + {"card": "33_41", "value": 0.4827116798257555 }, + {"card": "31_26", "value": 0.47944459569833925 }, + {"card": "32_54", "value": 0.47944459569833925 }, + {"card": "32_4" , "value": 0.47399945548597877 }, + {"card": "32_36", "value": 0.4674652872311462 }, + {"card": "32_50", "value": 0.46419820310372994 }, + {"card": "32_43", "value": 0.4486795534985026 }, + {"card": "33_21", "value": 0.4478627824666485 }, + {"card": "32_45", "value": 0.44377892730737817 }, + {"card": "31_24", "value": 0.44132861421181596 }, + {"card": "31_22", "value": 0.4402395861693439 }, + {"card": "33_45", "value": 0.43887830111625376 }, + {"card": "33_38", "value": 0.43642798802069155 }, + {"card": "31_13", "value": 0.43152736182956714 }, + {"card": "31_19", "value": 0.4290770487340049 }, + {"card": "30_3" , "value": 0.42145385243670025 }, + {"card": "31_21", "value": 0.418459025319902 }, + {"card": "32_61", "value": 0.418459025319902 }, + {"card": "31_10", "value": 0.4151919411924857 }, + {"card": "31_37", "value": 0.41410291315001363 }, + {"card": "33_52", "value": 0.41410291315001363 }, + {"card": "33_40", "value": 0.4053906888102369 }, + {"card": "31_18", "value": 0.4010345766403485 }, + {"card": "31_23", "value": 0.3966784644704601 }, + {"card": "31_58", "value": 0.39341138034304385 }, + {"card": "30_1" , "value": 0.3920500952899537 }, + {"card": "31_61", "value": 0.39123332425809965 }, + {"card": "31_28", "value": 0.38905526817315544 }, + {"card": "32_53", "value": 0.38578818404573917 }, + {"card": "32_56", "value": 0.3825210999183229 }, + {"card": "32_51", "value": 0.37598693166349034 }, + {"card": "32_39", "value": 0.37598693166349034 }, + {"card": "32_52", "value": 0.37271984753607407 }, + {"card": "32_9" , "value": 0.37054179145112986 }, + {"card": "31_9" , "value": 0.3694527634086578 }, + {"card": "30_23", "value": 0.36836373536618566 }, + {"card": "32_42", "value": 0.3645521372175334 }, + {"card": "32_7" , "value": 0.35638442689899263 }, + {"card": "32_58", "value": 0.35311734277157636 }, + {"card": "32_41", "value": 0.35066702967601415 }, + {"card": "31_29", "value": 0.3465831745167438 }, + {"card": "33_20", "value": 0.3465831745167438 }, + {"card": "32_32", "value": 0.3422270623468554 }, + {"card": "31_8" , "value": 0.336781922134495 }, + {"card": "32_55", "value": 0.32861421181595424 }, + {"card": "33_23", "value": 0.3269806697522461 }, + {"card": "30_13", "value": 0.32534712768853796 }, + {"card": "32_63", "value": 0.3237135856248298 }, + {"card": "31_12", "value": 0.313912333242581 }, + {"card": "31_30", "value": 0.30737816498774845 }, + {"card": "33_19", "value": 0.3008439967329159 }, + {"card": "32_30", "value": 0.2986659406479717 }, + {"card": "33_12", "value": 0.2943098284780833 }, + {"card": "31_57", "value": 0.2943098284780833 }, + {"card": "32_31", "value": 0.28886468826572287 }, + {"card": "31_36", "value": 0.28777566022325074 }, + {"card": "32_37", "value": 0.2861421181595426 }, + {"card": "33_43", "value": 0.28450857609583446 }, + {"card": "33_60", "value": 0.2779744078410019 }, + {"card": "31_56", "value": 0.2768853797985298 }, + {"card": "33_17", "value": 0.27470732371358564 }, + {"card": "31_31", "value": 0.2730737816498775 }, + {"card": "32_64", "value": 0.27144023958616936 }, + {"card": "31_59", "value": 0.26708412741628096 }, + {"card": "33_59", "value": 0.26490607133133676 }, + {"card": "32_5" , "value": 0.26490607133133676 }, + {"card": "33_22", "value": 0.26490607133133676 }, + {"card": "32_29", "value": 0.26490607133133676 }, + {"card": "33_54", "value": 0.2638170432888647 }, + {"card": "32_34", "value": 0.2627280152463926 }, + {"card": "33_53", "value": 0.25728287503403213 }, + {"card": "33_47", "value": 0.25183773482167165 }, + {"card": "32_65", "value": 0.25183773482167165 }, + {"card": "31_41", "value": 0.2507487067791996 }, + {"card": "32_38", "value": 0.2502041927579635 }, + {"card": "30_30", "value": 0.2488429077048734 }, + {"card": "32_62", "value": 0.24857065069425538 }, + {"card": "31_14", "value": 0.2453035665668391 }, + {"card": "32_44", "value": 0.2453035665668391 }, + {"card": "31_17", "value": 0.244214538524367 }, + {"card": "32_35", "value": 0.24203648243942283 }, + {"card": "32_2" , "value": 0.23768037026953445 }, + {"card": "33_61", "value": 0.23550231418459025 }, + {"card": "31_60", "value": 0.23441328614211815 }, + {"card": "32_28", "value": 0.23060168799346584 }, + {"card": "31_35", "value": 0.22733460386604956 }, + {"card": "32_11", "value": 0.2267900898448135 }, + {"card": "32_17", "value": 0.22570106180234142 }, + {"card": "32_16", "value": 0.22570106180234142 }, + {"card": "33_36", "value": 0.22461203375986932 }, + {"card": "33_32", "value": 0.22134494963245305 }, + {"card": "33_50", "value": 0.21807786550503674 }, + {"card": "31_27", "value": 0.21671658045194664 }, + {"card": "31_16", "value": 0.20936564116526002 }, + {"card": "33_10", "value": 0.20936564116526002 }, + {"card": "32_15", "value": 0.20936564116526002 }, + {"card": "32_20", "value": 0.20936564116526002 }, + {"card": "33_34", "value": 0.20609855703784372 }, + {"card": "31_43", "value": 0.20609855703784372 }, + {"card": "30_4" , "value": 0.20528178600598965 }, + {"card": "33_27", "value": 0.20500952899537164 }, + {"card": "31_25", "value": 0.20283147291042744 }, + {"card": "33_3" , "value": 0.20065341682548327 }, + {"card": "33_49", "value": 0.20038115981486523 }, + {"card": "31_52", "value": 0.19738633269806696 }, + {"card": "31_49", "value": 0.19303022052817861 }, + {"card": "32_26", "value": 0.1897631364007623 }, + {"card": "33_4" , "value": 0.18649605227334604 }, + {"card": "32_10", "value": 0.18322896814592976 }, + {"card": "32_57", "value": 0.18105091206098556 }, + {"card": "33_8" , "value": 0.17996188401851348 }, + {"card": "31_42", "value": 0.17887285597604138 }, + {"card": "32_22", "value": 0.1734277157636809 }, + {"card": "31_53", "value": 0.1734277157636809 }, + {"card": "32_1" , "value": 0.17016063163626463 }, + {"card": "32_25", "value": 0.17016063163626463 }, + {"card": "33_9" , "value": 0.16798257555132046 }, + {"card": "32_19", "value": 0.16798257555132046 }, + {"card": "32_6" , "value": 0.16689354750884836 }, + {"card": "33_48", "value": 0.16471549142390415 }, + {"card": "33_5" , "value": 0.16362646338143208 }, + {"card": "33_46", "value": 0.16362646338143208 }, + {"card": "31_15", "value": 0.16362646338143208 }, + {"card": "32_8" , "value": 0.16362646338143208 }, + {"card": "31_2" , "value": 0.16362646338143208 }, + {"card": "33_6" , "value": 0.16144840729648788 }, + {"card": "31_32", "value": 0.16117615028586987 }, + {"card": "33_29", "value": 0.1603593792540158 }, + {"card": "31_51", "value": 0.15790906615845357 }, + {"card": "31_3" , "value": 0.1570922951265995 }, + {"card": "33_31", "value": 0.15491423904165533 }, + {"card": "31_34", "value": 0.1521916689354751 }, + {"card": "32_27", "value": 0.15055812687176695 }, + {"card": "32_14", "value": 0.15055812687176695 }, + {"card": "32_21", "value": 0.14729104274435068 }, + {"card": "31_4" , "value": 0.1407568744895181 }, + {"card": "31_7" , "value": 0.13531173427715765 }, + {"card": "33_2" , "value": 0.13422270623468555 }, + {"card": "33_30", "value": 0.13095562210726927 }, + {"card": "31_33", "value": 0.1265995099373809 }, + {"card": "33_14", "value": 0.1265995099373809 }, + {"card": "31_55", "value": 0.12605499591614483 }, + {"card": "33_33", "value": 0.1244214538524367 }, + {"card": "30_14", "value": 0.12060985570378437 }, + {"card": "33_25", "value": 0.12006534168254833 }, + {"card": "32_33", "value": 0.11570922951265995 }, + {"card": "31_39", "value": 0.11462020147018785 }, + {"card": "31_40", "value": 0.11135311734277158 }, + {"card": "31_54", "value": 0.11135311734277158 }, + {"card": "31_11", "value": 0.10917506125782739 }, + {"card": "33_28", "value": 0.10917506125782739 }, + {"card": "31_50", "value": 0.1080860332153553 }, + {"card": "33_51", "value": 0.10590797713041111 }, + {"card": "33_13", "value": 0.10264089300299482 }, + {"card": "33_18", "value": 0.10155186496052274 }, + {"card": "33_26", "value": 0.10046283691805064 }, + {"card": "33_15", "value": 0.09501769670569017 }, + {"card": "33_24", "value": 0.0917506125782739 }, + {"card": "33_1" , "value": 0.08194936019602504 }, + {"card": "32_12", "value": 0.08194936019602504 }, + {"card": "33_11", "value": 0.08086033215355296 }, + {"card": "30_24", "value": 0.015790906615845358}, + {"card": "30_20", "value": 0.010890280424720936} + ] +} diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/TableDraftDefinitionBuilder.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/TableDraftDefinitionBuilder.java index 825cfd93e..f6a4f66d8 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/TableDraftDefinitionBuilder.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/TableDraftDefinitionBuilder.java @@ -18,6 +18,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; public class TableDraftDefinitionBuilder { private static final int HIGH_ENOUGH_PRIME_NUMBER = 8963; @@ -45,7 +47,8 @@ public class TableDraftDefinitionBuilder { int maxPlayers = ((Number) definition.get("max-players")).intValue(); StartingCollectionProducer startingCollectionProducer = buildStartingCollectionProducer((JSONArray) definition.get("starting-collection")); - BoosterProducer boosterProducer = buildBoosterProducer((JSONArray) definition.get("card-sets"), (JSONArray) definition.get("boosters")); + // test if booster producer can be made from this json + BoosterProducer testBoosterProducer = buildBoosterProducer((JSONArray) definition.get("card-sets"), (JSONArray) definition.get("boosters"), (JSONArray) definition.get("pools")); Map cardValues = buildCardValues((JSONArray) definition.get("card-values")); @@ -53,6 +56,7 @@ public class TableDraftDefinitionBuilder { return new TableDraftDefinition() { @Override public TableDraft getTableDraft(CollectionsManager collectionsManager, CollectionType collectionType, DraftTimer draftTimer) { + BoosterProducer boosterProducer = buildBoosterProducer((JSONArray) definition.get("card-sets"), (JSONArray) definition.get("boosters"), (JSONArray) definition.get("pools")); return new TableDraftClassic(collectionsManager, collectionType, startingCollectionProducer, boosterProducer, maxPlayers, boosterProducer.getMaxRound(), draftTimer, cardValues); } @@ -90,13 +94,43 @@ public class TableDraftDefinitionBuilder { return tbr; } - private static BoosterProducer buildBoosterProducer(JSONArray cardSets, JSONArray boosters) { + private static BoosterProducer buildBoosterProducer(JSONArray cardSets, JSONArray boosters, JSONArray pools) { Map> cardPools = new HashMap<>(); + Map> setPools = new HashMap<>(); + Map> draftPools = new HashMap<>(); for (JSONObject cardSet : (Iterable) cardSets) { String name = (String) cardSet.get("set-name"); - List cards = (List) cardSet.get("card-set"); - cardPools.put(name, cards); + if (cardSet.containsKey("card-set")) { + List cards = (List) cardSet.get("card-set"); + cardPools.put(name, cards); + } else if (cardSet.containsKey("set-set") && cardSet.containsKey("choose")) { + List setNames = (List) cardSet.get("set-set"); + Collections.shuffle(setNames); + int howMany = ((Number) cardSet.get("choose")).intValue(); + List chosenSetNames = new ArrayList<>(); + if (howMany <= setNames.size()) { + for (int i = 0; i < howMany; i++) { + chosenSetNames.add(setNames.get(i)); + } + setPools.put(name, chosenSetNames); + } else { + throw new IllegalArgumentException("Invalid JSON content"); + } + } else { + throw new IllegalArgumentException("Invalid JSON content"); + } + } + + if (pools != null) { + for (JSONObject cardSet : (Iterable) pools) { + String name = (String) cardSet.get("pool-name"); + draftPools.put(name, new ArrayList<>()); + List sets = (List) cardSet.get("set-set"); + for (String set : sets) { + addSetToPool(cardPools, setPools, draftPools, name, set); + } + } } Map>> boosterPlan = new HashMap<>(); @@ -132,10 +166,25 @@ public class TableDraftDefinitionBuilder { } return new BoosterProducer() { + Lock poolLock = new ReentrantLock(); + @Override public Booster getBooster(int round) { List pickedCards = new ArrayList<>(); - boosterPlan.get(round).forEach(pair -> pickedCards.addAll(pickRandom(cardPools.get(pair.getLeft()), pair.getRight()))); + boosterPlan.get(round).forEach(pair -> { + if (draftPools.get(pair.getLeft()) == null) { + // opening boosters + pickedCards.addAll(pickRandom(cardPools.get(pair.getLeft()), pair.getRight(), false)); + } else { + // opening cards from draft pool + poolLock.lock(); + try { + pickedCards.addAll(pickRandom(draftPools.get(pair.getLeft()), pair.getRight(), true)); + } finally { + poolLock.unlock(); + } + } + }); return new Booster(pickedCards); } @@ -144,7 +193,7 @@ public class TableDraftDefinitionBuilder { return boosterPlan.keySet().stream().max(Comparator.naturalOrder()).orElse(-1); } - private List pickRandom(List source, int count) { + private List pickRandom(List source, int count, boolean remove) { if (source.isEmpty() || count <= 0) return Collections.emptyList(); int size = source.size(); @@ -154,10 +203,18 @@ public class TableDraftDefinitionBuilder { List result = new ArrayList<>(); Random rand = new Random(); - while (selectedIndexes.size() < count) { - int randomIndex = rand.nextInt(size); - if (selectedIndexes.add(randomIndex)) { - result.add(source.get(randomIndex)); + while (result.size() < count) { + int chosenIndex; + if (size > 0) { + chosenIndex = rand.nextInt(size); + } else { + chosenIndex = 0; + } + if (remove) { + result.add(source.remove(chosenIndex)); + size--; + } else if (selectedIndexes.add(chosenIndex)) { + result.add(source.get(chosenIndex)); } } return result; @@ -165,6 +222,18 @@ public class TableDraftDefinitionBuilder { }; } + private static void addSetToPool(Map> cardPools, Map> setPools, Map> draftPools, String poolName, String setToAdd) { + if (cardPools.containsKey(setToAdd)) { + draftPools.get(poolName).addAll(cardPools.get(setToAdd)); + } else if (setPools.containsKey(setToAdd)) { + for (String setName : setPools.get(setToAdd)) { + addSetToPool(cardPools, setPools, draftPools, poolName, setName); + } + } else { + throw new IllegalArgumentException("Invalid JSON content"); + } + } + private static StartingCollectionProducer buildStartingCollectionProducer(JSONArray jsonArray) { return new StartingCollectionProducer() { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/AbstractDraftCardEvaluator.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/AbstractDraftCardEvaluator.java index 36e7fd24d..bc4123aa4 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/AbstractDraftCardEvaluator.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/AbstractDraftCardEvaluator.java @@ -29,7 +29,7 @@ public abstract class AbstractDraftCardEvaluator { // This is what bots pick according to - public final Map getValuesMap(Map winningMap, Map losingMap, int gamesAnalyzed) { + public Map getValuesMap(Map winningMap, Map losingMap, int gamesAnalyzed) { // Merge win and lose maps (they are kept separate for potential wr info) Map mergedMap = mergeMaps(winningMap, losingMap); @@ -54,7 +54,7 @@ public abstract class AbstractDraftCardEvaluator { return shiftedMap; } - private static Map mergeMaps(Map map1, Map map2) { + static Map mergeMaps(Map map1, Map map2) { Map result = new HashMap<>(map1); map2.forEach((key, value) -> result.merge(key, value, Integer::sum)); @@ -62,7 +62,7 @@ public abstract class AbstractDraftCardEvaluator { return result; } - private Map normalizeCountByDraftPackChance(Map map, int gamesAnalyzed) { + Map normalizeCountByDraftPackChance(Map map, int gamesAnalyzed) { Map normalizedMap = new HashMap<>(); map.forEach((key, value) -> { @@ -155,7 +155,7 @@ public abstract class AbstractDraftCardEvaluator { return fpInflatedMap; } - private Map shift(Map map) { + Map shift(Map map) { double min = map.values().stream().min(Double::compareTo).orElse(0.0); double positiveShift; diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/Evaluator.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/Evaluator.java index 2b491c579..32dd9ee88 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/Evaluator.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/Evaluator.java @@ -1,6 +1,7 @@ package com.gempukku.lotro.draft3.evaluator; import com.gempukku.lotro.common.AppConfig; +import com.gempukku.lotro.game.CardNotFoundException; import com.gempukku.lotro.game.LotroCardBlueprintLibrary; import com.gempukku.lotro.game.ReplayMetadata; import com.gempukku.util.JsonUtils; @@ -46,6 +47,7 @@ public class Evaluator { // Define what we care for assignmentList.add(new Assignment("Limited - FOTR", "draft")); assignmentList.add(new Assignment("Limited - TTT", "draft")); + assignmentList.add(new Assignment("Limited - Hobbit", "draft")); System.out.println("Game history reading started at " + new SimpleDateFormat("HH.mm.ss").format(new Date())); // Load decks from the past @@ -60,29 +62,39 @@ public class Evaluator { FotrDraftCardEvaluator fotrDraftCardEvaluator = new FotrDraftCardEvaluator(library); TttDraftCardEvaluator tttDraftCardEvaluator = new TttDraftCardEvaluator(library); + HobbitDraftCardEvaluator hobbitDraftCardEvaluator = new HobbitDraftCardEvaluator(library); // Send the loaded data to card evaluators -> they convert card counts to values from 0.0 to 1.0 // This is what bots pick according to in FotR drafts var fotrValues = fotrDraftCardEvaluator.getValuesMap(assignmentList.getFirst().winningMap, assignmentList.get(0).losingMap, assignmentList.getFirst().gamesAnalyzed); // Those are values to base fotr draft pools cuts on var fotrPlayRates = fotrDraftCardEvaluator.getPlayRateMap(assignmentList.getFirst().deckCount, assignmentList.getFirst().gamesAnalyzed); + // This is what bots pick according to in TTT drafts var tttValues = tttDraftCardEvaluator.getValuesMap(assignmentList.get(1).winningMap, assignmentList.get(1).losingMap, assignmentList.get(1).gamesAnalyzed); // Those are values to base TTT draft pools cuts on var tttPlayRates = tttDraftCardEvaluator.getPlayRateMap(assignmentList.get(1).deckCount, assignmentList.get(1).gamesAnalyzed); + var hobbitValues = hobbitDraftCardEvaluator.getValuesMap(assignmentList.get(2).winningMap, assignmentList.get(2).losingMap, assignmentList.get(2).gamesAnalyzed); + // Data from solo drafts do not contain rare one ring cards, don't forget to add some value manually after System.out.println("===FOTR VALUES"); + System.out.println("Games analyzes: " + assignmentList.get(0).gamesAnalyzed); printJsonStyle(fotrValues); // For json file - printMapStyle(fotrValues); // For cached maps in evaluators (not being used right now) System.out.println("===FOTR PLAY RATES"); // Regular draft - all rares included, U/C with play rate lower than 0.01 are cut // Power draft - R with play rate lower than 0.02 and U/C with play rate lower than 0.05 are cut - printMapStyle(fotrPlayRates); + printHumanReadable(fotrPlayRates, library); + System.out.println("===TTT VALUES"); + System.out.println("Games analyzes: " + assignmentList.get(1).gamesAnalyzed); printJsonStyle(tttValues); - printMapStyle(tttValues); System.out.println("===TTT PLAY RATES"); - printMapStyle(tttPlayRates); + printHumanReadable(tttPlayRates, library); + + System.out.println("===HOBBIT VALUES"); + System.out.println("Games analyzes: " + assignmentList.get(2).gamesAnalyzed); + printJsonStyle(hobbitValues); + printHumanReadable(hobbitValues, library); } private static void analyzeSummary(Path jsonFile, List assignmentList) { @@ -102,21 +114,29 @@ public class Evaluator { assignment.gamesAnalyzed++; assignment.deckCount.merge(winningDeck.RingBearer.replace("*", "").replace("T", ""), 1, Integer::sum); - assignment.deckCount.merge(winningDeck.Ring.replace("*", "").replace("T", ""), 1, Integer::sum); + if (winningDeck.Ring != null) { + assignment.deckCount.merge(winningDeck.Ring.replace("*", "").replace("T", ""), 1, Integer::sum); + } Set winningCardSet = new HashSet<>(winningDeck.DrawDeck); winningCardSet.forEach(card -> assignment.deckCount.merge(card.replace("*", "").replace("T", ""), 1, Integer::sum)); assignment.deckCount.merge(losingDeck.RingBearer.replace("*", "").replace("T", ""), 1, Integer::sum); - assignment.deckCount.merge(losingDeck.Ring.replace("*", "").replace("T", ""), 1, Integer::sum); + if (losingDeck.Ring != null) { + assignment.deckCount.merge(losingDeck.Ring.replace("*", "").replace("T", ""), 1, Integer::sum); + } Set losingCardSet = new HashSet<>(losingDeck.DrawDeck); losingCardSet.forEach(card -> assignment.deckCount.merge(card.replace("*", "").replace("T", ""), 1, Integer::sum)); assignment.winningMap.merge(winningDeck.RingBearer.replace("*", "").replace("T", ""), 1, Integer::sum); - assignment.winningMap.merge(winningDeck.Ring.replace("*", "").replace("T", ""), 1, Integer::sum); + if (winningDeck.Ring != null) { + assignment.winningMap.merge(winningDeck.Ring.replace("*", "").replace("T", ""), 1, Integer::sum); + } winningDeck.DrawDeck.forEach(card -> assignment.winningMap.merge(card.replace("*", "").replace("T", ""), 1, Integer::sum)); assignment.losingMap.merge(losingDeck.RingBearer.replace("*", "").replace("T", ""), 1, Integer::sum); - assignment.losingMap.merge(losingDeck.Ring.replace("*", "").replace("T", ""), 1, Integer::sum); + if (losingDeck.Ring != null) { + assignment.losingMap.merge(losingDeck.Ring.replace("*", "").replace("T", ""), 1, Integer::sum); + } losingDeck.DrawDeck.forEach(card -> assignment.losingMap.merge(card.replace("*", "").replace("T", ""), 1, Integer::sum)); } } @@ -153,4 +173,20 @@ public class Evaluator { System.out.println(s); }); } + + private static void printHumanReadable(Map toPrint, LotroCardBlueprintLibrary library) { +// 33_44 Lavastone Giant: 0.8333787095017696 + toPrint.entrySet().stream() + .sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())) + .forEach(stringDoubleEntry -> { + try { + String s = stringDoubleEntry.getKey() + " " + + library.getLotroCardBlueprint(stringDoubleEntry.getKey()).getFullName() + ": " + + stringDoubleEntry.getValue(); + System.out.println(s); + } catch (CardNotFoundException ignore) { + + } + }); + } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/HobbitDraftCardEvaluator.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/HobbitDraftCardEvaluator.java new file mode 100644 index 000000000..12ede2e6f --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/evaluator/HobbitDraftCardEvaluator.java @@ -0,0 +1,208 @@ +package com.gempukku.lotro.draft3.evaluator; + +import com.gempukku.lotro.game.LotroCardBlueprintLibrary; +import org.apache.commons.collections4.map.UnmodifiableMap; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HobbitDraftCardEvaluator extends AbstractDraftCardEvaluator { + private static final Map AVERAGE_STARTING_COUNT_MAP = new HashMap<>(); + + private static final List freePeoplesPack = List.of( + "30_1", "30_1", "30_3", "30_3", "30_4", "30_4", "30_13", "30_13", + "30_14", "30_14", "30_20", "30_20", "30_23", "30_23", "30_24", "30_24", + "30_30", "30_30", "30_31", "30_31", "30_58", "30_59", "30_60", "30_61", + "30_62", "30_63", "30_64", "30_65"); + private static final List swarmPack1 = List.of( + "31_30", "31_30", "31_30", "31_30", "31_31", "31_31", "31_31", "31_31", + "31_32", "31_32", "31_32", "31_32", "31_34", "31_34", "31_35", "31_35", + "31_35", "31_35", "31_36", "31_36", "31_49", "31_49", "31_49", "31_51", + "31_51", "31_51", "31_51", "31_52", "31_52", "31_52", "31_53", "31_53", + "31_53", "31_53", "31_54", "31_54", "31_55", "31_55", "31_55", "31_55"); + private static final List swarmPack2 = List.of( + "32_27", "32_27", "32_27", "32_27", "32_28", "32_28", "32_28", "32_28", + "32_31", "32_31", "32_31", "32_32", "32_32", "32_32", "32_33", "32_33", + "32_33", "32_34", "32_34", "32_34", "32_36", "32_36", "32_36", "32_38", + "32_38", "32_40", "32_40", "32_40", "32_41", "32_41", "32_41", "32_41", + "32_42", "32_42", "32_42", "32_42", "32_43", "32_43", "32_43", "32_43"); + private static final List swarmPack3 = List.of( + "33_38", "33_38", "33_38", "33_38", "33_39", "33_39", "33_39", "33_39", + "33_40", "33_40", "33_40", "33_41", "33_41", "33_41", "33_43", "33_43", + "33_45", "33_45", "33_45", "33_45", "33_46", "33_46", "33_46", "33_47", + "33_47", "33_47", "33_47", "33_48", "33_48", "33_48", "33_49", "33_49", + "33_49", "33_49", "33_50", "33_50", "33_50", "33_51", "33_51", "33_51"); + private static final List beatDownPack1 = List.of( + "31_19", "31_19", "31_19", "31_19", "31_20", "31_20", "31_20", "31_21", + "31_21", "31_21", "31_23", "31_23", "31_23", "31_24", "31_24", "31_26", + "31_26", "31_26", "31_27", "31_27", "31_27", "31_27", "31_28", "31_28", + "31_28", "31_56", "31_56", "31_56", "31_58", "31_58", "31_58", "31_59", + "31_59", "31_59", "31_60", "31_60", "31_60", "31_61", "31_61", "31_61"); + private static final List beatDownPack2 = List.of( + "32_37", "32_37", "32_37", "32_37", "32_44", "32_44", "32_45", "32_45", + "32_45", "32_45", "32_50", "32_50", "32_51", "32_51", "32_51", "32_51", + "32_52", "32_52", "32_52", "32_52", "32_54", "32_54", "32_54", "32_55", + "32_55", "32_56", "32_56", "32_56", "32_58", "32_58", "32_58", "32_59", + "32_60", "32_61", "32_62", "32_63", "32_64", "32_65", "32_66", "32_67"); + private static final List beatDownPack3 = List.of( + "33_24", "33_24", "33_24", "33_25", "33_25", "33_25", "33_26", "33_26", + "33_26", "33_27", "33_27", "33_27", "33_28", "33_28", "33_28", "33_29", + "33_29", "33_29", "33_30", "33_30", "33_30", "33_31", "33_31", "33_31", + "33_32", "33_32", "33_32", "33_34", "33_34", "33_34", "33_35", "33_35", + "33_35", "33_42", "33_42", "33_42", "33_42", "33_44", "33_44", "33_44"); + private static final List packA = List.of( + "31_38", "31_38", "31_38", "31_39", "31_39", "31_40", "31_40", "31_41", + "31_41", "31_41", "31_42", "31_42", "31_42", "31_43", "31_43", "31_22", + "31_22", "31_22", "31_57", "31_57", "31_45", "31_45"); + private static final List packB = List.of( + "32_1", "32_1", "32_1", "32_2", "32_2", "32_2", "32_4", "32_4", + "32_5", "32_5", "32_6", "32_6", "32_8", "32_8", "32_8", "32_26", + "32_26", "32_30", "32_30", "32_30", "32_49", "32_49"); + private static final List packC = List.of( + "32_15", "32_15", "32_15", "32_16", "32_16", "32_17", "32_17", "32_18", + "32_18", "32_19", "32_19", "32_19", "32_20", "32_20", "32_20", "32_25", + "32_25", "32_25", "32_53", "32_53", "32_47", "32_47"); + private static final List packD = List.of( + "31_3", "31_3", "31_3", "31_8", "31_8", "31_9", "31_9", "31_10", + "31_10", "31_11", "31_11", "31_11", "31_12", "31_12", "31_12", "31_29", + "31_29", "31_37", "31_37", "31_37", "31_46", "31_46"); + private static final List packE = List.of( + "31_1", "31_1", "31_2", "31_2", "31_2", "31_4", "31_4", "31_5", + "31_5", "31_5", "31_6", "31_6", "31_7", "31_7", "31_7", "31_33", + "31_33", "31_33", "31_48", "31_48", "31_47", "31_47"); + private static final List packF = List.of( + "32_3", "32_3", "32_3", "32_7", "32_7", "32_9", "32_9", "32_9", + "32_10", "32_10", "32_11", "32_11", "32_11", "32_12", "32_12", "32_29", + "32_29", "32_35", "32_35", "32_35", "32_48", "32_48"); + private static final List packG = List.of( + "32_13", "32_13", "32_13", "32_14", "32_14", "32_21", "32_21", "32_22", + "32_22", "32_23", "32_23", "32_23", "32_24", "32_24", "32_24", "32_39", + "32_39", "32_57", "32_57", "32_57", "32_46", "32_46"); + private static final List packH = List.of( + "31_13", "31_13", "31_13", "31_14", "31_14", "31_15", "31_15", "31_16", + "31_16", "31_17", "31_17", "31_17", "31_18", "31_18", "31_18", "31_25", + "31_25", "31_25", "31_50", "31_50", "31_44", "31_44"); + private static final List packI = List.of( + "33_1", "33_1", "33_3", "33_3", "33_3", "33_4", "33_4", "33_10", + "33_10", "33_10", "33_11", "33_11", "33_11", "33_12", "33_12", "33_36", + "33_36", "33_36", "33_59", "33_59", "33_56", "33_56"); + private static final List packJ = List.of( + "33_2", "33_2", "33_5", "33_5", "33_5", "33_6", "33_6", "33_6", + "33_7", "33_7", "33_8", "33_8", "33_9", "33_9", "33_9", "33_37", + "33_37", "33_37", "33_60", "33_60", "33_58", "33_58"); + private static final List packK = List.of( + "33_13", "33_13", "33_13", "33_14", "33_14", "33_14", "33_15", "33_15", + "33_16", "33_16", "33_17", "33_17", "33_17", "33_18", "33_18", "33_33", + "33_33", "33_33", "33_61", "33_61", "33_57", "33_57"); + private static final List packL = List.of( + "33_19", "33_19", "33_20", "33_20", "33_21", "33_21", "33_52", "33_52", + "33_52", "33_53", "33_53", "33_53", "33_54", "33_54", "33_54", "33_22", + "33_22", "33_23", "33_23", "33_23", "33_55", "33_55"); + private static final List shadowPacks = new ArrayList<>(); + private static final List supplementaryPacks = new ArrayList<>(); + private static final List everything = new ArrayList<>(); + + + static { + List startingDeck = List.of( + "30_1", "30_2", "30_3", "30_4", "30_5", "30_6", "30_7", "30_8", + "30_9", "30_10", "30_11", "30_12", "30_13", "30_14", "30_15", "30_16", + "30_17", "30_18", "30_19", "30_20", "30_21", "30_22", "30_23", "30_24", + "30_29", "30_30", "30_31", "30_47", "30_48", "30_32", "30_32", "30_32", + "30_33", "30_33", "30_34", "30_34", "30_35", "30_35", "30_35", "30_35", + "30_36", "30_36", "30_37", "30_37", "30_38", "30_38", "30_39", "30_39", + "30_39", "30_40", "30_40", "30_40", "30_41", "30_41", "30_42", "30_42", + "30_42", "30_42", "30_66", "30_49", "30_50", "30_51", "30_52", "30_53", + "30_54", "30_55", "30_56", "30_57"); + + for (String card : startingDeck) { + AVERAGE_STARTING_COUNT_MAP.merge(card, 1.0, Double::sum); + } + List.of("30_25", "30_26", "30_27", "30_28").forEach(gandalf -> AVERAGE_STARTING_COUNT_MAP.put(gandalf, 0.25)); + List.of("30_43", "30_44", "30_45", "30_46").forEach(bilbo -> AVERAGE_STARTING_COUNT_MAP.put(bilbo, 0.25)); + + shadowPacks.addAll(swarmPack1); + shadowPacks.addAll(swarmPack2); + shadowPacks.addAll(swarmPack3); + shadowPacks.addAll(beatDownPack1); + shadowPacks.addAll(beatDownPack2); + shadowPacks.addAll(beatDownPack3); + + supplementaryPacks.addAll(packA); + supplementaryPacks.addAll(packB); + supplementaryPacks.addAll(packC); + supplementaryPacks.addAll(packD); + supplementaryPacks.addAll(packE); + supplementaryPacks.addAll(packF); + supplementaryPacks.addAll(packG); + supplementaryPacks.addAll(packH); + supplementaryPacks.addAll(packI); + supplementaryPacks.addAll(packJ); + supplementaryPacks.addAll(packK); + supplementaryPacks.addAll(packL); + + everything.addAll(freePeoplesPack); + everything.addAll(freePeoplesPack); + everything.addAll(freePeoplesPack); + everything.addAll(freePeoplesPack); + everything.addAll(shadowPacks); + everything.addAll(shadowPacks); + everything.addAll(supplementaryPacks); + } + + public HobbitDraftCardEvaluator(LotroCardBlueprintLibrary library) { + super(library); + } + + @Override + public Map getValuesMap(Map winningMap, Map losingMap, int gamesAnalyzed) { + // Merge win and lose maps (they are kept separate for potential wr info) + Map mergedMap = mergeMaps(winningMap, losingMap); + // Lower count of cards from Draft Packs + Map startingCollectionNormalizedCardCountMap = normalizeCountByDraftPackChance(mergedMap, gamesAnalyzed); + + // Normalize for uneven set size + Map packNormalizedCardCountMap = normalizeCountByPackType(startingCollectionNormalizedCardCountMap); + + // Normalize count based on rarities + Map normalizedCardCountMap = normalizeCountByRarity(packNormalizedCardCountMap); + + // Make sure all values are positive and in 0-1 range + Map shiftedMap = shift(normalizedCardCountMap); + + return shiftedMap; + } + + private Map normalizeCountByRarity(Map map) { + Map normalizedMap = new HashMap<>(); + + map.forEach((key, value) -> normalizedMap.put(key, value / everything.stream().filter(s -> s.equals(key)).count())); + + return normalizedMap; + + } + + private Map normalizeCountByPackType(Map map) { + + Map normalizedMap = new HashMap<>(); + + map.forEach((key, value) -> { + if (shadowPacks.contains(key)) { + normalizedMap.put(key, value * 3.0); // appear in 1/3 of drafts + } else if (freePeoplesPack.contains(key)){ + normalizedMap.put(key, value); // appear in all drafts + } else if (supplementaryPacks.contains(key)) { + normalizedMap.put(key, value * 3.0); // appear in 1/3 of drafts (solo draft is using 4 packs out of 12) + } + }); + + return normalizedMap; + } + + @Override + public Map getAverageStartingCardMap() { + return UnmodifiableMap.unmodifiableMap(AVERAGE_STARTING_COUNT_MAP); + } +}