0

I am making a simple card game and I'm trying to use my file paths to .jpg files for card images. I am getting a NullPointerException, but I am new to Java and struggling to understand what exactly this means and what to look for.

This is my output:

Tie.
error in nextCard
Computer wins!
error in nextCard
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at War.getPlayerCard(War.java:160)
    at WarGUI$PlayCardListener.actionPerformed(WarGUI.java:98)

I have traced it thus far:

War class:

public String getPlayerCard()
{
   return playerWarCard.getFilepath();  // Error
}

called from WarGUI:

playerCard = new ImageIcon(game.getPlayerCard()); // Error

I have a feeling the problem is my getFilepath method in my Card class (marked at the bottom), but I'm unsure and so would appreciate if someone could confirm.

Card Class:

public class Card 
{      
   // Suits
   private int suit;                           
   public final static int SPADES = 1;
   public final static int HEARTS = 2;
   public final static int DIAMONDS = 3;
   public final static int CLUBS = 4;

   // Ranks
   private int rank; 
   public final static int JACK = 11;       
   public final static int QUEEN = 12;       
   public final static int KING = 13;
   public final static int ACE = 14; 

   String cardFilepath;                             

   /**
    The constructor initializes the card's rank and suit.
    @param rank
    @param suit
   */

   public Card(int rank, int suit) 
   {
      this.rank = rank;
      this.suit = suit;     
      cardFilepath = "cardpics/" + suit + rank + ".jpg";
   }

   /**
    The other constructor initializes the card's rank and suit.
    @param otherCard to be copied
   */ 

   public Card(Card otherCard) 
   {
      this.rank = otherCard.rank;
      this.suit = otherCard.suit;
   }

   /**
    The getRank method returns the int that represents the card's rank.
    @return card's rank
   */

   public int getSuit() 
   {
      return suit;
   }

   /**
    The getRank method returns the int that represents the card's rank.
    @return card's rank
   */

   public int getRank() 
   {
      return rank;
   }

   /**
   * Returns a description of this card.
   * @return the name of the card.
   */

    public String toString() 
    {
        return getRankAsString() + " of " + getSuitAsString();
    }

   /**
    The equals method compares the rank of the card to the rank of
    another card. If they are the same, the method returns true.
    @return boolean
   */

   public boolean equals(Card otherCard ) 
   {
      return rank == otherCard.rank;
   }

   /**
    The getSuitString method returns the card's suit as a string.
    @return suitString
   */

   public String getSuitAsString() 
   {
      switch (suit)
      {
         case SPADES:   return "Spades";
         case HEARTS:   return "Hearts";
         case DIAMONDS: return "Diamonds";
         case CLUBS:    return "Clubs";
         default:       return "Invalid";
      }
   }

   /**
    The getRankString method returns the card's rank.
    @return rank
   */

   public String getRankAsString() 
   {
      switch (rank) 
      {
         case 2:    return "2";
         case 3:    return "3";
         case 4:    return "4";
         case 5:    return "5";
         case 6:    return "6";
         case 7:    return "7";
         case 8:    return "8";
         case 9:    return "9";
         case 10:   return "10";
         case 11:   return "Jack";
         case 12:   return "Queen";
         case 13:   return "King";
         case 14:   return "Ace";
         default:   return "??";
      }
   }

   /**
    Returns the .jpg image of card
    @return path to image
   */

   public String getFilepath()     // Error?
   {
       return cardFilepath;
   }
}

Attached for reference is my War class:

import java.util.ArrayList;
import javax.swing.*;

public class War
{
   static Cardpile warPile;
   static Cardpile player1 = new Cardpile();
   static Cardpile player2 = new Cardpile();

   static Card unseenPlayerCard;
   static Card unseenComputerCard;
   static Card playerWarCard;
   static Card computerWarCard;

   static String war = "false";

   /**
    Constructor prepares, shuffles deck then deals to players.
   */

   public void War() 
   {
      Deck deck = new Deck();
      deck.shuffle();

      while(deck.getSize() > 0)
      {
         player1.collectCard(deck.deal());
         player2.collectCard(deck.deal());
      }
   }

