/* @(#)Methods.java 17 September 2005 */ /* Useful imports */ import edu.neu.ccs.*; import edu.neu.ccs.gui.*; import edu.neu.ccs.codec.*; import edu.neu.ccs.console.*; import edu.neu.ccs.filter.*; import edu.neu.ccs.jpf.*; import edu.neu.ccs.parser.*; import edu.neu.ccs.pedagogy.*; import edu.neu.ccs.quick.*; import edu.neu.ccs.util.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.font.*; import java.awt.image.*; import javax.swing.*; import javax.swing.border.*; import java.io.*; import java.util.*; import java.math.*; import java.beans.*; import java.lang.reflect.*; import java.net.URL; import java.util.regex.*; import java.text.ParseException; public class Goyne_Cardgame extends DisplayPanel implements JPTConstants { protected Goyne_Card[] cards = new Goyne_Card[52]; protected Goyne_Card[] rowHeaders = new Goyne_Card[16]; protected Goyne_Card[] cardStacks = new Goyne_Card[8]; protected Goyne_Card[] holdPiles = new Goyne_Card[4]; protected Goyne_Card[] victoryPiles = new Goyne_Card[4]; protected boolean[] pilesUsed = {false, false, false, false}; protected Integer pileCount = 4; protected final int BUFFERSIZE = 800; protected BufferedPanel window = new BufferedPanel(BUFFERSIZE, BUFFERSIZE); protected TablePanel mainPanel = new TablePanel( new Object[] { new Display(window, null, "Graphics") }, HORIZONTAL, 5, 5, NORTH); /* * TODO: Register click actions, preferably in a working manner * (Use wrapper for stacks?) * Directly registering each card results in no way to get the stack other than stupid hacks like checking position * (In addition to simply not working) */ public Goyne_Cardgame() { add(mainPanel); } public static void main(String[] args) { Goyne_Cardgame game = new Goyne_Cardgame(); JPTFrame.createQuickJPTFrame("Goyne_Card Game", game); game.loadCards(); //game.moveStack(1, 0); } public void loadCards() { String cardsURL = "http://www.ccs.neu.edu/jpt/images/jfitz_cards/"; String cardsList = "imagelist.txt"; ImagePaintableLite[] cardImages = WebImageTools.readImagesAsPaintableLite(cardsURL, cardsList); if(cardImages.length < 52) return; for(int i = 0; i < 8; i++) { rowHeaders[i] = new Goyne_Card(75 * i + 10, 100); cardStacks[i] = rowHeaders[i]; } for(int i = 8; i < 12; i++) { rowHeaders[i] = new Goyne_Card(71 * i + 10, 10); rowHeaders[i].setPlay(false); // ick holdPiles[i - 8] = rowHeaders[i]; } for(int i = 12; i < 16; i++) { rowHeaders[i] = new Goyne_Card(71 * i + 400, 10); // should have rowHeaders[i].setPlay(false);, but that's being used for magic in validateMove holdPiles[i - 12] = rowHeaders[i]; } int s = 0, v = 1; for(int i = 0; i < 52; i++) { if(v > 13) { v = 1; s++; } cards[i] = new Goyne_Card(s, v, cardImages[i]); } Collections.shuffle(Arrays.asList(cards)); /* * TODO: Introduce method of controlling shuffling for preset games, etc. */ int currentStack = -1; for(int i = 0; i < 52; i++) { if((i < 29 && i % 7 == 0) || (i > 29 && (i - 28) % 6 == 0)) currentStack++; cards[i].setParent(cardStacks[currentStack]); cardStacks[currentStack] = cards[i]; } /* * TODO: Replace this ugliness with CardStack class */ showCards(); } public void showCards() { window.clearSequence(); for (int i = 0; i < 8; i++) { cardStacks[i].draw(window); } window.repaint(); return; } public void moveCard(Goyne_Card source, Integer stack, Integer target) { cardStacks[stack] = source.parent; source.parent = cardStacks[target]; cardStacks[target] = source; } /* * TODO: * Return value magic is stupid * * Introduce checking for suit * Scan for empty stacks, using them to store cards if needed * Condense logic? * * Move to CardStack, and get all actual game logic out of the main class? * Removes need for special code for hold/victory, as they can be subclasses with different validation * Should the game even know they're special? */ public Integer validateMove(Integer source, Integer target) { Goyne_Card cs = cardStacks[source]; Goyne_Card ct = cardStacks[target]; if(ct.getValue() == 0) return 0; if(!ct.parent.getPlay()) // safe due to that value is 0 on parentless cards return -1; // There's already a card in the targeted holding stack for(int i = 0; cs.getValue() != 0; cs = cs.parent, i++) { if(cs.getValue() == ct.getValue() - 1) return i; if(cs.getValue() != cs.parent.getValue() - 1) return -1; } return -1; } public boolean validateVictoryMove(Integer source, Integer target) { if(cardStacks[source].getSuit() != target - 12) // Wrong suit return false; if(cardStacks[target].getValue() + 1 != cardStacks[source].getValue()) // Not the next card return false; return true; } /* TODO: * Needs a way to check if the target stack is a holding stack, and if so mark it as used * Fails miserably on victory stacks, as does validate -- somewhat fixed */ public boolean moveStack(Integer source, Integer target) { if(target > 11) { // i.e. victory stack if(validateVictoryMove(source, target)) { moveCard(cardStacks[source], source, target); return true; } else return false; } Integer moveCount = validateMove(source, target); if(moveCount > pileCount || moveCount == -1) return false; Goyne_Card ct = cardStacks[source]; while(moveCount > 0) // This is stupid. Merge this method with moveCard and make it so that so that holding stacks/victory piles work with it ct = ct.parent; moveCard(ct, source, target); return true; } /* * Victory Piles: * Hide top card, then move card there. * Cards under the top do not matter due to lack of ability to move them down. */ /* * Holding Spots: * Just a normal stack with a size limit of one * Stack size limit should be controlled by CardStack should it exist */ /* * Click effector: * Click triggers on card -> sets card's stack as active * Next click on card results in deselect or validateMove/moveStack * Implement in CardStack? */ }