From 2d5402b8e87ef827a327f61d13d7e13e3e5c020e Mon Sep 17 00:00:00 2001 From: benjamin Date: Sun, 26 Jul 2015 20:00:44 -0400 Subject: [PATCH 1/2] Added a Historical Standard deck validator, conforming to most of the rules found at http://thattournament.website/historic-tournament.php --- .../src/mage/deck/AllStandards.java | 253 ++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AllStandards.java diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AllStandards.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AllStandards.java new file mode 100644 index 00000000000..009c89c6da2 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AllStandards.java @@ -0,0 +1,253 @@ +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/AllStandards. + * + * 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 AllStandards extends Constructed { + + /* + * This array stores the set codes of each standard up to + * Kamigawa/Ravnica standard, where rotation stabilized. + */ + protected static final String[][] standards = { + + // the first 10 standards are commented out to adhere to the all + // standards ruleset, instaed of the historical standard ruleset. + +// // 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 AllStandards() { + super("Constructed - All Standards"); + + // banned cards for historical standard ruleset commented out. + +// // 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"); + + 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)); + + // 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; + } + +} From bd5d13a32362dc7631b05216bd6f82d6a4f7da2d Mon Sep 17 00:00:00 2001 From: benjamin Date: Sun, 26 Jul 2015 22:59:18 -0400 Subject: [PATCH 2/2] Updated Historical Standard validators changed name of AllStandards.java to more accurately reflect the format; it uses the new date range and banlist from /r/AllStandards. Historical Standard uses the banlist from http://thattournament.website/historic-tournament.php --- .../src/mage/deck/HistoricalStandard.java | 227 ++++++++++++++++++ .../{AllStandards.java => SuperStandard.java} | 70 ++---- 2 files changed, 241 insertions(+), 56 deletions(-) create mode 100644 Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/HistoricalStandard.java rename Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/{AllStandards.java => SuperStandard.java} (73%) 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/AllStandards.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperStandard.java similarity index 73% rename from Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AllStandards.java rename to Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperStandard.java index 009c89c6da2..be6caf7dc1a 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AllStandards.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperStandard.java @@ -15,7 +15,7 @@ import java.util.Map; /** * This class represents a deck conforming to the rules contained in the - * subreddit /r/AllStandards. + subreddit /r/SuperStandard. * * This class was originally made to work with the historical standard ruleset. * Data taken from http://thattournament.website/historic-tournament.php @@ -25,53 +25,15 @@ import java.util.Map; * * @author Marthinwurer (at gmail.com) */ -public class AllStandards extends Constructed { +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 = { - // the first 10 standards are commented out to adhere to the all - // standards ruleset, instaed of the historical standard ruleset. - -// // 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"}, @@ -110,23 +72,9 @@ public class AllStandards extends Constructed { * Constructor. Don't need to mess with any of the sets yet; that will be * done in the overridden validate function. */ - public AllStandards() { + public SuperStandard() { super("Constructed - All Standards"); - - // banned cards for historical standard ruleset commented out. -// // 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"); - banned.add("Ancient Den"); banned.add("Arcbound Ravager"); banned.add("Disciple of the Vault"); @@ -160,6 +108,16 @@ public class AllStandards extends Constructed { // 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)) {