   /**
    The compareCards method compares rank of card to determine winner
    @param playersCard, computersCard
    @return outcome
   */

   public static int compareCards(Card playersCard, Card computersCard)
   {
       if (playersCard.getRank() > computersCard.getRank())
            {
              player1.collectCard(playersCard);
              player1.collectCard(computersCard);

              System.out.println("Player's card: " + playersCard.toString() + "\nComputer's card: " + 
                                 computersCard.toString() + "\nYou win!");

              return 1;
            }

            else if (playersCard.getRank() < computersCard.getRank())
            {
              player2.collectCard(playersCard);
              player2.collectCard(computersCard);

              System.out.println("Your card: " + playersCard.toString() + "\nComputer's card: " + 
                                 computersCard.toString() + "\nYou lose.");

              return 2;
            }

            // If cards are equal, war
            else
            {
                war = "true";
                System.out.println("Your card: " + playersCard.toString());
                System.out.println("Computer's card: " + computersCard.toString());
                JOptionPane.showMessageDialog(null, "War!");
                beginWar(playersCard, computersCard);
                return 3;
            }
   }

   /**
    The beginWar method draws war cards, then compares to determine
    the winner of the war.
    @param playersCard, computersCard
   */

   public static void beginWar(Card playersCard, Card computersCard)
   {     
       // Prize cards 
       unseenPlayerCard = player1.playCard();
       unseenComputerCard = player2.playCard();

       // Add cards to winning pile
       warPile.collectCard(playersCard);
       warPile.collectCard(computersCard);
       warPile.collectCard(unseenPlayerCard);
       warPile.collectCard(unseenComputerCard);

       // Determine winner
       playerWarCard = player1.playCard();
       computerWarCard = player2.playCard();

       int outcome = compareCards(playerWarCard, computerWarCard);

       if (outcome == '1')
       {
           System.out.println("You win the war!");
       }

       if (outcome == '2')
       {
           System.out.println("You lose the war.");
       }
   }

   /**
    The computerCardsLeft method returns the number of cards in
    the computer's hand.
    @return computer hand size
   */

   public int computerCardsLeft()
   {
       return player2.getSize();
   }

   /**
    The playerCardsLeft method returns the number of cards in
    the players's hand.
    @return player hand size
   */

   public int playerCardsLeft()
   {
       return player1.getSize();
   }

   /**
    The getComputerCard method returns the image path of
    the computer's card for the GUI.
    @return filepath
   */

   public String getComputerCard()
   {
       return computerWarCard.getFilepath();
   }

   /**
    The getPlayerCard method returns the image path of
    the computer's card for the GUI.
    @return filepath
   */

   public String getPlayerCard() 
   {
       return playerWarCard.getFilepath();       // Error
   }

   /**
    The playerDraw method draws the next card in the player's pile.
    @return card
   */

   public Card playerDraw()
   {
       if (player1.getSize() < 1)  
       {
          endGame();
       }
       return player1.nextCard(); 
   }

   /**
    The computerDraw method draws the next card in the computer's pile.
   */

   public Card computerDraw()
   {   
       if (player2.getSize() < 1)
       {
          endGame();
       }

       return player2.playCard();
   }

   /**
    The endGame method displays the results.
   */

   public void endGame()
   {
        if (player1.getSize() > player2.getSize())
              System.out.println("Player wins!");
        else if (player2.getSize() > player1.getSize())
              System.out.println("Computer wins!");
        else
              System.out.println("Tie.");
   }

   /**
    The enoughCards method determins whether or not a player meets a minimum
    card requirement.
   */

   public static boolean enoughCards(int n)
   {
      if (player1.getSize() < n || player2.getSize() < n)
      {
         return false;
      }   
      return true;
   }  
}

