diff --git a/src/Card.java b/src/Card.java old mode 100755 new mode 100644 index 9eed9a5..efe2d86 --- a/src/Card.java +++ b/src/Card.java @@ -1,5 +1,84 @@ public class Card { - // Create the rest of this class yourself + private int quantity; + private int color; + private int shading; + private int shape; + + public Card(int q, int c, int shd, int shp){ + quantity = fixValue(q); + color = fixValue(c); + shading = fixValue(shd); + shape = fixValue(shp); + } + + public int getQuantity() { + return quantity; + } + + public int getColor() { + return color; + } + + public int getShading() { + return shading; + } + + public int getShape() { + return shape; + } + + public boolean isSet(Card c1, Card c2) { + if((c1.getQuantity() + c2.getQuantity() + quantity) % 3 == 0 && + (c1.getColor() + c2.getColor() + color) % 3 == 0 && + (c1.getShading() + c2.getShading() + shading) % 3 == 0 && + (c1.getShape() + c2.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 += "O"; + } + if(shape == 2) { + str += "D"; + } + if(shape == 3) { + str += "S"; + } + 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; diff --git a/src/CardTest.java b/src/CardTest.java new file mode 100644 index 0000000..9b5e0b7 --- /dev/null +++ b/src/CardTest.java @@ -0,0 +1,66 @@ +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 testAllOnes() { + Card c1 = new Card(1, 1, 1, 1); + Card c2 = new Card(1, 1, 1, 1); + + assertEquals(c1, c2); + } + + public void testThreeCards() { + Card c1 = new Card(1, 1, 1, 1); + Card c2 = new Card(1, 1, 1, 1); + Card c3 = new Card(1, 1, 1, 1); + + assertEquals(c1, c2); + assertEquals(c1, c3); + assertEquals(c2, c3); + } + public void testIsSet() { + Card c1 = new Card(1, 1, 1, 1); + Card c2 = new Card(1, 1, 1, 1); + Card c3 = new Card(1, 1, 1, 1); + + assertTrue(c1.isSet(c2,c3)); + } + public void testNotSet() { + Card c1 = new Card(1, 2, 3, 1); + Card c2 = new Card(2, 3, 3, 1); + Card c3 = new Card(2, 3, 3, 3); + + assertFalse(c1.isSet(c2,c3)); + } + public void testToString() { + Card c1 = new Card(1, 2, 3, 1); + + assertEquals("1GSO", c1.toString()); + } + public void testInvalidNumbers() { + Card c1 = new Card(8, 7, 6, 4); + + assertEquals("3GOD", c1.toString()); + } + public void testNegativeNumbers() { + Card c1 = new Card(-8, -7, -6, -4); + + assertEquals("2POS", c1.toString()); + } + public void testNegativeAndPositiveNumbers() { + Card c1 = new Card(-8, 3, -6, 4); + + assertEquals("2POD", c1.toString()); + } +} diff --git a/src/Deck.java b/src/Deck.java old mode 100755 new mode 100644 index ab3a2a3..86744c6 --- a/src/Deck.java +++ b/src/Deck.java @@ -2,9 +2,52 @@ import java.io.FileReader; import java.util.StringTokenizer; import java.util.ArrayList; +import java.util.Collections; public class Deck { - // Implement the rest of this class yourself + private ArrayList cards; + private int nextCardIndex; + + public Deck() { + // Creates a deck with all standard 81 set cards, shuffled. + cards = new ArrayList(81); + + for (int quantity =1; quantity <= 3; quantity ++) { + for (int color =1; color <= 3; color++) { + for (int shading =1; shading <= 3; shading++) { + for (int shape =1; shape <= 3; shape++) { + Card c = new Card(quantity, color, shading, shape); + cards.add(c); + } + } + } + } + Collections.shuffle(cards); + } + +// public Deck(String filename) { +// Creates a pre-defined deck from a file named filename, and does not shuffle it. +// Usage (in test code, and in the later code): +// Deck d = new Deck("example.dat"); +// } + + public boolean hasNext() { + // Returns true if any cards 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 += 1; + return cards.get(nextCardIndex -1); + } + else + return null; + } public Deck(String filename) { cards = new ArrayList(81); diff --git a/src/DeckTest.java b/src/DeckTest.java new file mode 100644 index 0000000..59c231c --- /dev/null +++ b/src/DeckTest.java @@ -0,0 +1,62 @@ +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 DeckTest 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("1GSO", d.getNext().toString()); + assertFalse(d.hasNext()); + } + public void testOneSet() { + Deck d = new Deck("oneSet.dat"); + + assertTrue(d.hasNext()); + assertEquals("1ROO", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("1GTD", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("1PSS", d.getNext().toString()); + assertFalse(d.hasNext()); + } + public void testNoSet() { + Deck d = new Deck("noSet.dat"); + + assertTrue(d.hasNext()); + assertEquals("1GSO", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("1GOO", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("1ROO", d.getNext().toString()); + assertFalse(d.hasNext()); + } + public void testSixCardsWithOneSet() { + Deck d = new Deck("sixCards.dat"); + + assertTrue(d.hasNext()); + assertEquals("1ROO", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("2GTD", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("3PSS", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("1GSO", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("1RTD", d.getNext().toString()); + assertTrue(d.hasNext()); + assertEquals("3GOD", d.getNext().toString()); + assertFalse(d.hasNext()); + } +} diff --git a/src/Game.java b/src/Game.java new file mode 100644 index 0000000..f51082f --- /dev/null +++ b/src/Game.java @@ -0,0 +1,104 @@ +public class Game { + private Deck d; + private Table t; + + public Game() { + d = new Deck(); + t = new Table(); + + for (int i = 0; i < 12; i++) { + t.add(d.getNext()); + } + } + + public Game(String filename) { + // uses a preset deck + d = new Deck(filename); + t = new Table(); + + while (d.hasNext() == true) { + t.add(d.getNext()); + + if (t.numCards() == 12) { + return; + } + } + } + + public int numSets() { + return t.numSets(); + } + + public int numCards() { + return t.numCards(); + } + + public void playRound() { + if (t.numSets() == 0 && d.hasNext() == true) { + for (int i = 0; i < 3; i++) { + if (d.hasNext() == false) { + return; + } + t.add(d.getNext()); + } + return; + } + + else if (t.numSets() > 0 && d.hasNext() == true) { + for (int i = 0; i < t.numCards() - 2; i++) { + for (int j = i + 1; j < t.numCards() - 1; j++) { + for (int h = j + 1; h < t.numCards(); h++) { + + Card c1 = t.getCard(i); + Card c2 = t.getCard(j); + Card c3 = t.getCard(h); + + if (c1.isSet(c2,c3)) { + t.removeSet(c1,c2,c3); + } + + if (numCards() < 12 && d.hasNext() == true) { + + while ( t.numCards() < 12) { + + if (d.hasNext() == false) { + return; + } + t.add(d.getNext()); + } + return; + } + } + } + } + } + + else if (t.numSets() != 0 && d.hasNext() == false) { + for (int i = 0; i < t.numCards() - 2; i++) { + for (int j = i + 1; j < t.numCards() - 1; j++) { + for (int h = j + 1; h < t.numCards(); h++) { + + Card c1 = t.getCard(i); + Card c2 = t.getCard(j); + Card c3 = t.getCard(h); + + if (c1.isSet(c2,c3)) { + t.removeSet(c1,c2,c3); + return; + } + } + } + } + } + return; + } + + public boolean isGameOver() { + if (d.hasNext() == false && t.numSets() == 0) { + return true; + } + else { + return false; + } + } +} \ No newline at end of file diff --git a/src/GameAverage.java b/src/GameAverage.java new file mode 100644 index 0000000..895f37a --- /dev/null +++ b/src/GameAverage.java @@ -0,0 +1,19 @@ +public class GameAverage { + public static void main(String[] args) { + + float setSum = 0; + float cardSum = 0; + + for (int i = 0; i < 1000000; i++) { + Game g = new Game(); + setSum += g.numSets(); + + while (g.isGameOver() == false) { + g.playRound(); + } + cardSum += g.numCards(); + } + System.out.println ("Average number of sets from 12 cards: " + setSum/1000000); + System.out.println ("Average number of remaining cards at the end of a game: " + cardSum/1000000); + } +} \ No newline at end of file diff --git a/src/Table.java b/src/Table.java new file mode 100644 index 0000000..7243203 --- /dev/null +++ b/src/Table.java @@ -0,0 +1,127 @@ +public class Table { + private TableNode head; + + public Table() { + //initialize head + head = null; + } + + public void add(Card card) { + TableNode newTableNode = new TableNode(card); + newTableNode.setNext(head); + head = newTableNode; + } + + private boolean onTable(Card c) { + TableNode curr = head; + + while (curr != null) { + if (curr.getCard().equals(c)) { + return true; + } + curr = curr.getNext(); + } + return false; + } + + private void removeCard(Card c) { + TableNode prev = findPrev(c); + + if (prev == null) // head remove + head = head.getNext(); + else {// middle or tail remove + TableNode curr = prev.getNext(); + prev.setNext(curr.getNext()); + } + } + + private TableNode findPrev(Card c) { + TableNode curr = head; + TableNode prev = null; + + while (curr != null) { + if (c.equals(curr.getCard())) { + return prev; + } + else { + prev = curr; + curr = curr.getNext(); + } + } + return null; + } + + public void removeSet(Card c1, Card c2, Card 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. + + if (! c1.isSet(c2,c3)) + return; + if (! onTable(c1)) + return; + if (! onTable(c2)) + return; + if (! onTable(c3)) + return; + removeCard(c1); + removeCard(c2); + removeCard(c3); + } + + public int numCards() { + //if we havent stored the length of the list, we have to iterate through the + //list and count the cards. + + TableNode curr = head; + int count = 0; + + while (curr != null) { + count += 1; + curr = curr.getNext(); + } + return count; + } + + public Card getCard(int index) { + //if index is out of bounds, return null. + //otherwise: + // iterate through the list index number of times, + // return the node there + + TableNode temp = head; + if (temp == null) + return null; + + for (int i = 0; i < index; i++) { + temp = temp.getNext(); + + if (temp == null) + return null; + } + return temp.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 count = 0; + int length = numCards(); + + for (int i = 0; i < length - 2; i++) { + for (int t = i + 1; t < length -1; t++) { + for (int h = t + 1; h < length; h++) { + + Card c1 = getCard(i); + Card c2 = getCard(t); + Card c3 = getCard(h); + + if (c1.isSet(c2, c3)) + count +=1; + } + } + } + return count; + } +} \ No newline at end of file diff --git a/src/TableNode.java b/src/TableNode.java new file mode 100644 index 0000000..33d8431 --- /dev/null +++ b/src/TableNode.java @@ -0,0 +1,21 @@ +public class TableNode { + private Card card; + private TableNode next; + + public TableNode(Card c) { + card = c; + next = null; + } + + public void setNext(TableNode node) { + next = node; + } + + public TableNode getNext() { + return next; + } + + public Card getCard() { + return card; + } +} \ No newline at end of file diff --git a/src/TableNodeTest.java b/src/TableNodeTest.java new file mode 100644 index 0000000..39699e0 --- /dev/null +++ b/src/TableNodeTest.java @@ -0,0 +1,22 @@ +import junit.framework.TestCase; + +public class TableNodeTest extends TestCase { + public void testTableNode() { + + Card card1 = new Card(2, 3, 3, 1); + TableNode n1 = new TableNode(card1); + assertEquals(null, n1.getNext()); + assertEquals(card1, n1.getCard()); + + Card card2 = new Card(1, 2, 3, 1); + TableNode n2 = new TableNode(card2); + assertEquals(null, n1.getNext()); + assertEquals(card2, n2.getCard()); + + Card card3 = new Card(1, 2, 2, 2); + TableNode n3 = new TableNode(card3); + assertEquals(null, n1.getNext()); + assertEquals(card3, n3.getCard()); + } + +} diff --git a/src/TableTest.java b/src/TableTest.java new file mode 100644 index 0000000..0e9fdc3 --- /dev/null +++ b/src/TableTest.java @@ -0,0 +1,56 @@ +import junit.framework.TestCase; + + +public class TableTest extends TestCase { + public void testNumCards() { + Card c1 = new Card(1, 1, 1, 1); + Card c2 = new Card(2, 2, 2, 2); + Card c3 = new Card(3, 3, 3, 3); + + Table t = new Table(); + + t.add(c1); + t.add(c2); + t.add(c3); + + assertEquals(3, t.numCards()); + } + + public void testRemoveSet() { + Table t = new Table(); + + Card c1 = new Card(1, 1, 1, 1); + Card c2 = new Card(2, 2, 2, 2); + Card c3 = new Card(3, 3, 3, 3); + Card c4 = new Card(1, 2, 3, 1); + + t.add(c1); + t.add(c2); + t.add(c3); + t.add(c4); + + assertEquals(1, t.numSets()); + assertEquals(4, t.numCards()); + assertTrue(c1.isSet(c2, c3)); + + t.removeSet(c1, c2, c3); + + assertEquals(1, t.numCards()); + } + + public void testGetCard() { + Card c1 = new Card(1, 1, 1, 1); + Card c2 = new Card(2, 2, 2, 2); + Card c3 = new Card(3, 3, 3, 3); + + Table t = new Table(); + + t.add(c1); + t.add(c2); + t.add(c3); + + assertEquals("1ROO", t.getCard(0).toString()); + assertEquals("2GTD", t.getCard(1).toString()); + assertEquals("3PSS", t.getCard(2).toString()); + } +}