package com.josesandoval.magic; import java.io.*; import java.applet.*; import java.awt.*; import java.awt.event.*; /** * Implemets card trick with 21 cards. * * This trick was tought to me by my father when I was a little kid. * * * The trick goes: * * 1. Get 21 distinct cards out of regular deck of playing cards. * 2. Get user to pick a card (You don't need to see or know which card). * 3. Deal cards into 3 piles of 7 and have user select the pile the card is that he/she has picked. * 4. Repeat 3 times. * 5. The card picked, will always be the 11th card. * * * The trick depends on a bit of mathematics, * hence, there should be a rigorous proof as to why it works every time. Of course, as a 10 year old, * I could never understand how the trick worked. So, magical powers was a reasonable explanation :) * * * Maybe you know a proof. As for me, I haven't spend any time trying to prove it. Perhaps in the future. * * * Check back at http://www.josesandoval.com/software/cards/. * * * All code and algorithms have been done entirely by me. The deck image I downloaded from somewhere * in the Web (Sorry, I can't remember where). If you know the origins of the trick, let me know also. * * * You can use and modify the code, as long as you keep this copyright, and let me know (via email) that you * are using the code. Needles, to say that the code comes without any type of warranty and you can use it at * your own risk. * * (c) Copyright Jose Sandoval 2003. * * Creation date: (25/12/2002 3:48:36 PM) * @author: Jose Sandoval - jose@josesandoval.com - http://www.josesandoval.com/ */ public class MagicTrick extends Applet { Image[] cardImages; private Image deckImage; private Panel ivjPanelCards = null; private Panel ivjPanelMenu = null; IvjEventHandler ivjEventHandler = new IvjEventHandler(); private Button ivjButtonPile1 = null; private Button ivjButtonPile2 = null; private Button ivjButtonPile3 = null; private Panel ivjPanelBegin = null; private FlowLayout ivjPanelBeginFlowLayout = null; private Deck deck; private com.josesandoval.magic.Card[] playCards; private com.josesandoval.magic.Card[] pile1; private com.josesandoval.magic.Card[] pile2; private com.josesandoval.magic.Card[] pile3; private java.util.Hashtable cardTable; private int countShuffles; private final static int xBegin = 10; private final static int yBegin = 10; private final static int cardWidth = 73; private final static int cardHeight = 107; private Button ivjButtonStart = null; private java.awt.Image backCard; class IvjEventHandler implements java.awt.event.ActionListener { public void actionPerformed(java.awt.event.ActionEvent e) { if (e.getSource() == MagicTrick.this.getButtonPile1()) connEtoC2(e); if (e.getSource() == MagicTrick.this.getButtonPile2()) connEtoC3(e); if (e.getSource() == MagicTrick.this.getButtonPile3()) connEtoC4(e); if (e.getSource() == MagicTrick.this.getButtonStart()) connEtoC5(e); }; }; private java.awt.Image offScreenBuffer; /** * Pile1 button clicked. */ public void buttonPile1_ActionPerformed(java.awt.event.ActionEvent actionEvent) { doSelectPile1(); doDisplayPiles(getPanelCards().getGraphics()); doCheckCountShuffles(); } /** * Pile2 button clicked. */ public void buttonPile2_ActionPerformed(java.awt.event.ActionEvent actionEvent) { doSelectPile2(); doDisplayPiles(getPanelCards().getGraphics()); doCheckCountShuffles(); } /** * Pile3 button clicked. */ public void buttonPile3_ActionPerformed(java.awt.event.ActionEvent actionEvent) { doSelectPile3(); doDisplayPiles(getPanelCards().getGraphics()); doCheckCountShuffles(); } /** * Start button clicked. */ public void buttonStart_ActionPerformed(java.awt.event.ActionEvent actionEvent) { doResetToDeal(); doDisplayPiles(getPanelCards().getGraphics()); getButtonStart().setEnabled(false); getButtonPile1().setEnabled(true); getButtonPile2().setEnabled(true); getButtonPile3().setEnabled(true); doDisplayStatus(getPanelCards().getGraphics(), "Pick a card and click the button beside the pile it is in."); } /** * connEtoC2: (ButtonPile1.action.actionPerformed(java.awt.event.ActionEvent) --> MagicTrick.buttonPile1_ActionPerformed(Ljava.awt.event.ActionEvent;)V) * @param arg1 java.awt.event.ActionEvent */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private void connEtoC2(java.awt.event.ActionEvent arg1) { try { // user code begin {1} countShuffles++; // user code end this.buttonPile1_ActionPerformed(arg1); // user code begin {2} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {3} // user code end handleException(ivjExc); } } /** * connEtoC3: (ButtonPile2.action.actionPerformed(java.awt.event.ActionEvent) --> MagicTrick.buttonPile2_ActionPerformed(Ljava.awt.event.ActionEvent;)V) * @param arg1 java.awt.event.ActionEvent */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private void connEtoC3(java.awt.event.ActionEvent arg1) { try { // user code begin {1} countShuffles++; // user code end this.buttonPile2_ActionPerformed(arg1); // user code begin {2} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {3} // user code end handleException(ivjExc); } } /** * connEtoC4: (ButtonPile3.action.actionPerformed(java.awt.event.ActionEvent) --> MagicTrick.buttonPile3_ActionPerformed(Ljava.awt.event.ActionEvent;)V) * @param arg1 java.awt.event.ActionEvent */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private void connEtoC4(java.awt.event.ActionEvent arg1) { try { // user code begin {1} countShuffles++; // user code end this.buttonPile3_ActionPerformed(arg1); // user code begin {2} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {3} // user code end handleException(ivjExc); } } /** * connEtoC5: (ButtonStart.action.actionPerformed(java.awt.event.ActionEvent) --> MagicTrick.buttonStart_ActionPerformed(Ljava.awt.event.ActionEvent;)V) * @param arg1 java.awt.event.ActionEvent */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private void connEtoC5(java.awt.event.ActionEvent arg1) { try { // user code begin {1} // user code end this.buttonStart_ActionPerformed(arg1); // user code begin {2} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {3} // user code end handleException(ivjExc); } } /** * Check if dealing of 21 cards has reached 3. * Creation date: (29/12/2002 4:56:49 PM) * @author: Jose Sandoval */ private void doCheckCountShuffles() { if (countShuffles == 3) { // Reset countShuffles = 0; doDisplayAllBack(getPanelCards().getGraphics()); doDisplayChoosenCard(getPanelCards().getGraphics()); doDisplayStatus(getPanelCards().getGraphics(), "This is the card you picked."); getButtonStart().setEnabled(true); getButtonPile1().setEnabled(false); getButtonPile2().setEnabled(false); getButtonPile3().setEnabled(false); initTrick(); } else { doDisplayStatus(getPanelCards().getGraphics(), "Which pile is your card in?"); } } /** * Display deck the back of 21. * Creation date: (29/12/2002 5:34:25 PM) * @author: Jose Sandoval */ private void doDisplayAllBack(Graphics g) { g.clearRect(0, 0, getPanelCards().getSize().width, getPanelCards().getSize().height); for (int i = 0; i < 7; i++) { g.drawImage(backCard, xBegin + (cardWidth * i), yBegin + (cardHeight * 0), null); // row 1 g.drawImage(backCard, xBegin + (cardWidth * i), yBegin + (cardHeight * 1), null); // row 2 g.drawImage(backCard, xBegin + (cardWidth * i), yBegin + (cardHeight * 2), null); // row 3 } } /** * Display picked card. * Creation date: (29/12/2002 5:41:01 PM) * @author: Jose Sandoval * @param g java.awt.Graphics */ private void doDisplayChoosenCard(Graphics g) { g.drawImage((Image) cardTable.get("" + playCards[10].getSuit() + "_" + playCards[10].getValue()), xBegin, yBegin, null); // row 1 } /** * Display intro. * Creation date: (25/12/2002 7:57:40 PM) * @author: Jose Sandoval * @param g java.awt.Graphics */ private void doDisplayIntro(Graphics g) { //g.drawImage(deckImage, 0, 0, null); //g.drawString("Jose Sandoval", 10, 10); } /** * Display the piles. * Creation date: (29/12/2002 1:22:44 PM) * @author: Jose Sandoval * @param g java.awt.Graphics */ private void doDisplayPiles(Graphics g) { // Clear screen g.clearRect(0, 0, getPanelCards().getSize().width, getPanelCards().getSize().height); // Card images are stored in hashtable for (int i = 0; i < 7; i++) { g.drawImage((Image) cardTable.get("" + pile1[i].getSuit() + "_" + pile1[i].getValue()), xBegin + (cardWidth * i), yBegin + (cardHeight * 0), null); // row 1 g.drawImage((Image) cardTable.get("" + pile2[i].getSuit() + "_" + pile2[i].getValue()), xBegin + (cardWidth * i), yBegin + (cardHeight * 1), null); // row 2 g.drawImage((Image) cardTable.get("" + pile3[i].getSuit() + "_" + pile3[i].getValue()), xBegin + (cardWidth * i), yBegin + (cardHeight * 2), null); // row 3 } } /** * Display status. * Creation date: (29/12/2002 6:25:08 PM) * @author: Jose Sandoval * @param g java.awt.Graphics * @param status java.lang.String */ private void doDisplayStatus(Graphics g, String status) { g.setFont(new java.awt.Font("Helvetica", java.awt.Font.BOLD, 16)); g.setColor(java.awt.Color.orange); g.drawString(status, 40, 360); } /** * Reset card into a pile of 21 to be dealt. * Creation date: (29/12/2002 3:57:25 PM) * @author: Jose Sandoval */ private void doResetToDeal() { // Get cards for (int i = 0; i < 7; i++) { playCards[i] = pile1[i]; playCards[i + 7] = pile2[i]; playCards[i + 14] = pile3[i]; } // Deal from the top int counter1 = 0; int counter2 = 0; int counter3 = 0; int switchFlag = 0; for (int i = playCards.length - 1; i >= 0; i--) { // Order is reversed switch ((i + 1) % 3) { case 0 : pile1[counter1] = playCards[i]; counter1++; break; case 1 : pile3[counter2] = playCards[i]; counter2++; break; case 2 : pile2[counter3] = playCards[i]; counter3++; break; } } } /** * Select pile 1. * Creation date: (29/12/2002 2:27:00 PM) * @author: Jose Sandoval */ private void doSelectPile1() { // resetPlayCards(); //for (int i = 0; i < 21; i++) { //playCards[i] = pile1[i]; //playCards[i + 7] = pile2[i]; //playCards[i + 14] = pile3[i]; //} Card tmpPile[] = new Card[7]; tmpPile = pile1; pile1 = pile2; pile2 = tmpPile; doResetToDeal(); } /** * Select pile 2. * Creation date: (29/12/2002 2:27:17 PM) * @author: Jose Sandoval */ private void doSelectPile2() { doResetToDeal(); } /** * Select pile 3. * Creation date: (29/12/2002 2:27:31 PM) * @author: Jose Sandoval */ private void doSelectPile3() { Card tmpPile[] = new Card[7]; tmpPile = pile2; pile2 = pile3; pile3 = tmpPile; doResetToDeal(); } /** * Returns information about this applet. * @return a string of information about this applet */ public String getAppletInfo() { return "MagicTrick\n" + "\n" + "This trick was taught to me, when I was around 10 years old, by my father.\n" + "Creation date: (25/12/2002 3:47:30 PM)\n" + "@author: Jose Sandoval\n" + ""; } /** * Return the Button2 property value. * @return java.awt.Button */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private java.awt.Button getButtonPile1() { if (ivjButtonPile1 == null) { try { ivjButtonPile1 = new java.awt.Button(); ivjButtonPile1.setName("ButtonPile1"); ivjButtonPile1.setBounds(540, 50, 45, 23); ivjButtonPile1.setEnabled(false); ivjButtonPile1.setLabel("Pile 1"); // user code begin {1} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {2} // user code end handleException(ivjExc); } } return ivjButtonPile1; } /** * Return the Button3 property value. * @return java.awt.Button */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private java.awt.Button getButtonPile2() { if (ivjButtonPile2 == null) { try { ivjButtonPile2 = new java.awt.Button(); ivjButtonPile2.setName("ButtonPile2"); ivjButtonPile2.setBounds(540, 155, 45, 23); ivjButtonPile2.setEnabled(false); ivjButtonPile2.setLabel("Pile 2"); // user code begin {1} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {2} // user code end handleException(ivjExc); } } return ivjButtonPile2; } /** * Return the ButtonPile3 property value. * @return java.awt.Button */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private java.awt.Button getButtonPile3() { if (ivjButtonPile3 == null) { try { ivjButtonPile3 = new java.awt.Button(); ivjButtonPile3.setName("ButtonPile3"); ivjButtonPile3.setBounds(540, 260, 45, 23); ivjButtonPile3.setEnabled(false); ivjButtonPile3.setLabel("Pile 3"); // user code begin {1} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {2} // user code end handleException(ivjExc); } } return ivjButtonPile3; } /** * Return the ButtonStart property value. * @return java.awt.Button */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private java.awt.Button getButtonStart() { if (ivjButtonStart == null) { try { ivjButtonStart = new java.awt.Button(); ivjButtonStart.setName("ButtonStart"); ivjButtonStart.setLabel("Play Game"); // user code begin {1} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {2} // user code end handleException(ivjExc); } } return ivjButtonStart; } /** * Return the PanelBegin property value. * @return java.awt.Panel */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private java.awt.Panel getPanelBegin() { if (ivjPanelBegin == null) { try { ivjPanelBegin = new java.awt.Panel(); ivjPanelBegin.setName("PanelBegin"); ivjPanelBegin.setLayout(getPanelBeginFlowLayout()); ivjPanelBegin.setBackground(java.awt.Color.gray); getPanelBegin().add(getButtonStart(), getButtonStart().getName()); // user code begin {1} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {2} // user code end handleException(ivjExc); } } return ivjPanelBegin; } /** * Return the PanelBeginFlowLayout property value. * @return java.awt.FlowLayout */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private java.awt.FlowLayout getPanelBeginFlowLayout() { java.awt.FlowLayout ivjPanelBeginFlowLayout = null; try { /* Create part */ ivjPanelBeginFlowLayout = new java.awt.FlowLayout(); ivjPanelBeginFlowLayout.setAlignment(java.awt.FlowLayout.RIGHT); } catch (java.lang.Throwable ivjExc) { handleException(ivjExc); }; return ivjPanelBeginFlowLayout; } /** * Return the PanelCards property value. * @return java.awt.Panel */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private java.awt.Panel getPanelCards() { if (ivjPanelCards == null) { try { ivjPanelCards = new java.awt.Panel(); ivjPanelCards.setName("PanelCards"); ivjPanelCards.setLayout(null); ivjPanelCards.setBackground(new java.awt.Color(25, 105, 18)); getPanelCards().add(getButtonPile1(), getButtonPile1().getName()); getPanelCards().add(getButtonPile2(), getButtonPile2().getName()); getPanelCards().add(getButtonPile3(), getButtonPile3().getName()); // user code begin {1} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {2} // user code end handleException(ivjExc); } } return ivjPanelCards; } /** * Return the PanelMenu property value. * @return java.awt.Panel */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private java.awt.Panel getPanelMenu() { if (ivjPanelMenu == null) { try { ivjPanelMenu = new java.awt.Panel(); ivjPanelMenu.setName("PanelMenu"); ivjPanelMenu.setLayout(new java.awt.GridBagLayout()); java.awt.GridBagConstraints constraintsPanelBegin = new java.awt.GridBagConstraints(); constraintsPanelBegin.gridx = 0; constraintsPanelBegin.gridy = 0; constraintsPanelBegin.fill = java.awt.GridBagConstraints.HORIZONTAL; constraintsPanelBegin.anchor = java.awt.GridBagConstraints.EAST; constraintsPanelBegin.weightx = 1.0; constraintsPanelBegin.weighty = 1.0; getPanelMenu().add(getPanelBegin(), constraintsPanelBegin); // user code begin {1} // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {2} // user code end handleException(ivjExc); } } return ivjPanelMenu; } /** * Called whenever the part throws an exception. * @param exception java.lang.Throwable */ private void handleException(java.lang.Throwable exception) { /* Uncomment the following lines to print uncaught exceptions to stdout */ // System.out.println("--------- UNCAUGHT EXCEPTION ---------"); // exception.printStackTrace(System.out); } /** * Initializes the applet. */ public void init() { try { super.init(); setName("MagicTrick"); setLayout(new java.awt.BorderLayout()); setSize(600, 420); add(getPanelCards(), "Center"); add(getPanelMenu(), "South"); initConnections(); // user code begin {1} MediaTracker tracker = new MediaTracker(this); playCards = new Card[21]; pile1 = new Card[7]; pile2 = new Card[7]; pile3 = new Card[7]; deck = new Deck(); initTrick(); // Load cards image Image wholeDeck = getImage(getCodeBase(), "images/cards.gif"); // Image wholeDeck = ImageLoader.getImage("images/cards.gif"); tracker.addImage(wholeDeck, 0); // Wait for image to be loaded try { tracker.waitForID(0); } catch (Exception e) { e.printStackTrace(); } // Load card images using image cropping cardTable = new java.util.Hashtable(); Image tmpImage = null; java.awt.image.CropImageFilter filter = null; int counter = 0; for (int i = 0; i < 4; i++) { // Suits: 0 - 3 for (int j = 1; j <= 13; j++) { // Values: 1 - 13 filter = new java.awt.image.CropImageFilter(cardWidth * j, (cardHeight - 10) * i, cardWidth, cardHeight - 10); tmpImage = createImage(new java.awt.image.FilteredImageSource(wholeDeck.getSource(), filter)); tracker.addImage(tmpImage, ++counter); cardTable.put("" + i + "_" + j, tmpImage); } } // Load deck image // deckImage = getImage(getCodeBase(), "images/deck.jpg"); filter = new java.awt.image.CropImageFilter(0, cardHeight - 10, cardWidth, cardHeight - 10); backCard = createImage(new java.awt.image.FilteredImageSource(wholeDeck.getSource(), filter)); tracker.addImage(backCard, ++counter); // Wait for images to be in the hashtable try { tracker.waitForAll(); } catch (Exception e) { e.printStackTrace(); } // doDisplayIntro(getPanelCards().getGraphics()); // user code end } catch (java.lang.Throwable ivjExc) { // user code begin {2} // user code end handleException(ivjExc); } } /** * Initializes connections * @exception java.lang.Exception The exception description. */ /* WARNING: THIS METHOD WILL BE REGENERATED. */ private void initConnections() throws java.lang.Exception { // user code begin {1} // user code end getButtonPile1().addActionListener(ivjEventHandler); getButtonPile2().addActionListener(ivjEventHandler); getButtonPile3().addActionListener(ivjEventHandler); getButtonStart().addActionListener(ivjEventHandler); } /** * Initialize piles and shuffle same card deck. * Creation date: (29/12/2002 1:08:28 PM) * @author: Jose Sandoval */ private void initTrick() { countShuffles = 0; deck.shuffle(); // Get 3 piles for (int i = 0; i < 7; i++) { pile1[i] = deck.getDeck()[i]; pile2[i] = deck.getDeck()[i + 7]; pile3[i] = deck.getDeck()[i + 14]; } } /** * main entrypoint - starts the part when it is run as an application * @param args java.lang.String[] */ public static void main(java.lang.String[] args) { try { Frame frame = new java.awt.Frame(); MagicTrick aMagicTrick; Class iiCls = Class.forName("com.josesandoval.magic.MagicTrick"); ClassLoader iiClsLoader = iiCls.getClassLoader(); aMagicTrick = (MagicTrick) java.beans.Beans.instantiate(iiClsLoader, "com.josesandoval.magic.MagicTrick"); frame.add("Center", aMagicTrick); frame.setSize(aMagicTrick.getSize()); frame.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); }; }); frame.show(); java.awt.Insets insets = frame.getInsets(); frame.setSize(frame.getWidth() + insets.left + insets.right, frame.getHeight() + insets.top + insets.bottom); frame.setVisible(true); } catch (Throwable exception) { System.err.println("Exception occurred in main() of java.applet.Applet"); exception.printStackTrace(System.out); } } /** * Draws the text on the drawing area. * @param g the specified Graphics window */ public void paint(Graphics g) { paint(g); } /** * Starts up the thread. */ public void start() { // Display intro image // doDisplayIntro(getPanelCards().getGraphics()); } /** * Terminates the thread and leaves it for garbage collection. */ public void stop() { } /** * Override update(). * Creation date: (01/01/2003 3:22:26 PM) * @author: Jose Sandoval * @param g java.awt.Graphics */ public void update(Graphics g) { paint(g); } }