...and my WarGUI

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class WarGUI extends JFrame
{  
   private WarGUI guiGame;    
   private War game;                                                                         

   private JPanel rightPlayerPanel;           // Player                   
   private JPanel leftPlayerPanel;            // Computer
   private JPanel buttonPanel;                // Holds buttons                  
   private JPanel gamePanel;                  // Main deck area

   private JButton playButton;       

   private static JLabel backLabelLeft;                       
   private static JLabel playerCardLabel;                          
   private static JLabel computerCardLabel; 

   private ImageIcon back;                    // Icon for backside of card
   private ImageIcon blank;                   // Place holder
   private static ImageIcon playerCard;              // Player 1's current card
   private static ImageIcon computerCard;            // Player 2's current card

   private JTextField playerCardsLeft;
   private JTextField computerCardsLeft;

//    static Hand player1;
//    static Hand player2;

   private Card playersCard;
   Card computersCard;

   private String war = "false";  
   String imagePath = "cardPics/back.jpg";                              

   /**
    This constructor builds & adds panels to contentpane.
   */

   public WarGUI()
   {
      // Set contentPane
      setLayout(new BorderLayout());
      setTitle("Game of War");
      setSize(1100, 550);
      setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      setLocationRelativeTo(null);

      // Build & add deck panel
      assembleGamePanel();
      add(gamePanel, BorderLayout.CENTER);      

      // Build & add player panels
      assembleDecksPanel();
      add(leftPlayerPanel, BorderLayout.WEST);
      add(rightPlayerPanel, BorderLayout.EAST);

      // Build & add button panel
      assembleButtonPanel();
      add(buttonPanel, BorderLayout.SOUTH);

      setVisible(true);

      // Prepare deck & Player hands
      game = new War();  

      // //Welcome message
//        JOptionPane.showMessageDialog(null, "Welcome!");
   }

   /**
    The PlayCardListener tracks clicks on Play Card button. Cards are drawn, war status is checked, scores and images are adjusted.
   */

   private class PlayCardListener implements ActionListener
   {
      public void actionPerformed(ActionEvent e)
      {
         // Regular gameplay
         if (war.equals("false"))
         {
            Card playersCard = game.playerDraw();    
            Card computersCard = game.computerDraw(); 


            // Update card images
            playerCard = new ImageIcon(game.getPlayerCard());    // Error
            playerCardLabel.setIcon(playerCard);


            computerCard = new ImageIcon(computersCard.getFilepath());
            computerCardLabel.setIcon(computerCard);

            // Compare
            game.compareCards(playersCard, computersCard);

                        // // Otherwise, update score 
//             //if (!war.equals("true"))
//             else
//             {
//                 // playerCardsLeft.setText("Player's Cards: " + (player1.getSize() - 1));
// //                 computerCardsLeft.setText("Computer's Cards: " + (player2.getSize() - 1));
// 
//             }
            playerCardsLeft.setText("Player's Cards: " + (game.playerCardsLeft() - 1));
            computerCardsLeft.setText("Computer's Cards: " + (game.computerCardsLeft() - 1));
          }

         // War deckplay
         // Second click - face down card
         else if (war.equals("true"))
         {
            // Set icons to card backside
            playerCardLabel.setIcon(back);
            computerCardLabel.setIcon(back);

            war = "last";
         }   

         // Third click
         else if (war.equals("last"))
         {
            // Identify cards involved in the war, update icons
            computerCard = new ImageIcon(game.getComputerCard());
            computerCardLabel.setIcon(computerCard);

            playerCard = new ImageIcon(game.getPlayerCard());
            playerCardLabel.setIcon(playerCard);

            war = "final";
         }

         // War final
         else if (war.equals("final"))
         {
            war = "false";

            // Update scores
            playerCardsLeft.setText("Player's Cards: " + (game.playerCardsLeft()));
            computerCardsLeft.setText("Computer's Cards: " + (game.computerCardsLeft()));
         }
         else
            System.out.println("ERROR");
      }
   }

   /**
    The assembleGamePanel builds the cardPanel - the main deck area, where cards are displayed.
   */

   private void assembleGamePanel()
   {
      // Place holder for cards
      blank = new ImageIcon();
      playerCardLabel = new JLabel(blank);
      computerCardLabel = new JLabel(blank);

      // Add labels to cardPanel 
      gamePanel = new JPanel();
      gamePanel.add(playerCardLabel);
      gamePanel.add(computerCardLabel);
      gamePanel.setPreferredSize(new Dimension(545, 540));
      gamePanel.setBackground(new Color(0, 64, 0));
   }

   /**
    The assembleDecksPanel method builds the panel that displays the players' cardpiles.
   */

   private void assembleDecksPanel()
   {
      // Icons of card backside
      back = new ImageIcon(imagePath);

      // Add icons
      backLabelLeft = new JLabel();
      backLabelLeft.setIcon(back);
      JLabel backLabelRight = new JLabel();
      backLabelRight.setIcon(back);

      // Add labels to panels
      // Right
      rightPlayerPanel = new JPanel();
      rightPlayerPanel.setPreferredSize(new Dimension(150,220));
      rightPlayerPanel.add(backLabelRight);
      rightPlayerPanel.setBackground(new Color(0, 64, 0));
      playerCardsLeft = new JTextField("Player's Cards: 26", 13);
      playerCardsLeft.setEditable(false);
      rightPlayerPanel.add(playerCardsLeft);

      // Left 
      leftPlayerPanel = new JPanel();
      leftPlayerPanel.setPreferredSize(new Dimension(150,220));
      leftPlayerPanel.add(backLabelLeft);
      leftPlayerPanel.setBackground(new Color(0, 64, 0));
      computerCardsLeft = new JTextField("Computer's Cards: 26", 13); 
      computerCardsLeft.setEditable(false);
      leftPlayerPanel.add(computerCardsLeft);

   }

   /**
    The assembleButtonPanel method adds buttons to button panel.
   */

   private void assembleButtonPanel()
   {
      // Create & add button
      JButton playCardButton = new JButton("Play!");
      playCardButton.setPreferredSize(new Dimension(150,80));
      buttonPanel = new JPanel();
      buttonPanel.add(playCardButton);
      buttonPanel.setBackground(new Color(0, 64, 0));

      // Add event listeners for the buttons.
      playCardButton.addActionListener(new PlayCardListener());
   }     

   /**
    The main method begins the GUI deck.
   */

   public static void main(String[] args) 
   {
       WarGUI guiGame = new WarGUI();
   } 
}

