From f70899a487cf0cdc58b8f4e0efea98e8404766c8 Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Tue, 15 Mar 2016 22:04:06 +0100 Subject: Refactor is coming along, just need to sort out the new file structure now --- src/eu/equalparts/cardbase/CardEntry.java | 25 ----------- src/eu/equalparts/cardbase/Cardbase.java | 19 +++++++-- src/eu/equalparts/cardbase/cli/CardbaseCLI.java | 6 +-- test/eu/equalparts/cardbase/CardbaseSortTest.java | 11 ++--- test/eu/equalparts/cardbase/CardbaseTest.java | 51 ++++++++++------------- test/shivandragon.json | 2 +- test/testbase.cb | 2 +- test/testcards.json | 2 +- todo | 5 ++- 9 files changed, 51 insertions(+), 72 deletions(-) delete mode 100644 src/eu/equalparts/cardbase/CardEntry.java diff --git a/src/eu/equalparts/cardbase/CardEntry.java b/src/eu/equalparts/cardbase/CardEntry.java deleted file mode 100644 index c4a4c94..0000000 --- a/src/eu/equalparts/cardbase/CardEntry.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.equalparts.cardbase; - -import eu.equalparts.cardbase.cards.Card; - -/** - * The purpose of this class is to hold a single {@code Card} object but - * also all associated metadata, such as count. - * - * @author Eduardo Pedroni - * - */ -public class CardEntry { - - private final Card card; - public int count; - - public CardEntry(Card card, int count) { - this.card = card; - this.count = count; - } - - public Card card() { - return card; - } -} diff --git a/src/eu/equalparts/cardbase/Cardbase.java b/src/eu/equalparts/cardbase/Cardbase.java index af8e7d5..075f7f3 100644 --- a/src/eu/equalparts/cardbase/Cardbase.java +++ b/src/eu/equalparts/cardbase/Cardbase.java @@ -11,8 +11,8 @@ import java.util.Map; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; import eu.equalparts.cardbase.cards.Card; import eu.equalparts.cardbase.comparator.CardComparator; @@ -56,14 +56,21 @@ public class Cardbase { * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs. */ public Cardbase(File cardbaseFile) throws JsonParseException, JsonMappingException, IOException { - cards = JSON.mapper.readValue(cardbaseFile, new TypeReference>() {}); + initialise(); + parseCardbase(JSON.mapper.readValue(cardbaseFile, JsonNode.class)); + } /** * Initialises a clean cardbase. */ public Cardbase() { + initialise(); + } + + private void initialise() { cards = new HashMap(); + collection = new HashMap(); decks = new HashMap(); } @@ -192,11 +199,15 @@ public class Cardbase { return Collections.unmodifiableMap(decks); } - public int getCount(String setCode, String number) { - Integer count = collection.get(Card.makeHash(setCode, number)); + public int getCount(Card card) { + Integer count = collection.get(Card.makeHash(card.setCode, card.number)); return count != null ? count : 0; } + private void parseCardbase(JsonNode jsonTree) { + + } + // public List getMissingCards(StandaloneDeck deckToCheck) { // List missingCards = new ArrayList(); // for (Card card : deckToCheck.cards) { diff --git a/src/eu/equalparts/cardbase/cli/CardbaseCLI.java b/src/eu/equalparts/cardbase/cli/CardbaseCLI.java index 8aece5d..b1a4028 100644 --- a/src/eu/equalparts/cardbase/cli/CardbaseCLI.java +++ b/src/eu/equalparts/cardbase/cli/CardbaseCLI.java @@ -337,7 +337,7 @@ public final class CardbaseCLI { int total = 0; for (Card card : cardbase.getCards()) { printGlance(card); - total += cardbase.getCount(card.setCode, card.number); + total += cardbase.getCount(card); } System.out.println("Total: " + total); } @@ -365,7 +365,7 @@ public final class CardbaseCLI { int total = 0; for (Card card : cardbase.getCards()) { printPerusal(card); - total += cardbase.getCount(card.setCode, card.number); + total += cardbase.getCount(card); } System.out.println("Total: " + total); } @@ -523,7 +523,7 @@ public final class CardbaseCLI { * @param card the card to glance. */ private void printGlance(Card card) { - System.out.println(String.format("%1$-4d %2$s (%3$s, %4$s)", cardbase.getCount(card.setCode, card.number), card.name, card.setCode, card.number)); + System.out.println(String.format("%1$-4d %2$s (%3$s, %4$s)", cardbase.getCount(card), card.name, card.setCode, card.number)); } /** diff --git a/test/eu/equalparts/cardbase/CardbaseSortTest.java b/test/eu/equalparts/cardbase/CardbaseSortTest.java index e3a92ee..2dbb68e 100644 --- a/test/eu/equalparts/cardbase/CardbaseSortTest.java +++ b/test/eu/equalparts/cardbase/CardbaseSortTest.java @@ -1,5 +1,6 @@ package eu.equalparts.cardbase; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Collection; @@ -40,8 +41,9 @@ public class CardbaseSortTest { @Before public void setUp() throws Exception { uut = new Cardbase(); - for (Card card : testCards) { - uut.addCard(card, card.count); + int[] cardCounts = {1, 2, 3, 8, 1, 15, 1, 1}; + for (int i = 0; i < testCards.size(); i++) { + uut.addCard(testCards.get(i), cardCounts[i]); } } @@ -387,11 +389,10 @@ public class CardbaseSortTest { public void sortByCount() throws Exception { Collection sortedCards = uut.sort("count"); int i = 0; - Integer[] counts = {1, 1, 1, 1, 2, 3, 8, 15 }; + int[] counts = {1, 1, 1, 1, 2, 3, 8, 15 }; for (Card card : sortedCards) { - assertTrue(card.count + " should have been " + counts[i] + ", i = " + i, card.count.equals(counts[i])); + assertEquals(uut.getCount(card) + " should have been " + counts[i] + ", i = " + i, uut.getCount(card), counts[i]); i++; } } - } diff --git a/test/eu/equalparts/cardbase/CardbaseTest.java b/test/eu/equalparts/cardbase/CardbaseTest.java index 424befc..ec9494e 100644 --- a/test/eu/equalparts/cardbase/CardbaseTest.java +++ b/test/eu/equalparts/cardbase/CardbaseTest.java @@ -90,7 +90,7 @@ public class CardbaseTest { for (CardInfo ci : testCards) { Card card = uut.getCard(ci.setCode, ci.number); assertNotNull("Missing card, set " + ci.setCode + ", " + ci.number, card); - assertEquals("Wrong card count, set " + ci.setCode + ", " + ci.number, ci.count, card.count); + assertEquals("Wrong card count, set " + ci.setCode + ", " + ci.number, ci.count, (Integer) uut.getCount(card)); } } @@ -139,19 +139,21 @@ public class CardbaseTest { ***********************************************************************************/ @Test public void cardbaseIsSaved() throws Exception { + final int testCount = 5; + File testFile = tempFolder.newFile("saveTest.cb"); uut.writeCollection(testFile); uut = new Cardbase(testFile); assertEquals("Cardbase should contain no cards.", 0, uut.getCards().size()); - uut.addCard(testCard, testCard.count); + uut.addCard(testCard, testCount); uut.writeCollection(testFile); uut = new Cardbase(testFile); - assertEquals("Cardbase should contain one card.", 1, uut.getCards().size()); + assertEquals("Cardbase should contain " + testCount + " cards.", testCount, uut.getCards().size()); Card card = uut.getCard("M15", "281"); assertNotNull("Cardbase should contain a Shivan Dragon.", card); - assertEquals("Cardbase should contain only one Shivan Dragon.", new Integer(1), card.count); + assertEquals("Cardbase should contain " + testCount + " Shivan Dragon.", testCount, uut.getCount(card)); } /* @@ -176,7 +178,7 @@ public class CardbaseTest { ***********************************************************************************/ @Test public void newCardIsAdded() throws Exception { - uut.addCard(testCard, testCard.count); + uut.addCard(testCard, 1); Card addedCard = uut.getCard("M15", "281"); assertNotNull("Card was not found in cardbase.", addedCard); @@ -185,15 +187,12 @@ public class CardbaseTest { @Test public void existingCardIsIncremented() throws Exception { - Card shivanClone = testCard.clone(); - uut.addCard(shivanClone, shivanClone.count); - Card shivanClone2 = testCard.clone(); - shivanClone2.count = 2; - uut.addCard(shivanClone2, shivanClone2.count); + uut.addCard(testCard, 2); + uut.addCard(testCard, 4); Card addedCard = uut.getCard("M15", "281"); assertNotNull("Card was not found in cardbase.", addedCard); - assertEquals("Card count was not updated correctly.", new Integer(3), addedCard.count); + assertEquals("Card count was not updated correctly.", 6, uut.getCount(addedCard)); } /* @@ -210,39 +209,31 @@ public class CardbaseTest { ***********************************************************************************/ @Test public void cardRemoveCountIsLessThanCardCount() throws Exception { - Card shivanClone = testCard.clone(); - shivanClone.count = 5; - uut.addCard(shivanClone, shivanClone.count); + uut.addCard(testCard, 5); - int removed = uut.removeCard(testCard, testCard.count); + int removed = uut.removeCard(testCard, 3); Card removedCard = uut.getCard("M15", "281"); assertNotNull("Card was not found in cardbase.", removedCard); - assertEquals("Card count was not updated correctly.", new Integer(4), removedCard.count); - assertEquals("Cardbase reports wrong removed count.", 1, removed); + assertEquals("Card count was not updated correctly.", 2, uut.getCount(removedCard)); + assertEquals("Cardbase reports wrong removed count.", 3, removed); } @Test public void cardRemoveCountIsEqualToCardCount() throws Exception { - Card shivanClone = testCard.clone(); - uut.addCard(shivanClone, shivanClone.count); + uut.addCard(testCard, 5); - int removed = uut.removeCard(testCard, testCard.count); + int removed = uut.removeCard(testCard, 5); Card removedCard = uut.getCard("M15", "281"); assertNull("Card was not removed from cardbase.", removedCard); - assertEquals("Cardbase reports wrong removed count.", 1, removed); + assertEquals("Cardbase reports wrong removed count.", 5, removed); } @Test public void cardRemoveCountIsGreaterThanCardCount() throws Exception { - Card shivanClone = testCard.clone(); - shivanClone.count = 3; - uut.addCard(shivanClone, shivanClone.count); - - Card shivanClone2 = testCard.clone(); - shivanClone2.count = 5; - int removed = uut.removeCard(shivanClone2, shivanClone2.count); + uut.addCard(testCard, 3); + int removed = uut.removeCard(testCard, 5); Card removedCard = uut.getCard("M15", "281"); assertNull("Card was not removed from cardbase.", removedCard); @@ -260,7 +251,7 @@ public class CardbaseTest { @Test public void removedCardIsNotInCardbase() throws Exception { - int removed = uut.removeCard(testCard, testCard.count); + int removed = uut.removeCard(testCard, 1); assertEquals("Removed count should be 0.", 0, removed); } @@ -270,7 +261,7 @@ public class CardbaseTest { ***********************************************************************************/ @Test public void correctCardIsReturnedByGetter() throws Exception { - uut.addCard(testCard.clone(), testCard.count); + uut.addCard(testCard, 1); Card card = uut.getCard("M15", "281"); diff --git a/test/shivandragon.json b/test/shivandragon.json index 345d4b1..6237c3c 100644 --- a/test/shivandragon.json +++ b/test/shivandragon.json @@ -1 +1 @@ -{"name":"Shivan Dragon","layout":"normal","manaCost":"{4}{R}{R}","cmc":6,"type":"Creature — Dragon","rarity":"Rare","text":"Flying (This creature can't be blocked except by creatures with flying or reach.)\n{R}: Shivan Dragon gets +1/+0 until end of turn.","flavor":"The undisputed master of the mountains of Shiv.","artist":"Donato Giancola","number":"281","power":"5","toughness":"5","loyalty":null,"multiverseid":383172,"imageName":"shivan dragon","watermark":null,"setCode":"M15","imageCode":"m15","count":1} \ No newline at end of file +{"name":"Shivan Dragon","layout":"normal","manaCost":"{4}{R}{R}","cmc":6,"type":"Creature — Dragon","rarity":"Rare","text":"Flying (This creature can't be blocked except by creatures with flying or reach.)\n{R}: Shivan Dragon gets +1/+0 until end of turn.","flavor":"The undisputed master of the mountains of Shiv.","artist":"Donato Giancola","number":"281","power":"5","toughness":"5","loyalty":null,"multiverseid":383172,"imageName":"shivan dragon","watermark":null,"setCode":"M15","imageCode":"m15"} diff --git a/test/testbase.cb b/test/testbase.cb index 80dc98f..13eee5d 100644 --- a/test/testbase.cb +++ b/test/testbase.cb @@ -1 +1 @@ -{"1588769":{"name":"Reverberate","layout":"normal","manaCost":"{R}{R}","cmc":2,"type":"Instant","rarity":"Rare","text":"Copy target instant or sorcery spell. You may choose new targets for the copy.","flavor":"For every action, there is a swifter and more violent reaction.","artist":"jD","number":"152","power":null,"toughness":null,"loyalty":null,"multiverseid":233722,"imageName":"reverberate","watermark":null,"setCode":"M12","imageCode":"m12","count":1},"126251":{"name":"Mighty Leap","layout":"normal","manaCost":"{1}{W}","cmc":2,"type":"Instant","rarity":"Common","text":"Target creature gets +2/+2 and gains flying until end of turn. (It can't be blocked except by creatures with flying or reach.)","flavor":"\"The southern fortress taken by invaders? Heh, sure . . . when elephants fly.\"\n—Brezard Skeinbow, captain of the guard","artist":"rk post","number":"26","power":null,"toughness":null,"loyalty":null,"multiverseid":241989,"imageName":"mighty leap","watermark":null,"setCode":"M12","imageCode":"m12","count":1},"1580419":{"name":"Formless Nurturing","layout":"normal","manaCost":"{3}{G}","cmc":4,"type":"Sorcery","rarity":"Common","text":"Manifest the top card of your library, then put a +1/+1 counter on it. (To manifest a card, put it onto the battlefield face down as a 2/2 creature. Turn it face up any time for its mana cost if it's a creature card.)","flavor":null,"artist":"Cliff Childs","number":"129","power":null,"toughness":null,"loyalty":null,"multiverseid":391837,"imageName":"formless nurturing","watermark":null,"setCode":"FRF","imageCode":"frf","count":8},"1580388":{"name":"Feral Krushok","layout":"normal","manaCost":"{4}{G}","cmc":5,"type":"Creature — Beast","rarity":"Common","text":null,"flavor":"In a stunning act of diplomacy, Yasova Dragonclaw ceded a portion of Temur lands to the Sultai. Her clan protested until they saw she had given the Sultai the breeding grounds of the krushoks. They hadn't realized she had a sense of humor.","artist":"Kev Walker","number":"128","power":"5","toughness":"4","loyalty":null,"multiverseid":391831,"imageName":"feral krushok","watermark":null,"setCode":"FRF","imageCode":"frf","count":1},"1580357":{"name":"Destructor Dragon","layout":"normal","manaCost":"{4}{G}{G}","cmc":6,"type":"Creature — Dragon","rarity":"Uncommon","text":"Flying\nWhen Destructor Dragon dies, destroy target noncreature permanent.","flavor":"After countless attacks on the Salt Road where it passes through the frozen tundra, the Abzan began to refer to the area as Atarka territory rather than Temur lands.","artist":"Peter Mohrbacher","number":"127","power":"4","toughness":"4","loyalty":null,"multiverseid":391818,"imageName":"destructor dragon","watermark":"Atarka","setCode":"FRF","imageCode":"frf","count":1},"127150":{"name":"Siege Mastodon","layout":"normal","manaCost":"{4}{W}","cmc":5,"type":"Creature — Elephant","rarity":"Common","text":null,"flavor":"\"The walls of the wicked will fall before us. Ready the siege engines. We proceed to war!\"\n—General Avitora","artist":"Matt Cavotta","number":"34","power":"3","toughness":"5","loyalty":null,"multiverseid":222635,"imageName":"siege mastodon","watermark":null,"setCode":"M12","imageCode":"m12","count":2}} \ No newline at end of file +{"1588769":{"name":"Reverberate","layout":"normal","manaCost":"{R}{R}","cmc":2,"type":"Instant","rarity":"Rare","text":"Copy target instant or sorcery spell. You may choose new targets for the copy.","flavor":"For every action, there is a swifter and more violent reaction.","artist":"jD","number":"152","power":null,"toughness":null,"loyalty":null,"multiverseid":233722,"imageName":"reverberate","watermark":null,"setCode":"M12","imageCode":"m12"},"126251":{"name":"Mighty Leap","layout":"normal","manaCost":"{1}{W}","cmc":2,"type":"Instant","rarity":"Common","text":"Target creature gets +2/+2 and gains flying until end of turn. (It can't be blocked except by creatures with flying or reach.)","flavor":"\"The southern fortress taken by invaders? Heh, sure . . . when elephants fly.\"\n—Brezard Skeinbow, captain of the guard","artist":"rk post","number":"26","power":null,"toughness":null,"loyalty":null,"multiverseid":241989,"imageName":"mighty leap","watermark":null,"setCode":"M12","imageCode":"m12"},"1580419":{"name":"Formless Nurturing","layout":"normal","manaCost":"{3}{G}","cmc":4,"type":"Sorcery","rarity":"Common","text":"Manifest the top card of your library, then put a +1/+1 counter on it. (To manifest a card, put it onto the battlefield face down as a 2/2 creature. Turn it face up any time for its mana cost if it's a creature card.)","flavor":null,"artist":"Cliff Childs","number":"129","power":null,"toughness":null,"loyalty":null,"multiverseid":391837,"imageName":"formless nurturing","watermark":null,"setCode":"FRF","imageCode":"frf"},"1580388":{"name":"Feral Krushok","layout":"normal","manaCost":"{4}{G}","cmc":5,"type":"Creature — Beast","rarity":"Common","text":null,"flavor":"In a stunning act of diplomacy, Yasova Dragonclaw ceded a portion of Temur lands to the Sultai. Her clan protested until they saw she had given the Sultai the breeding grounds of the krushoks. They hadn't realized she had a sense of humor.","artist":"Kev Walker","number":"128","power":"5","toughness":"4","loyalty":null,"multiverseid":391831,"imageName":"feral krushok","watermark":null,"setCode":"FRF","imageCode":"frf"},"1580357":{"name":"Destructor Dragon","layout":"normal","manaCost":"{4}{G}{G}","cmc":6,"type":"Creature — Dragon","rarity":"Uncommon","text":"Flying\nWhen Destructor Dragon dies, destroy target noncreature permanent.","flavor":"After countless attacks on the Salt Road where it passes through the frozen tundra, the Abzan began to refer to the area as Atarka territory rather than Temur lands.","artist":"Peter Mohrbacher","number":"127","power":"4","toughness":"4","loyalty":null,"multiverseid":391818,"imageName":"destructor dragon","watermark":"Atarka","setCode":"FRF","imageCode":"frf"},"127150":{"name":"Siege Mastodon","layout":"normal","manaCost":"{4}{W}","cmc":5,"type":"Creature — Elephant","rarity":"Common","text":null,"flavor":"\"The walls of the wicked will fall before us. Ready the siege engines. We proceed to war!\"\n—General Avitora","artist":"Matt Cavotta","number":"34","power":"3","toughness":"5","loyalty":null,"multiverseid":222635,"imageName":"siege mastodon","watermark":null,"setCode":"M12","imageCode":"m12"}} diff --git a/test/testcards.json b/test/testcards.json index 18b3783..3ab9906 100644 --- a/test/testcards.json +++ b/test/testcards.json @@ -1 +1 @@ -[{"name":"Callow Jushi","layout":"flip","manaCost":"{1}{U}{U}","cmc":3,"type":"Creature — Human Wizard","rarity":"Uncommon","text":"Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Callow Jushi.\nAt the beginning of the end step, if there are two or more ki counters on Callow Jushi, you may flip it.","flavor":null,"artist":"Tsutomu Kawade","number":"31a","power":"2","toughness":"2","loyalty":null,"multiverseid":74489,"imageName":"callow jushi","watermark":null,"setCode":"BOK","imageCode":"bok","count":1},{"name":"Coerced Confession","layout":"normal","manaCost":"{4}{U/B}","cmc":5,"type":"Sorcery","rarity":"Uncommon","text":"Target player puts the top four cards of his or her library into his or her graveyard. You draw a card for each creature card put into that graveyard this way.","flavor":"\"Ask the right questions in the right way and truth is inevitable.\"\n—Lazav","artist":"Mathias Kollros","number":"217","power":null,"toughness":null,"loyalty":null,"multiverseid":366408,"imageName":"coerced confession","watermark":"Dimir","setCode":"GTC","imageCode":"gtc","count":2},{"name":"Khalni Hydra","layout":"normal","manaCost":"{G}{G}{G}{G}{G}{G}{G}{G}","cmc":8,"type":"Creature — Hydra","rarity":"Mythic Rare","text":"Khalni Hydra costs {G} less to cast for each green creature you control.\nTrample","flavor":"\"In ages past, bargains were struck and promises were made. Now we must collect on our debt. Begin the hymns.\"\n—Moruul, Khalni druid","artist":"Todd Lockwood","number":"192","power":"8","toughness":"8","loyalty":null,"multiverseid":193551,"imageName":"khalni hydra","watermark":null,"setCode":"ROE","imageCode":"roe","count":3},{"name":"Nightmare","layout":"normal","manaCost":"{5}{B}","cmc":6,"type":"Creature — Nightmare Horse","rarity":"Rare","text":"Flying (This creature can't be blocked except by creatures with flying or reach.)\nNightmare's power and toughness are each equal to the number of Swamps you control.","flavor":"The thunder of its hooves beats dreams into despair.","artist":"Vance Kovacs","number":"276","power":"*","toughness":"*","loyalty":null,"multiverseid":383168,"imageName":"nightmare","watermark":null,"setCode":"M15","imageCode":"m15","count":8},{"name":"Shivan Dragon","layout":"normal","manaCost":"{4}{R}{R}","cmc":6,"type":"Creature — Dragon","rarity":"Rare","text":"Flying (This creature can't be blocked except by creatures with flying or reach.)\n{R}: Shivan Dragon gets +1/+0 until end of turn.","flavor":"The undisputed master of the mountains of Shiv.","artist":"Donato Giancola","number":"281","power":"5","toughness":"5","loyalty":null,"multiverseid":383172,"imageName":"shivan dragon","watermark":null,"setCode":"M15","imageCode":"m15","count":1},{"name":"Disrupting Shoal","layout":"normal","manaCost":"{X}{U}{U}","cmc":2,"type":"Instant — Arcane","rarity":"Rare","text":"You may exile a blue card with converted mana cost X from your hand rather than pay Disrupting Shoal's mana cost.\nCounter target spell if its converted mana cost is X.","flavor":null,"artist":"Scott M. Fischer","number":"33","power":null,"toughness":null,"loyalty":null,"multiverseid":74128,"imageName":"disrupting shoal","watermark":null,"setCode":"BOK","imageCode":"bok","count":15},{"name":"Sorin Markov","layout":"normal","manaCost":"{3}{B}{B}{B}","cmc":6,"type":"Planeswalker — Sorin","rarity":"Mythic Rare","text":"+2: Sorin Markov deals 2 damage to target creature or player and you gain 2 life.\n−3: Target opponent's life total becomes 10.\n−7: You control target player during that player's next turn.","flavor":null,"artist":"Michael Komarck","number":"109","power":null,"toughness":null,"loyalty":4,"multiverseid":238330,"imageName":"sorin markov","watermark":null,"setCode":"M12","imageCode":"m12","count":1},{"name":"Ugin's Construct","layout":"normal","manaCost":"{4}","cmc":4,"type":"Artifact Creature — Construct","rarity":"Uncommon","text":"When Ugin's Construct enters the battlefield, sacrifice a permanent that's one or more colors.","flavor":"While trapping the Eldrazi on Zendikar, Ugin learned little from Sorin, but he gleaned the rudiments of lithomancy from Nahiri.","artist":"Peter Mohrbacher","number":"164","power":"4","toughness":"5","loyalty":null,"multiverseid":391949,"imageName":"ugin's construct","watermark":null,"setCode":"FRF","imageCode":"frf","count":1}] \ No newline at end of file +[{"name":"Callow Jushi","layout":"flip","manaCost":"{1}{U}{U}","cmc":3,"type":"Creature — Human Wizard","rarity":"Uncommon","text":"Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Callow Jushi.\nAt the beginning of the end step, if there are two or more ki counters on Callow Jushi, you may flip it.","flavor":null,"artist":"Tsutomu Kawade","number":"31a","power":"2","toughness":"2","loyalty":null,"multiverseid":74489,"imageName":"callow jushi","watermark":null,"setCode":"BOK","imageCode":"bok"},{"name":"Coerced Confession","layout":"normal","manaCost":"{4}{U/B}","cmc":5,"type":"Sorcery","rarity":"Uncommon","text":"Target player puts the top four cards of his or her library into his or her graveyard. You draw a card for each creature card put into that graveyard this way.","flavor":"\"Ask the right questions in the right way and truth is inevitable.\"\n—Lazav","artist":"Mathias Kollros","number":"217","power":null,"toughness":null,"loyalty":null,"multiverseid":366408,"imageName":"coerced confession","watermark":"Dimir","setCode":"GTC","imageCode":"gtc"},{"name":"Khalni Hydra","layout":"normal","manaCost":"{G}{G}{G}{G}{G}{G}{G}{G}","cmc":8,"type":"Creature — Hydra","rarity":"Mythic Rare","text":"Khalni Hydra costs {G} less to cast for each green creature you control.\nTrample","flavor":"\"In ages past, bargains were struck and promises were made. Now we must collect on our debt. Begin the hymns.\"\n—Moruul, Khalni druid","artist":"Todd Lockwood","number":"192","power":"8","toughness":"8","loyalty":null,"multiverseid":193551,"imageName":"khalni hydra","watermark":null,"setCode":"ROE","imageCode":"roe"},{"name":"Nightmare","layout":"normal","manaCost":"{5}{B}","cmc":6,"type":"Creature — Nightmare Horse","rarity":"Rare","text":"Flying (This creature can't be blocked except by creatures with flying or reach.)\nNightmare's power and toughness are each equal to the number of Swamps you control.","flavor":"The thunder of its hooves beats dreams into despair.","artist":"Vance Kovacs","number":"276","power":"*","toughness":"*","loyalty":null,"multiverseid":383168,"imageName":"nightmare","watermark":null,"setCode":"M15","imageCode":"m15"},{"name":"Shivan Dragon","layout":"normal","manaCost":"{4}{R}{R}","cmc":6,"type":"Creature — Dragon","rarity":"Rare","text":"Flying (This creature can't be blocked except by creatures with flying or reach.)\n{R}: Shivan Dragon gets +1/+0 until end of turn.","flavor":"The undisputed master of the mountains of Shiv.","artist":"Donato Giancola","number":"281","power":"5","toughness":"5","loyalty":null,"multiverseid":383172,"imageName":"shivan dragon","watermark":null,"setCode":"M15","imageCode":"m15"},{"name":"Disrupting Shoal","layout":"normal","manaCost":"{X}{U}{U}","cmc":2,"type":"Instant — Arcane","rarity":"Rare","text":"You may exile a blue card with converted mana cost X from your hand rather than pay Disrupting Shoal's mana cost.\nCounter target spell if its converted mana cost is X.","flavor":null,"artist":"Scott M. Fischer","number":"33","power":null,"toughness":null,"loyalty":null,"multiverseid":74128,"imageName":"disrupting shoal","watermark":null,"setCode":"BOK","imageCode":"bok"},{"name":"Sorin Markov","layout":"normal","manaCost":"{3}{B}{B}{B}","cmc":6,"type":"Planeswalker — Sorin","rarity":"Mythic Rare","text":"+2: Sorin Markov deals 2 damage to target creature or player and you gain 2 life.\n−3: Target opponent's life total becomes 10.\n−7: You control target player during that player's next turn.","flavor":null,"artist":"Michael Komarck","number":"109","power":null,"toughness":null,"loyalty":4,"multiverseid":238330,"imageName":"sorin markov","watermark":null,"setCode":"M12","imageCode":"m12"},{"name":"Ugin's Construct","layout":"normal","manaCost":"{4}","cmc":4,"type":"Artifact Creature — Construct","rarity":"Uncommon","text":"When Ugin's Construct enters the battlefield, sacrifice a permanent that's one or more colors.","flavor":"While trapping the Eldrazi on Zendikar, Ugin learned little from Sorin, but he gleaned the rudiments of lithomancy from Nahiri.","artist":"Peter Mohrbacher","number":"164","power":"4","toughness":"5","loyalty":null,"multiverseid":391949,"imageName":"ugin's construct","watermark":null,"setCode":"FRF","imageCode":"frf"}] diff --git a/todo b/todo index ef1b7ad..7644fcc 100644 --- a/todo +++ b/todo @@ -1,4 +1,5 @@ -TESTS +parsing the new cardbase file format +fix up the test files -Cardbase: +Cardbase tests: * decks \ No newline at end of file -- cgit v1.2.3