diff --git a/src/Card.java b/src/Card.java old mode 100755 new mode 100644 index 9eed9a5..036dfde --- a/src/Card.java +++ b/src/Card.java @@ -1,7 +1,110 @@ -public class Card { +public class Card +{ + private int quantity; + private int color; + private int shading; + private int shape; // Create the rest of this class yourself + public Card(int q, int c, int s, int sh) + { + quantity = fixValue(q); + color = fixValue(c); + shading = fixValue(s); + shape = fixValue(sh); + } + public int getQuantity() + { + return quantity; + } + + public int getColor() + { + return color; + } + + public int getShading() + { + return shading; + } + + public int getShape() + { + return shape; + } - public boolean equals(Object obj) { + public boolean isSet(Card c, Card d) + { + if((c.getQuantity() + d.getQuantity() + quantity) % 3 == 0 && + (c.getColor() + d.getColor() +color) % 3 == 0 && + (c.getShading() + d.getShading() + shading) % 3 == 0 && + (c.getShape() + d.getShape() + shape) % 3 == 0) + { + return true; + } + else + { + return false; + } + } + + public String toString() + { + String str = ""; + str += quantity; + if(color == 1) + { + str += "R"; + } + if(color == 2) + { + str += "G"; + } + if(color == 3) + { + str += "P"; + } + if(shading == 1) + { + str += "O"; + } + if(shading == 2) + { + str += "T"; + } + if(shading == 3) + { + str += "S"; + } + if(shape == 1) + { + str += "V"; + } + if(shape == 2) + { + str += "D"; + } + if(shape == 3) + { + str += "Q"; + } + + return str; + } + + private int fixValue(int valueToFix) + { + if(valueToFix < 1 || valueToFix > 3) + { + return(((valueToFix % 3) + 3) % 3) + 1; + } + else + { + return valueToFix; + } + } + + public boolean equals(Object obj) + { Card that = (Card)obj; return quantity == that.getQuantity() && @@ -9,4 +112,6 @@ public boolean equals(Object obj) { shading == that.getShading() && shape == that.getShape(); } + + } diff --git a/src/CardTest.java b/src/CardTest.java new file mode 100644 index 0000000..c705953 --- /dev/null +++ b/src/CardTest.java @@ -0,0 +1,27 @@ +import junit.framework.TestCase; + +/** + * A JUnit test case class. + * Every method starting with the word "test" will be called when running + * the test with JUnit. + */ +public class CardTest extends TestCase { + + /** + * A test method. + * (Replace "X" with a name describing the test. You may write as + * many "testSomething" methods in this class as you wish, and each + * one will be called when running JUnit over this class.) + */ + public void testCardSet() { + Card c1 = new Card(3,4,2,4); + Card c2 = new Card(2,-4,2,1); + Card c3 = new Card(1,1,2,5); + + assertTrue(c1.isSet(c2, c3)); + assertEquals("3GTD",c1.toString()); + assertEquals("2PTV",c2.toString()); + assertEquals("1RTQ",c3.toString()); + } + +} diff --git a/src/Deck.java b/src/Deck.java old mode 100755 new mode 100644 index ab3a2a3..3acfa7f --- a/src/Deck.java +++ b/src/Deck.java @@ -2,19 +2,47 @@ import java.io.FileReader; import java.util.StringTokenizer; import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; -public class Deck { +public class Deck +{ // Implement the rest of this class yourself + private int nextCardIndex = 0; + private ArrayList cards; - public Deck(String filename) { + public Deck() + { + cards = new ArrayList(81); + for(int q = 1; q<=3; q++) + { + for(int c = 1; c<=3; c++) + { + for(int s = 1; s<=3; s++) + { + for(int sh = 1; sh<=3; sh++) + { + Card leaf = new Card(q, c, s, sh); + } + } + } + } + Collections.shuffle(cards); + } + + + public Deck(String filename) + { cards = new ArrayList(81); - try { + try + { String line; BufferedReader infile = new BufferedReader(new FileReader(filename)); int position = 0; - while((line = infile.readLine()) != null) { + while((line = infile.readLine()) != null) + { // Blank lines might contain white space, so trim it off line = line.trim(); @@ -38,8 +66,37 @@ public Deck(String filename) { nextCardIndex = 0; } } - catch(Exception e) { + catch(Exception e) + { throw new RuntimeException("Error while reading file: " + e.toString()); } } + public boolean hasNext() + { + //Returns true if any cards are left, false otherwise + if(nextCardIndex < cards.size()) + { + return true; + } + else + { + return false; + } + } + + public Card getNext() + { + //Returns the next card in the deck if there is one. null otherwise. + if(hasNext() == true) + { + nextCardIndex++; + return cards.get(nextCardIndex-1); + } + else + { + return null; + } + //You can call hasNext() within this method to see if you should return + //a card or null + } } diff --git a/src/DeckTester.java b/src/DeckTester.java new file mode 100644 index 0000000..c96b748 --- /dev/null +++ b/src/DeckTester.java @@ -0,0 +1,31 @@ +import junit.framework.TestCase; + +/** + * A JUnit test case class. + * Every method starting with the word "test" will be called when running + * the test with JUnit. + */ +public class DeckTester extends TestCase { + + /** + * A test method. + * (Replace "X" with a name describing the test. You may write as + * many "testSomething" methods in this class as you wish, and each + * one will be called when running JUnit over this class.) + */ + public void testOneCard() { + Deck d = new Deck("OneCard.dat"); + assertTrue(d.hasNext()); + assertEquals("1ROO", d.getNext().toString()); + } + + public void testIsSet(){ + Deck d = new Deck("CardSet.dat"); + assertTrue(d.hasNext()); + assertEquals + } + + public void testNoSet(){ + } + +} diff --git a/src/Game.java b/src/Game.java new file mode 100644 index 0000000..b435e75 --- /dev/null +++ b/src/Game.java @@ -0,0 +1,90 @@ +public class Game +{ + private Table t; + private Deck d; + + public Game() + { + d = new Deck(); + t = new Table(); + + for(int i = 0; i< 12; i++) + { + if(d.hasNext() == true) + { + t.add(d.getNext()); + } + } + } + + public Game(String filename) + { + d = new Deck(filename); + t = new Table(); + + int j = 0; + while(d.hasNext() == true) + { + t.add(d.getNext()); + j++; + + if(t.numCards() == 12) + return; + } + } + + public int numSets() + { + return t.numSets(); + } + + public int numCards() + { + return t.numCards(); + } + + public void playRound() + { + if(numSets() >=1) + { + for(int j = 0; j < numCards()-2; j++) + { + for(int k = j + 1; k< numCards()-1; k++) + { + for(int x = k + 1; x< numCards(); x++) + { + if(t.getCard(j).isSet(t.getCard(k), t.getCard(x))) + { + t.removeSet(t.getCard(j), t.getCard(k), t.getCard(x)); + if(numCards() < 12) + { + for(int y = 0; y < 3 && d.hasNext(); y++) + { + t.add(d.getNext()); + } + } + return; + + } + } + } + } + + } + if(numSets() == 0) + { + + for(int i = 0; i<3 && d.hasNext(); i++) + t.add(d.getNext()); + return; + } + } + + public boolean isGameOver() + { + if(numSets() == 0 && !d.hasNext()) + return true; + else + return false; + } +} \ No newline at end of file diff --git a/src/GameTest.java b/src/GameTest.java new file mode 100644 index 0000000..e587d2a --- /dev/null +++ b/src/GameTest.java @@ -0,0 +1,167 @@ +import junit.framework.TestCase; + +/** + * A JUnit test case class. + * Every method starting with the word "test" will be called when running + * the test with JUnit. + */ +public class GameTest extends TestCase { + + /** + * A test method. + * (Replace "X" with a name describing the test. You may write as + * many "testSomething" methods in this class as you wish, and each + * one will be called when running JUnit over this class.) + */ + public void testGame() { + Game g = new Game(); + assertEquals(g.numCards(), 12); + assertFalse(g.isGameOver()); + } + + public void noSetsFirstTwelve() + { + Game g = new Game("15cards0setsin12Milestone.dat"); + assertEquals(0, g.numSets()); + assertEquals(12, g.numCards()); + + g.playRound(); + + assertEquals(15, g.numCards()); + } + + public void testNoSetsFirstFifteen() + { + Game g = new Game("18cards0setsin15Milestone.dat"); + + assertEquals(0, g.numSets()); + assertEquals(12, g.numCards()); + + g.playRound(); + + assertEquals(0, g.numSets()); + assertEquals(15, g.numCards()); + + g.playRound(); + + assertEquals(9, g.numSets()); + assertEquals(18, g.numCards()); + } + + public void testBackToTwelveAfterFifteen() + { + Game g = new Game("15cards0setsin12Milestone.dat"); + g.playRound(); + + assertEquals(15, g.numCards()); + + g.playRound(); + assertEquals(12, g.numCards()); + } + + public void testBackToFifteenAfterEighteen() + { + Game g = new Game("18cards0setsin15Milestone.dat"); + g.playRound(); + g.playRound(); + + assertEquals(18, g.numCards()); + + g.playRound(); + assertEquals(15, g.numCards()); + } + + public void testDeckNotMultipleOfThree() + { + Game g = new Game("14cardsMilestone.dat"); + assertEquals(12, g.numCards()); + // when we play a round, there is a set, but there are + // only 2 more cards available. + g.playRound(); + + assertEquals(11, g.numCards()); + } + + public void testDeckLessThanTwelve() + { + Game g = new Game("7cardsMilestone.dat"); + + assertEquals(7, g.numCards()); + g.playRound(); + + assertEquals(4, g.numCards()); + } + + public void testGameOverEmptyTable() + { + Game g = new Game("12cards4setsMilestone.dat"); + + assertEquals(12, g.numCards()); + assertEquals(4, g.numSets()); + + g.playRound(); + assertEquals(9, g.numCards()); + assertEquals(3, g.numSets()); + + g.playRound(); + assertEquals(6, g.numCards()); + assertEquals(2, g.numSets()); + + g.playRound(); + assertEquals(3, g.numCards()); + assertEquals(1, g.numSets()); + + g.playRound(); + assertEquals(0, g.numCards()); + assertTrue(g.isGameOver()); + } + + public void test14Sets() + { + Game g = new Game("14in12Milestone.dat"); + + assertEquals(12, g.numCards()); + assertEquals(14, g.numSets()); + assertFalse(g.isGameOver()); + + g.playRound(); + assertEquals(9, g.numCards()); + assertFalse(g.isGameOver()); + + g.playRound(); + assertEquals(6, g.numCards()); + assertFalse(g.isGameOver()); + + g.playRound(); + assertEquals(3, g.numCards()); + assertTrue(g.isGameOver()); + } + + public void testRemoveAdd() + { + Game g = new Game("15cardsMilestone.dat"); + + assertEquals(12, g.numCards()); + assertEquals(3, g.numSets()); + assertFalse(g.isGameOver()); + + g.playRound(); + + assertEquals(12, g.numCards()); + assertEquals(3, g.numSets()); + assertFalse(g.isGameOver()); + + g.playRound(); + assertEquals(9, g.numCards()); + assertEquals(1, g.numSets()); + assertFalse(g.isGameOver()); + + g.playRound(); + assertEquals(6, g.numCards()); + assertEquals(0, g.numSets()); + assertTrue(g.isGameOver()); + } +} + + + diff --git a/src/MonteCarlo.java b/src/MonteCarlo.java new file mode 100644 index 0000000..b0b510e --- /dev/null +++ b/src/MonteCarlo.java @@ -0,0 +1,20 @@ +public class MonteCarlo +{ + public static void main(String[] args) + { + float sum = 0; + float sum2 = 0; + for(int i = 0; i<10000; i++) + { + Game g = new Game(); + sum += g.numSets(); + while(g.isGameOver() == false) + { + g.playRound(); + } + sum2+= g.numCards(); + } + System.out.println("The average number of sets on the table are: " + sum/10000); + System.out.print("The average number of cards at the end of the game are: " + sum2/10000); + } +} \ No newline at end of file diff --git a/src/Table.java b/src/Table.java new file mode 100644 index 0000000..3766049 --- /dev/null +++ b/src/Table.java @@ -0,0 +1,161 @@ +public class Table +{ + private TableNode head; + private int length; + + public Table() + { + //initialize head + head = null; + } + + public void add(Card card) + { + if(head == null) + head = new TableNode(card); + else + { + TableNode n = new TableNode(card); + length++; + n.setNext(head); + head = n; + } + } + + private boolean onTable(Card p) + { + TableNode curr = head; + while(curr!= null) + { + if(curr.getCard().equals(p)) + { + return true; + } + curr= curr.getNext(); + } + + return false; + } + + private void removeCard(Card y) + { + TableNode prev = findPrev(y); + length-=1; + if(prev == null) + { + head = head.getNext(); + } + else + { + TableNode curr = prev.getNext(); + prev.setNext(curr.getNext()); + } + } + + private TableNode findPrev(Card c) + { + TableNode prev = null; + TableNode curr = head; + + while(curr!= null) + { + Card n = curr.getCard(); + if(n.equals(c)) + { + return prev; + } + prev = curr; + curr = curr.getNext(); + } + return null; + } + + public void removeSet(Card c1, Card c2, Card c3) + { + if(!c1.isSet(c2, c3)) + { + return; + } + if(!onTable(c1)) + { + return; + } + if(!onTable(c2)) + { + return; + } + if(!onTable(c3)) + { + return; + } + removeCard(c1); + removeCard(c2); + removeCard(c3); + //if 3 cards dont form a set or if any of the cards are not on the table, + // return. + //otherwise: + // remove c1, c2, and c3 preserving the relative order of the rest of the cards. + } + + public int numCards() + { + int count = 0; + TableNode curr = head; + if(curr == null) + { + return 0; + } + while(curr!= null) + { + count++; + curr = curr.getNext(); + } + //if we havent stored the length of the list, we have to iterate through the + //list and count the cards. + return count; + } + + public Card getCard(int index) + { + TableNode p = head; + //if index is out of bounds, return null. + //otherwise: + // iterate through the list index number of times, + // return the node there + if(index >= length || p == null) + return null; + if(index == 0) + return p.getCard(); + for(int j = 0; j < index; j++) + { + p = p.getNext(); + } + return p.getCard(); + } + + public int numSets() + { + //get all triples of cards on the table, and check isSet(). Create a counter and + //everytime isSet() == true, update the counter by 1. + int counter = 0; + + for(int j = 0; j< length-2; j++) + { + for(int k = j + 1; k< length-1; k++) + { + for(int z = k + 1; z< length; z++) + { + Card i = getCard(j); + Card e = getCard(k); + Card o = getCard(z); + + if(i.isSet(e,o)) + { + counter++; + } + } + } + } + return counter; + } +} \ No newline at end of file diff --git a/src/TableNode.java b/src/TableNode.java new file mode 100644 index 0000000..2ef64d5 --- /dev/null +++ b/src/TableNode.java @@ -0,0 +1,26 @@ +public class TableNode +{ + private Card card; + private TableNode next; + + public TableNode(Card c) + { + card = c; + next = null; + } + + public void setNext(TableNode t) + { + next = t; + } + + public TableNode getNext() + { + return next; + } + + public Card getCard() + { + return card; + } +} \ No newline at end of file diff --git a/src/TableTest.java b/src/TableTest.java new file mode 100644 index 0000000..8b2d775 --- /dev/null +++ b/src/TableTest.java @@ -0,0 +1,44 @@ +import junit.framework.TestCase; + +/** + * A JUnit test case class. + * Every method starting with the word "test" will be called when running + * the test with JUnit. + */ +public class TableTest extends TestCase { + + /** + * A test method. + * (Replace "X" with a name describing the test. You may write as + * many "testSomething" methods in this class as you wish, and each + * one will be called when running JUnit over this class.) + */ + public void testTableSet() { + Table tab = new Table(); + + Card c1 = new Card(1,1,1,1); + Card c2 = new Card(1,1,1,1); + Card c3 = new Card(1,1,1,1); + + tab.add(c1); + tab.add(c2); + tab.add(c3); + + assertEquals(3, tab.numCards()); + tab.removeSet(c1,c2,c3); + } + + public void testNumSet(){ + Table tab = new Table(); + Card c1 = new Card(2,1,1,1); + Card c2 = new Card(3,1,1,1); + Card c3 = new Card(3,1,1,1); + + tab.add(c1); + tab.add(c2); + tab.add(c3); + + assertEquals(0, tab.numSets()); + } + +}