Edit: I now understand there is a problem somewhere else. as such, I will post my other classes...

Cardpile

public class Cardpile
{
   // Create an array to hold the player's pile, and parameters for that array. 
   private Card[] cardPile;
   private int front;
   private int end;

   /**
    Constructor creates an empty pile capable of holding 52 cards.
   */

   public Cardpile()
   {
      cardPile = new Card[52];
      front = 0; 
      end = 0;
   }

   /**
    The nextCard method returns the card at the front of the pile.
    @return c
   */

   public Card nextCard()
   {
      if (front == end)
      {
         System.out.println("error in nextCard");
      }

      Card c = cardPile[front];
      front++;
      return c;   
   }

   /**
    The collectCard method adds a card to the pile.
   */

   public void collectCard(Card c) 
   {
      cardPile[end] = c;
      end++;
   }

   public Card playCard()
   {
      return nextCard();
   }

   /**
    The getSize method returns the size of the pile.
    @return size
   */

   public int getSize()
   {
      int size = end - front;
      return size;
   }

   /**
    The clear method clears the pile of all cards.
   */

   public void clear()
   {
      front = 0;
      end = 0;
   }
}

Deck:

import java.util.*;

public class Deck
{
   private Card[] deck;
   private int numCards;

   /**
    The constructor creates a deck of 52 cards
   */

   public Deck()
   {
      deck = new Card[52];
      fillDeck();
   }

   /**
    The fillDeck method fills the deck with cards.
   */

   public void fillDeck()
   {
      int index = 0;
      for (int q = 1; q <= 13; q++)
      {
         for (int n = 1; n <= 4; n++)
         {
            deck[index] = new Card(q, n);
            index++;
         }
      }
   }

