diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/HistoricalStandard.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/HistoricalStandard.java new file mode 100644 index 00000000000..1c8ba55341f --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/HistoricalStandard.java @@ -0,0 +1,227 @@ +package mage.deck; + +import mage.cards.ExpansionSet; +import mage.cards.Sets; +import mage.cards.decks.Constructed; +import mage.cards.decks.Deck; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; + +/** + * This class represents a deck from any past standard. + * + * This class was originally made to work with the historical standard ruleset. + * Data taken from http://thattournament.website/historic-tournament.php + * (site changed, originally thtp://mtgt.nfshost.com/historic-tournament.php) + * + * If there are any questions or corrections, feel free to contact me. + * + * @author Marthinwurer (at gmail.com) + */ +public class HistoricalStandard extends Constructed { + + /* + * This array stores the set codes of each standard up to + * Kamigawa/Ravnica standard, where rotation stabilized. + */ + protected static final String[][] standards = { + + // 1st standard: The Dark, Fallen Empires, and 4th. + { "DRK", "FEM", "4ED" }, + + // 2nd standard: 4th, Fallen Empires, Ice Age, Chronicles, Homelands, + // Alliances, and Mirage. + {"FEM", "4ED", "ICE", "HML", "ALL", "MIR"}, + + // 3rd standard: 4th, Chronicles, Alliances, Mirage, Visions. + {"4ED", "ALL", "MIR", "VIS"}, + + // 4th Standard: Ice Age, Homelands, Alliances, Mirage, Visions, 5th, + // and Weatherlight. + {"ICE", "HML", "ALL", "MIR", "VIS", "5ED", "WTH"}, + + // 5th Standard: Mirage, Visions, 5th, Weatherlight, Tempest, + // Stronghold, and Exodus. + {"MIR", "VIS", "5ED", "WTH", "TMP", "STH", "EXO"}, + + // 6th Standard: 5th, Tempest, Stronghold, Exodus, Urza's Saga, Urza's + // Legacy, Urza's Destiny. + {"5ED", "TMP", "STH", "EXO", "USG", "ULG"}, + + // 7th Standard: Tempest, Stronghold, Exodus, Urza's Saga, Urza's + // Legacy, 6th, Urza's Destiny. + {"TMP", "STH", "EXO", "USG", "ULG", "6ED", "UDS"}, + + // 8th Standard: Urza's Saga, Urza's Legacy, 6th, Urza's Destiny, + // Mercadian Masques, Nemesis, Prophecy. + {"USG", "ULG", "6ED", "UDS", "MMQ", "NMS", "PCY"}, + + // 9th Standard + {"6ED", "MMQ", "NMS", "PCY", "INV", "PLS"}, + + // 10th Standard + {"7ED", "MMQ", "NMS", "PCY", "INV", "PLS", "APC"}, + + // 11th Standard + {"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"}, + + // 12th Standard + {"7ED", "ODY", "TOR", "JUD", "ONS", "LGN", "LGN"}, + + // 13th Standard + {"8ED", "ODY", "TOR", "JUD", "ONS", "LGN", "LGN"}, + + // 14th Standard + {"8ED", "ONS", "LGN", "LGN", "MRD", "DST", "5DN"}, + + // 15th Standard + {"8ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, + + // 16th Standard + {"9ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, + + // 17th Standard + {"9ED", "CHK", "BOK", "SOK", "RAV", "GPT", "DIS", "CSP"}, + + // 18th Standard + {"9ED", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, + + // 19th Standard + {"10E", "RAV", "GPT", "DIS", "CSP", "TSP", "PLC", "FUT"}, + + // 20th Standard + {"10E", "CSP", "TSP", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE"}, + + // 21st Standard + {"10E", "LRW", "MOR", "SHM", "EVE", "ALA", "CON", "ARB"} + }; + + /** + * Constructor. Don't need to mess with any of the sets yet; that will be + * done in the overridden validate function. + */ + public HistoricalStandard() { + super("Constructed - Historical Standard"); + + // banned cards + banned.add("Balance"); + // Not banned in the format, but it is either this or Misty, and most + // people choose Misty. + banned.add("Batterskull"); + banned.add("Memory Jar"); + banned.add("Mind Over Matter"); + banned.add("Mind Twist"); + banned.add("Skullclamp"); + banned.add("Tolarian Academy"); + banned.add("Yawgmoth's Bargain"); + } + + /** + * Overridden validate function. Changes the standard sets, then uses the + * regular validation function to test validity. + * @param deck - the deck to validate. + * @return + */ + @Override + public boolean validate(Deck deck) { + + Map leastInvalid = null; + + boolean valid = false; + + // up to Lorwyn/Alara, standards will have to be hard-coded. + // iterate through the array of standards. + for (String[] sets : standards) { + + // clear the invalid list + invalid.clear(); + + // add the sets to the setCodes. + setCodes = new ArrayList<>(Arrays.asList(sets)); + + // validate it. If it validates, clear the invalid cards and break. + if (super.validate(deck)) { + valid = true; + break; + } + + // if the map holding the invalid cards is empty, set it to a + // copy of the current invalid list. + if (leastInvalid == null) { + leastInvalid = new HashMap<>(this.getInvalid()); + continue; + } + + // see how many invalid cards there are. if there are less invalid + // cards than the stored invalid list, assign the current invalid + // to leastInvalid. + if (leastInvalid.size() > this.getInvalid().size()) { + leastInvalid = new HashMap<>(this.getInvalid()); + } + } + + // After testing the first few standards, do the regular ones. + // set the initial starting and ending date, as well as the current. + GregorianCalendar start = new GregorianCalendar(2006, + Calendar.SEPTEMBER, 1); + GregorianCalendar end = new GregorianCalendar(2008, + Calendar.SEPTEMBER, 1); + GregorianCalendar current = new GregorianCalendar(); + + // use the method for determining regular standard legality, but change + // the date for each standard. + while (end.before(current) && !valid) { + + // clear the invalid list and set codes. + setCodes.clear(); + invalid.clear(); + + // increment the start and end dates. + start.set(Calendar.YEAR, start.get(Calendar.YEAR) + 1); + end.set(Calendar.YEAR, start.get(Calendar.YEAR) + 2); + + // Get the sets in that time period. + // (code taken from standard.java) + for (ExpansionSet set : Sets.getInstance().values()) { + if (set.getReleaseDate().after(start.getTime()) + && set.getReleaseDate().before(end.getTime()) + && (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) { + setCodes.add(set.getCode()); + } + } + + // validate it. If it validates, clear the invalid cards and break. + if (super.validate(deck)) { + invalid.clear(); + valid = true; + break; + } + + // see how many invalid cards there are. if there are less invalid + // cards than the stored invalid list, assign the current invalid + // to leastInvalid. + if (leastInvalid == null){ + leastInvalid = new HashMap<>(this.getInvalid()); + + }else if (leastInvalid.size() > this.getInvalid().size()) { + leastInvalid = new HashMap<>(this.getInvalid()); + } + } + + // if no standard environment is valid, set the invalid to the + // invalid that had the least errors. + if( !valid ){ + this.invalid = new HashMap<>(leastInvalid); + } + + // return the validity. + return valid; + } + +} diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperStandard.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperStandard.java new file mode 100644 index 00000000000..be6caf7dc1a --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperStandard.java @@ -0,0 +1,211 @@ +package mage.deck; + +import mage.cards.ExpansionSet; +import mage.cards.Sets; +import mage.cards.decks.Constructed; +import mage.cards.decks.Deck; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; + +/** + * This class represents a deck conforming to the rules contained in the + subreddit /r/SuperStandard. + * + * This class was originally made to work with the historical standard ruleset. + * Data taken from http://thattournament.website/historic-tournament.php + * (site changed, originally thtp://mtgt.nfshost.com/historic-tournament.php) + * + * If there are any questions or corrections, feel free to contact me. + * + * @author Marthinwurer (at gmail.com) + */ +public class SuperStandard extends Constructed { + + /* + * This array stores the set codes of each standard up to + * Kamigawa/Ravnica standard, where rotation stabilized. + * Data taken from http://thattournament.website/historic-tournament.php + */ + protected static final String[][] standards = { + + // 11th Standard + {"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"}, + + // 12th Standard + {"7ED", "ODY", "TOR", "JUD", "ONS", "LGN", "LGN"}, + + // 13th Standard + {"8ED", "ODY", "TOR", "JUD", "ONS", "LGN", "LGN"}, + + // 14th Standard + {"8ED", "ONS", "LGN", "LGN", "MRD", "DST", "5DN"}, + + // 15th Standard + {"8ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, + + // 16th Standard + {"9ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, + + // 17th Standard + {"9ED", "CHK", "BOK", "SOK", "RAV", "GPT", "DIS", "CSP"}, + + // 18th Standard + {"9ED", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, + + // 19th Standard + {"10E", "RAV", "GPT", "DIS", "CSP", "TSP", "PLC", "FUT"}, + + // 20th Standard + {"10E", "CSP", "TSP", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE"}, + + // 21st Standard + {"10E", "LRW", "MOR", "SHM", "EVE", "ALA", "CON", "ARB"} + }; + + /** + * Constructor. Don't need to mess with any of the sets yet; that will be + * done in the overridden validate function. + */ + public SuperStandard() { + super("Constructed - All Standards"); + + banned.add("Ancient Den"); + banned.add("Arcbound Ravager"); + banned.add("Disciple of the Vault"); + banned.add("Great Furnace"); + banned.add("Jace, the Mind Sculptor"); + banned.add("Seat of the Synod"); + banned.add("Skullclamp"); + banned.add("Tree of Tales"); + banned.add("Vault of Whispers"); + } + + /** + * Overridden validate function. Changes the standard sets, then uses the + * regular validation function to test validity. + * @param deck - the deck to validate. + * @return + */ + @Override + public boolean validate(Deck deck) { + + Map leastInvalid = null; + + boolean valid = false; + + // up to Lorwyn/Alara, standards will have to be hard-coded. + // iterate through the array of standards. + for (String[] sets : standards) { + + // clear the invalid list + invalid.clear(); + + // add the sets to the setCodes. + setCodes = new ArrayList<>(Arrays.asList(sets)); + + // if either of the mirrodin blocks are in the time period, ban + // misty and darksteel citadel + if( setCodes.contains("MRD") || setCodes.contains("SOM")){ + banned.add("Darksteel Citadel"); + banned.add("Stoneforge Mystic"); + }else{ + banned.remove("Darksteel Citadel"); + banned.remove("Stoneforge Mystic"); + } + + // validate it. If it validates, clear the invalid cards and break. + if (super.validate(deck)) { + valid = true; + break; + } + + // if the map holding the invalid cards is empty, set it to a + // copy of the current invalid list. + if (leastInvalid == null) { + leastInvalid = new HashMap<>(this.getInvalid()); + continue; + } + + // see how many invalid cards there are. if there are less invalid + // cards than the stored invalid list, assign the current invalid + // to leastInvalid. + if (leastInvalid.size() > this.getInvalid().size()) { + leastInvalid = new HashMap<>(this.getInvalid()); + } + } + + // After testing the first few standards, do the regular ones. + // set the initial starting and ending date, as well as the current. + GregorianCalendar start = new GregorianCalendar(2006, + Calendar.SEPTEMBER, 1); + GregorianCalendar end = new GregorianCalendar(2008, + Calendar.SEPTEMBER, 1); + GregorianCalendar current = new GregorianCalendar(); + + // use the method for determining regular standard legality, but change + // the date for each standard. + while (end.before(current) && !valid) { + + // clear the invalid list and set codes. + setCodes.clear(); + invalid.clear(); + + // increment the start and end dates. + start.set(Calendar.YEAR, start.get(Calendar.YEAR) + 1); + end.set(Calendar.YEAR, start.get(Calendar.YEAR) + 2); + + // Get the sets in that time period. + // (code taken from standard.java) + for (ExpansionSet set : Sets.getInstance().values()) { + if (set.getReleaseDate().after(start.getTime()) + && set.getReleaseDate().before(end.getTime()) + && (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) { + setCodes.add(set.getCode()); + } + } + + // if either of the mirrodin blocks are in the time period, ban + // misty and darksteel citadel + if( setCodes.contains("MRD") || setCodes.contains("SOM")){ + banned.add("Darksteel Citadel"); + banned.add("Stoneforge Mystic"); + }else{ + banned.remove("Darksteel Citadel"); + banned.remove("Stoneforge Mystic"); + } + + // validate it. If it validates, clear the invalid cards and break. + if (super.validate(deck)) { + invalid.clear(); + valid = true; + break; + } + + // see how many invalid cards there are. if there are less invalid + // cards than the stored invalid list, assign the current invalid + // to leastInvalid. + if (leastInvalid == null){ + leastInvalid = new HashMap<>(this.getInvalid()); + + }else if (leastInvalid.size() > this.getInvalid().size()) { + leastInvalid = new HashMap<>(this.getInvalid()); + } + } + + // if no standard environment is valid, set the invalid to the + // invalid that had the least errors. + if( !valid ){ + this.invalid = new HashMap<>(leastInvalid); + } + + // return the validity. + return valid; + } + +}