mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Allow multiple deck hints in a card
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package forge.card;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
* CardAiHints holds all the different types of card hints for AI decks.
|
||||
*
|
||||
*/
|
||||
public class CardAiHints {
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.PredicateString.StringOp;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -22,7 +23,7 @@ public class DeckHints {
|
||||
/**
|
||||
* Enum of types of DeckHints.
|
||||
*/
|
||||
public enum Type {
|
||||
private enum Type {
|
||||
|
||||
/** The Color. */
|
||||
COLOR,
|
||||
@@ -36,84 +37,98 @@ public class DeckHints {
|
||||
NONE
|
||||
}
|
||||
|
||||
private Type type = Type.NONE;
|
||||
private String filterParam = null;
|
||||
private boolean valid = false;
|
||||
private List<Pair<Type, String>> filters = null;
|
||||
|
||||
/**
|
||||
* Construct a DeckHints from the SVar string.
|
||||
*
|
||||
* @param wants
|
||||
* @param hints
|
||||
* SVar for DeckHints
|
||||
*/
|
||||
public DeckHints(String wants) {
|
||||
String[] pieces = wants.split("\\$");
|
||||
public DeckHints(String hints) {
|
||||
String[] pieces = hints.split("\\&");
|
||||
if (pieces.length > 0) {
|
||||
for (String piece : pieces) {
|
||||
Pair<Type, String> pair = parseHint(piece.trim());
|
||||
if (pair != null) {
|
||||
if (filters == null) {
|
||||
filters = new ArrayList<>();
|
||||
}
|
||||
filters.add(pair);
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<Type, String> parseHint(String hint) {
|
||||
Pair<Type, String> pair = null;
|
||||
String[] pieces = hint.split("\\$");
|
||||
if (pieces.length == 2) {
|
||||
try {
|
||||
Type typeValue = Type.valueOf(pieces[0].toUpperCase());
|
||||
for (Type t : Type.values()) {
|
||||
if (typeValue == t) {
|
||||
type = t;
|
||||
pair = Pair.of(t, pieces[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// type will remain NONE
|
||||
// will remain null
|
||||
}
|
||||
|
||||
filterParam = pieces[1];
|
||||
}
|
||||
return pair;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of Cards from the given List<Card> that match this
|
||||
* Returns a list of Cards from the given List<PaperCard> that match this
|
||||
* DeckHints. I.e., other cards that this Card needs in its deck.
|
||||
*
|
||||
* @param cardList
|
||||
* list of cards to be filtered
|
||||
* @return List<Card> of Cards that match this DeckHints.
|
||||
* @return List<PaperCard> of Cards that match this DeckHints.
|
||||
*/
|
||||
public List<PaperCard> filter(Iterable<PaperCard> cardList) {
|
||||
List<PaperCard> ret;
|
||||
switch (type) {
|
||||
case TYPE:
|
||||
ret = new ArrayList<PaperCard>();
|
||||
String[] types = filterParam.split("\\|");
|
||||
for (String type : types) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.subType(type), PaperCard.FN_GET_RULES);
|
||||
List<PaperCard> ret = new ArrayList<>();
|
||||
for (Pair<Type, String> pair : filters) {
|
||||
Type type = pair.getLeft();
|
||||
String param = pair.getRight();
|
||||
switch (type) {
|
||||
case TYPE:
|
||||
String[] types = param.split("\\|");
|
||||
for (String t : types) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.subType(t), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
case COLOR:
|
||||
String[] colors = param.split("\\|");
|
||||
for (String color : colors) {
|
||||
ColorSet cc = ColorSet.fromNames(color);
|
||||
if (cc.isColorless()) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard.FN_GET_RULES);
|
||||
} else {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KEYWORD:
|
||||
String[] keywords = param.split("\\|");
|
||||
for (String keyword : keywords) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.hasKeyword(keyword), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
case NAME:
|
||||
String[] names = param.split("\\|");
|
||||
for (String name : names) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case COLOR:
|
||||
ret = new ArrayList<PaperCard>();
|
||||
String[] colors = filterParam.split("\\|");
|
||||
for (String color : colors) {
|
||||
ColorSet cc = ColorSet.fromNames(color);
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
case KEYWORD:
|
||||
ret = new ArrayList<PaperCard>();
|
||||
String[] keywords = filterParam.split("\\|");
|
||||
for (String keyword : keywords) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.hasKeyword(keyword), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
case NAME:
|
||||
ret = new ArrayList<PaperCard>();
|
||||
String[] names = filterParam.split("\\|");
|
||||
for (String name : names) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = Lists.newArrayList(cardList);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -38,13 +38,11 @@ public class DeckHintsTest {
|
||||
Assert.assertEquals("Griffin Rider", cp.getName());
|
||||
DeckHints hints = cp.getRules().getAiHints().getDeckHints();
|
||||
Assert.assertNotNull(hints);
|
||||
Assert.assertEquals(DeckHints.Type.TYPE, hints.getType());
|
||||
Assert.assertTrue(hints.isValid());
|
||||
|
||||
List<PaperCard> list = new ArrayList<PaperCard>();
|
||||
PaperCard c0 = readCard("assault_griffin.txt");
|
||||
list.add(c0);
|
||||
PaperCard c1 = readCard("auramancer.txt");
|
||||
list.add(c1);
|
||||
list.add(readCard("assault_griffin.txt"));
|
||||
list.add(readCard("auramancer.txt"));
|
||||
|
||||
Assert.assertEquals(1, hints.filter(list).size());
|
||||
Assert.assertEquals("Assault Griffin", hints.filter(list).get(0).getName());
|
||||
@@ -59,15 +57,12 @@ public class DeckHintsTest {
|
||||
Assert.assertEquals("Throne of Empires", cp.getName());
|
||||
DeckHints hints = cp.getRules().getAiHints().getDeckHints();
|
||||
Assert.assertNotNull(hints);
|
||||
Assert.assertEquals(DeckHints.Type.NAME, hints.getType());
|
||||
Assert.assertTrue(hints.isValid());
|
||||
|
||||
List<PaperCard> list = new ArrayList<PaperCard>();
|
||||
PaperCard c0 = readCard("assault_griffin.txt");
|
||||
list.add(c0);
|
||||
PaperCard c1 = readCard("scepter_of_empires.txt");
|
||||
list.add(c1);
|
||||
PaperCard c2 = readCard("crown_of_empires.txt");
|
||||
list.add(c2);
|
||||
list.add(readCard("assault_griffin.txt"));
|
||||
list.add(readCard("scepter_of_empires.txt"));
|
||||
list.add(readCard("crown_of_empires.txt"));
|
||||
|
||||
Assert.assertEquals(2, hints.filter(list).size());
|
||||
}
|
||||
@@ -80,13 +75,11 @@ public class DeckHintsTest {
|
||||
IPaperCard cp = readCard("mwonvuli_beast_tracker.txt");
|
||||
DeckHints hints = cp.getRules().getAiHints().getDeckHints();
|
||||
Assert.assertNotNull(hints);
|
||||
Assert.assertEquals(DeckHints.Type.KEYWORD, hints.getType());
|
||||
Assert.assertTrue(hints.isValid());
|
||||
|
||||
List<PaperCard> list = new ArrayList<PaperCard>();
|
||||
PaperCard c0 = readCard("acidic_slime.txt");
|
||||
list.add(c0);
|
||||
PaperCard c1 = readCard("ajanis_sunstriker.txt");
|
||||
list.add(c1);
|
||||
list.add(readCard("acidic_slime.txt"));
|
||||
list.add(readCard("ajanis_sunstriker.txt"));
|
||||
|
||||
Assert.assertEquals(1, hints.filter(list).size());
|
||||
}
|
||||
@@ -99,13 +92,11 @@ public class DeckHintsTest {
|
||||
IPaperCard cp = readCard("wurms_tooth.txt");
|
||||
DeckHints hints = cp.getRules().getAiHints().getDeckNeeds();
|
||||
Assert.assertNotNull(hints);
|
||||
Assert.assertEquals(DeckHints.Type.COLOR, hints.getType());
|
||||
Assert.assertTrue(hints.isValid());
|
||||
|
||||
List<PaperCard> list = new ArrayList<PaperCard>();
|
||||
PaperCard c0 = readCard("llanowar_elves.txt");
|
||||
list.add(c0);
|
||||
PaperCard c1 = readCard("unsummon.txt");
|
||||
list.add(c1);
|
||||
list.add(readCard("llanowar_elves.txt"));
|
||||
list.add(readCard("unsummon.txt"));
|
||||
|
||||
Assert.assertEquals(1, hints.filter(list).size());
|
||||
}
|
||||
@@ -114,19 +105,30 @@ public class DeckHintsTest {
|
||||
*
|
||||
* Test for no wants.
|
||||
*/
|
||||
@Test(timeOut = 1000, enabled = false)
|
||||
@Test(timeOut = 1000, enabled = true)
|
||||
void testNoFilter() {
|
||||
PaperCard cp = readCard("assault_griffin.txt");
|
||||
DeckHints hints = cp.getRules().getAiHints().getDeckHints();
|
||||
Assert.assertEquals("Assault Griffin", cp.getName());
|
||||
Assert.assertNull(hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for multiple.
|
||||
*/
|
||||
@Test(timeOut = 1000, enabled = true)
|
||||
void testMultiple() {
|
||||
PaperCard pc = readCard("ruination_guide.txt");
|
||||
DeckHints hints = pc.getRules().getAiHints().getDeckHints();
|
||||
Assert.assertNotNull(hints);
|
||||
Assert.assertEquals(DeckHints.Type.NONE, hints.getType());
|
||||
Assert.assertTrue(hints.isValid());
|
||||
|
||||
List<PaperCard> list = new ArrayList<PaperCard>();
|
||||
PaperCard c0 = readCard("assault_griffin.txt");
|
||||
list.add(c0);
|
||||
list.add(readCard("assault_griffin.txt"));
|
||||
list.add(readCard("breaker_of_armies.txt"));
|
||||
list.add(readCard("benthic_infiltrator.txt"));
|
||||
|
||||
Assert.assertEquals(1, hints.filter(list).size());
|
||||
Assert.assertEquals(2, hints.filter(list).size());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,6 @@ K:Devoid
|
||||
K:Ingest
|
||||
S:Mode$ Continuous | Affected$ Creature.Colorless+Other+YouCtrl | AddPower$ 1 | Description$ Other colorless creatures you control get +1/+0.
|
||||
SVar:PlayMain1:TRUE
|
||||
DeckHints:Type$Processor
|
||||
DeckHints:Type$Processor & Keyword$Devoid & Color$Colorless
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/ruination_guide.jpg
|
||||
Oracle:Devoid (This card has no color.)\nIngest (Whenever this creature deals combat damage to a player, that player exiles the top card of his or her library.)\nOther colorless creatures you control get +1/+0.
|
||||
|
||||
@@ -127,7 +127,6 @@ public class CardRanker {
|
||||
double synergyScore = 0.0;
|
||||
|
||||
synergyScore += getScoreForDeckHints(card, otherCards);
|
||||
synergyScore += getScoreForBuffedBy(card, otherCards);
|
||||
|
||||
return synergyScore;
|
||||
}
|
||||
@@ -135,7 +134,7 @@ public class CardRanker {
|
||||
private double getScoreForDeckHints(PaperCard card, Iterable<PaperCard> otherCards) {
|
||||
double score = 0.0;
|
||||
final DeckHints hints = card.getRules().getAiHints().getDeckHints();
|
||||
if (hints != null && hints.getType() != DeckHints.Type.NONE) {
|
||||
if (hints != null && hints.isValid()) {
|
||||
final List<PaperCard> comboCards = hints.filter(otherCards);
|
||||
if (comboCards.size() > 0) {
|
||||
score = comboCards.size() * 10;
|
||||
@@ -144,22 +143,6 @@ public class CardRanker {
|
||||
return score;
|
||||
}
|
||||
|
||||
private double getScoreForBuffedBy(PaperCard card, Iterable<PaperCard> otherCards) {
|
||||
double matchBuffScore = 0.0;
|
||||
Iterable<Map.Entry<String, String>> vars = card.getRules().getMainPart().getVariables();
|
||||
for (Map.Entry<String, String> var : vars) {
|
||||
if (var.getKey().equals("BuffedBy")) {
|
||||
String buff = var.getValue();
|
||||
final Iterable<PaperCard> buffers = Iterables.filter(otherCards,
|
||||
Predicates.compose(CardRulesPredicates.subType(buff), PaperCard.FN_GET_RULES));
|
||||
if (Iterables.size(buffers) > 0) {
|
||||
matchBuffScore = Iterables.size(buffers) * 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchBuffScore;
|
||||
}
|
||||
|
||||
private List<PaperCard> sortAndCreateList(List<Pair<Double, PaperCard>> cardScores) {
|
||||
Collections.sort(cardScores, Collections.reverseOrder(new CardRankingComparator()));
|
||||
|
||||
|
||||
@@ -558,12 +558,12 @@ public class LimitedDeckBuilder extends DeckGeneratorBase {
|
||||
if (ai.getRemRandomDecks()) {
|
||||
final List<PaperCard> comboCards = new ArrayList<PaperCard>();
|
||||
if (ai.getDeckNeeds() != null
|
||||
&& ai.getDeckNeeds().getType() != DeckHints.Type.NONE) {
|
||||
&& ai.getDeckNeeds().isValid()) {
|
||||
final DeckHints needs = ai.getDeckNeeds();
|
||||
comboCards.addAll(needs.filter(deckList));
|
||||
}
|
||||
if (ai.getDeckHints() != null
|
||||
&& ai.getDeckHints().getType() != DeckHints.Type.NONE) {
|
||||
&& ai.getDeckHints().isValid()) {
|
||||
final DeckHints hints = ai.getDeckHints();
|
||||
comboCards.addAll(hints.filter(deckList));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user