   /**
    The shuffle method shuffles the deck.
   */

   public void shuffle()
   {
      for (int sh = 0; sh < numCards - 1; sh++)
      {
         int r = myRandom(sh, numCards - 1);
         Card shuffleCard = deck[sh];
         deck[sh] = deck[r];
         deck[r] = shuffleCard;
      }
   }

   /**
    The deal method deals to the players.
    @return updated deck
   */

   public Card deal()
   {
      if(numCards == 0)
      {
         return null;
      }
      numCards--;        
      return deck[numCards];     
   }

   /**
    The getSize method returns the size of the deck
    @return numCards in deck
   */

   public int getSize()
   {
      return numCards;
   }

   /**
    The myRandom method returns a random number.
    @return random number
   */

   private static int myRandom(int low, int high)
   {
      int random = (int)((high + 1 - low) * Math.random() + low);
      return random;
   }
}
  • please post the exact stacktrace – Manuel Jain Apr 29 '15 at 06:16
  • `ImageIcon(String)` expects that the image will be located on the disk somewhere. Where are the images in relationship to the program/source? – MadProgrammer Apr 29 '15 at 06:25
  • MadProgrammer - the images are in the source folder along with my classes. Manuel - it has been posted! – rotational_torque_girl Apr 29 '15 at 06:31
  • From which directory do you execute your java program? I.e. what is the "current" directory, from which the relative file paths are resolved? If the goal is to embed your images in the program itself (i.e. in the generated jar file), you should use `Class.getResource()` to load the images: `new ImageIcon(MyClass.class.getResource("/cardspic/12.jpg"))` – JB Nizet Apr 29 '15 at 06:34
  • JB I am not confident I understood your question but I think my answer is that it is being run from a GitHub directory? Does that make sense? My goal is to embed the images in the program, but I didn't follow your comment at all. Could you (or someone) point me to a helpful reading on the matter? – rotational_torque_girl Apr 29 '15 at 06:42
  • To me it looks like playerWarCard is null as the exception is thrown in War.java:160. Try to debug the code to see if there is a valid Card object behind that variable. – Luke Apr 29 '15 at 06:55
  • @rotational_torque_girl Hi, are you mistakenly this code `new ImageIcon(game.getPlayerCard());` with this code `new ImageIcon(playersCard.getFilepath());`? – kucing_terbang Apr 29 '15 at 06:58
  • Luke: I should probably mention that I can't debug on my laptop and no one in the comp sci department at my university can figure out why. As such, I don't even know how to debug code. That being said, I had managed to identify that line of code as being a problem. Is it even possible for me to figure this out without debugging?? – rotational_torque_girl Apr 29 '15 at 07:02
  • kucing_terbang: I actually spent a considerable amount of time before posting this question substituting code for that line in order to identify the problem - including the line you suggested. It didn't change anything, leading me to believe it was the getFilepath method – rotational_torque_girl Apr 29 '15 at 07:04
  • I debugging doesn't work, try with console output: public String getPlayerCard() { System.out.println("playerWarCard is null: "+playerWarCard==null"); return playerWarCard.getFilepath(); // Error } – Luke Apr 29 '15 at 10:23

2 Answers2

0

You have two constructors:

public Card(int rank, int suit) 
   {
      this.rank = rank;
      this.suit = suit;     
      cardFilepath = "cardpics/" + suit + rank + ".jpg";
   }

   /**
    The other constructor initializes the card's rank and suit.
    @param otherCard to be copied
   */ 

   public Card(Card otherCard) 
   {
      this.rank = otherCard.rank;
      this.suit = otherCard.suit;
   }

If the card is instantiated with a rank and suite, you also set the cardFilepath. If you instantiate using an otherCard you never set the cardFilepath, meaning for that instance no String is created and the cardFilepath = null.

JohannisK
  • 535
  • 2
  • 10
0

i think this should be

public Card(Card otherCard) {
  this.rank = otherCard.getRank;
  this.suit = otherCard.getSuit;
  cardFilepath = "cardpics/" + suit + rank + ".jpg";
}