1

I've been working on a basic simulation of the card game Gin Rummy and, although it's incomplete at the moment, it was able to run the basic functions of a deck of cards until I tried to implement a method to deal a hand to each player.

The class Player is supposed to consist of an ArrayList (which holds the cards in each players hands) and an integer (used as a player id). I have declared these as static objects, but of course this means each instance of Player I create now has the same Hand and playerid as the variables are static.

This is the problem I face then. I am lead to believe that any static class or method, can only access other static classes, methods objects etc. As the main method must be static, surely anything it can access has to also be static and so on and so forth? How can the objects in my Player class not be static, and thus allow me to assign each instance of Player a different Hand and playerid?

I have included my code below, my apologies that it's so long, I thought I'd put everything in just in case. For the record, it's the points in the PlayGinRummy class where I call new instances of Player that are throwing up the error non-static variable Hand cannot be referenced from a static context.

package labexercise1;

import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class DeckOfCardsTest {

public DeckOfCardsTest(){}

private static int Menu;

public static void main(String[] args) throws InterruptedException{

    DeckOfCards.FillDeck(); 

    do{
        Thread.sleep(1000);
        System.out.println("Please select from the following menu options using the corresponding number:");
        System.out.println("1. Display Deck | 2. Shuffle Deck | 3. Cut Deck | 4. Start Game | 5. Exit"); //Start game will lead into another switch menu to set no of players etc.
        System.out.print("Your choice: ");
        Scanner UserInput = new Scanner(System.in);
        System.out.println();
        Menu = UserInput.nextInt(); // Maybe build in a system that recognises, for example, "1", "one" and "One" as the menu selection 1, using if/else
        System.out.println();

        switch(Menu){
            case 1:
                DeckOfCards.DisplayDeck();
                break;

            case 2:
                DeckOfCards.ShuffleDeck();
                break;

            case 3:
                DeckOfCards.CutDeck();
                break;

            case 4:
                PlayGinRummy.DealDeck(); // Maybe shuffle things around so this just calls a method in player, from which everything else is called. Would mean moving things over from DeckOfCards so Player had access to hp, cp1, cp2 and cp3.
                break;

            case 5: 
                System.out.println("The program will now end.");
                System.out.println();
                break;

            default: 
                System.out.println("Your input is not a valid selection.");
                System.out.println();
                break;
        }
    } while(Menu!=5);
}

public class DeckOfCards {

    public DeckOfCards(){}

    public static ArrayList<Integer> Deck = new ArrayList<>(); 
    public static ArrayList<Integer> Discard = new ArrayList<>();

    public static void FillDeck() throws InterruptedException{
        System.out.print("Compiling deck");
        DeckOfCards.CountdownEffect();
        for(int count=0; count<52; count++){
            Deck.add(count);
        }
        System.out.println(" Deck compiled!");
        System.out.println();
    }   

    public static void DisplayDeck() throws InterruptedException{
        System.out.println("Displaying deck contents:");
        Thread.sleep(1000);
        for(int count=0; count<52; count++){
            System.out.println(Deck.get(count));
        }
        System.out.println();
    }

    public static void ShuffleDeck() throws InterruptedException{
        System.out.print("Shuffling deck");
        Thread.sleep(1000);
        for(int count=0; count<3; count++){
            System.out.print(".");
            Thread.sleep(1000);
        }
        Collections.shuffle(Deck);
        System.out.println(" Deck shuffled!");
        System.out.println();
    }

    public static void CutDeck() throws InterruptedException{
        System.out.print("Cutting deck");
        Thread.sleep(1000);
        for(int count=0; count<3; count++){
            System.out.print(".");
            Thread.sleep(1000);
        }
        System.out.println();
        System.out.println("The cut card is:");
        Random random = new Random();
        int CutPoint = 51 - (random.nextInt(52));
        System.out.println(Deck.get(CutPoint));
        System.out.println();
    }

    public static void CountdownEffect() throws InterruptedException{
        Thread.sleep(1000);
        for(int count=0; count<3; count++){
            System.out.print(".");
            Thread.sleep(1000);
        }
    }
} 

public class Player{

    public Player(ArrayList<Integer> h, int id, int n){
        Hand = new ArrayList<>(h);
        playerid = id;
        NoOfPlayers = n;
    }

    public ArrayList<Integer> Hand;
    public int playerid;
    public static int NoOfPlayers;

    public int SizeOfHand(){
        int s = Hand.size();
        return s;
    }

    public void DisplayHand() throws InterruptedException{
        System.out.print("Displaying ");
        if (playerid==1)
            System.out.print("player's");
        else if (playerid==2)
            System.out.print("computer player 1's");
        else if (playerid==3)
            System.out.print("computer player 2's");
        else if (playerid==4)
            System.out.print("computer player 3's");
        System.out.println(" hand:");
        Thread.sleep(1000);
        for(int count=0; count<7; count++){
            if (count<6)
                System.out.print(Hand.get(count) + ", ");
            else if (count==6)
                System.out.println(Hand.get(count) + ".");
        }
    }
}

public class PlayGinRummy {

    public PlayGinRummy(){}

    public static int NoOfPlayers;

    public static void DealDeck() throws InterruptedException{
        int cardno, playerno; // Tracks index of top card
        System.out.println("Please input the desired number of players (2-4): ");
        Scanner UserInput = new Scanner(System.in);
        NoOfPlayers = UserInput.nextInt(); 
        System.out.println();
        System.out.println();

        cardno=51;
        playerno=0;

        do{
            if (NoOfPlayers==2){
                Player hp = new Player(Player.Hand,1,NoOfPlayers); 
                Player cp1 = new Player(Player.Hand,2,NoOfPlayers);

                do{
                    if (playerno%2==0)
                        hp.Hand.add(DeckOfCards.Deck.get(cardno));
                    else if (playerno%2==1)
                        cp1.Hand.add(DeckOfCards.Deck.get(cardno));

                    DeckOfCards.Deck.remove(cardno);

                    playerno++;
                    cardno--;
                }while(hp.SizeOfHand()!=7 && cp1.SizeOfHand()!=7);

                hp.DisplayHand();
                cp1.DisplayHand();
            }
            else if (NoOfPlayers==3){
                Player hp = new Player(Player.Hand,1,NoOfPlayers);
                Player cp1 = new Player(Player.Hand,2,NoOfPlayers);
                Player cp2 = new Player(Player.Hand,3,NoOfPlayers);

                do{
                    if (playerno%3==0)
                        hp.Hand.add(DeckOfCards.Deck.get(cardno));
                    else if (playerno%3==1)
                        cp1.Hand.add(DeckOfCards.Deck.get(cardno));
                    else if (playerno%3==2)
                        cp2.Hand.add(DeckOfCards.Deck.get(cardno));

                    DeckOfCards.Deck.remove(cardno);

                    playerno++;
                    cardno--;
                }while(hp.SizeOfHand()!=7 && cp1.SizeOfHand()!=7 && cp2.SizeOfHand()!=7);

                hp.DisplayHand();
                cp1.DisplayHand();
                cp2.DisplayHand();
            }
            else if (NoOfPlayers==4){
                Player hp = new Player(Player.Hand,1,NoOfPlayers);
                Player cp1 = new Player(Player.Hand,2,NoOfPlayers);
                Player cp2 = new Player(Player.Hand,3,NoOfPlayers);
                Player cp3 = new Player(Player.Hand,4,NoOfPlayers);

                do{
                    if (playerno%4==0)
                        hp.Hand.add(DeckOfCards.Deck.get(cardno));
                    else if (playerno%4==1)
                        cp1.Hand.add(DeckOfCards.Deck.get(cardno));
                    else if (playerno%4==2)
                        cp2.Hand.add(DeckOfCards.Deck.get(cardno));
                    else if (playerno%4==3)
                        cp3.Hand.add(DeckOfCards.Deck.get(cardno));

                    DeckOfCards.Deck.remove(cardno);

                    playerno++;
                    cardno--;
                }while(hp.SizeOfHand()!=7 && cp1.SizeOfHand()!=7 && cp2.SizeOfHand()!=7 && cp3.SizeOfHand()!=7);

                hp.DisplayHand();
                cp1.DisplayHand();
                cp2.DisplayHand();
                cp3.DisplayHand();
            }
            else{
                System.out.println("The choice made is invalid, please try again.");
                System.out.println();
            }
        }while(NoOfPlayers!=2 && NoOfPlayers!=3 && NoOfPlayers!=4);       

        System.out.println();
    }
}    
ADTC
  • 8,999
  • 5
  • 68
  • 93
Spirrett
  • 11
  • 1

1 Answers1

2

As the "main" method must be static, surely anything it can access has to also be static and so on and so forth?

No. Static methods can access instance methods. They do that by using an instance. It's very, very common for main to create an instance in order to use instance methods (either of the class main itself is in, or of other classes).

So in general:

public static final void main(String[] args) {
    SomeClass instance = new SomeClass();
    instance.method();
}

If you're making something small and entirely self-contained, it's common for main to create the class it's in. For example:

public class Simple {
    private String name;

    public static final void main(String[] args) {
        // Create a couple of instances
        Simple s1 = new Simple();
        Simple s2 = new Simple();

        // Use instance methods
        s1.setName("s1");
        s2.setName("s2");
        System.out.println(s1.getName());
        System.out.println(s2.getName());
    }

    private void setName(String name) {
        this.name = name;
    }

    private String getName() {
        return this.name;
    }
}

There I've used two separate instances for emphasis. I used individual variables for them, but of course if you're going to treat them as a grouped list or set of instances, you'd probably use an array, List, or Set. Array example:

public class Simple {
    private String name;

    public static final void main(String[] args) {
        // Create the array (no instances are created)
        Simple[] simples = new Simple[2];

        // Create a couple of instances, set their names
        for (int n = 0; n < simples.length; ++n) {
            simples[n] = new Simple();
            simples[n].setName("s[" + n + "]");
        }

        // Use instance methods
        for (Simple s : simples) {
            System.out.println(s.getName());
        }
    }

    private void setName(String name) {
        this.name = name;
    }

    private String getName() {
        return this.name;
    }
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • It is not a requirement for main to be `final` in this case, is it? – Nico Jan 06 '14 at 18:53
  • I think, no. It does not matter. – solvator Jan 06 '14 at 18:55
  • 1
    @nickecarlo: I'm just used to using `final` on `main`, since the purpose of `main` is to be the entry point of an application; overriding it in a subclass would be odd. But no, quite right, it's not *necessary*. – T.J. Crowder Jan 06 '14 at 18:56
  • @T.J.Crowder Thanks, I wasn't sure myself actually. Haven't done anything in Java in a little while now. – Nico Jan 06 '14 at 18:59
  • So in this instance, how would I go about calling multiple instances of "Player", so that I could set them all to have different hands and player ids? My knowledge of java is still pretty poor, so I don't know what code I'd need to use... – Spirrett Jan 06 '14 at 19:27
  • @Spirrett Have you gone through this: http://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html ? – Nico Jan 06 '14 at 20:38
  • @nickecarlo I have had a look through it a couple of times before, and while obviously I can see that it's relevant to what I'm trying to do, I can't see what I'm doing differently in my program to what's in the examples. Very confusing, as I'm pretty sure I'm using the same code, but that article doesn't give me a wider context to compare to. – Spirrett Jan 07 '14 at 12:03