1

For my school examn I have to make a console-application game of Hangman in Java, in which a player should be able to play against another player or a computer (2 players). A player should however also be able to play against a computer/AI. On top of that computers should be able to play against a computer as well.

Given the above, I have defined HashMaps with the player's names as String indexes and respective objects as values, like so:

private HashMap<String, PlayerHuman> humans = new HashMap<>(2);
private HashMap<String, PlayerComputer> computers = new HashMap<>(2);

Since both 2 players and 2 computers can play against each other, both HashMaps have a capacity of 2. Now when creating the players, there should either be real names entered (e.g. "John", "Mary") or a simple "C" if a player is computer-controlled. I then run a check on wether the input given was a "C" or not, resulting in creating the respective class for that player, like so:

    Scanner scanner = new Scanner(System.in);

    System.out.println("First create the players for the game!");

    //
    System.out.println("Type the name of player 1 (type C for computer): ");
    String playerName1 = scanner.nextLine();

    System.out.println("Type the nam of player 2 (type C for computer): ");
    String playerName2 = scanner.nextLine();

    if (playerName1.equals("C")) {

        PlayerComputer player1 = new PlayerComputer();
        player1.setPlayerName(playerName1);

        if (playerName2.equals("C")) {
            playerName1 = "C1";
            playerName2 = "C2";
            PlayerComputer player2 = new PlayerComputer();
            player1.setPlayerName(playerName1);
            player2.setPlayerName(playerName2);
            this.computers.put(playerName2, player2);

        } else {
            PlayerHuman player2 = new PlayerHuman();
            player2.setPlayerName(playerName2);
            this.humans.put(playerName2, player2);
        }

        this.computers.put(playerName1, player1);

    } else {
        PlayerHuman player1 = new PlayerHuman();
        player1.setPlayerName(playerName1);

        if (playerName2.equals("C")) {
            PlayerComputer player2 = new PlayerComputer();
            player2.setPlayerName(playerName2);
            this.computers.put(playerName2, player2);

        } else {
            PlayerHuman player2 = new PlayerHuman();
            player2.setPlayerName(playerName2);
            this.humans.put(playerName2, player2);
        }

        this.humans.put(playerName1, player1);

    }

    String startingPlayer = raffle(playerName1, playerName2);

There is definitely an easier way to do this, I have just run completely stuck and do not see a way out anymore. I then have to randomly select either of 2 players to be the first to play. I do this in the following method "raffle".

private String raffle(String nameOne, String nameTwo) {
    Random random = new Random();
    String raffledName = random.nextBoolean() ? nameOne : nameTwo;

    System.out.println(raffledName + " may begin!");

    return raffledName;
}

After this is where I run stuck. I'm getting the expected result from the "raffle" method; one of two given player's names, however I'm lost on how to make the code know which array to retrieve the returned player from, as a computer could either be named "C", or "C1" and "C2" when both players are computer-controlled, to know which computer represents which player. How do I make my code take this into consideration when retrieving the player's respective instance?

Any suggestions on creating the players are welcome too, since I feel the above written code is dirty and too procedural.

Thanks in advance!

NickL
  • 4,258
  • 2
  • 21
  • 38
thebugsdontwork
  • 401
  • 3
  • 17

1 Answers1

2

I would like to suggest that you define a super class "Player" that your two player types derive from.

abstract class Player {
    private String name;
    public void setPlayerName(String name) {
        this.name = name;
    }
    public String getPlayerName() { return name; }

    abstract public boolean isCPU();
    ...
}


class PlayerHuman extends Player {
    public boolean isCPU() { return false; }
    ...
}

class PlayerComputer extends Player {
    public boolean isCPU() { return true; }
    ...
}

HashMap<String, Player> players = ...

Or, you can just use an array for players:

Player[] players = new Player[2];

You don't have to refer to player by name, then, and you can shuffle the array to decide who goes first.

Jamie
  • 1,888
  • 1
  • 18
  • 21
  • They can also add a `Team` class (which can be a [Pair](https://stackoverflow.com/a/7733735/2928853) in this case) to hold team logic and behavior. – jrook Oct 17 '18 at 20:21
  • Just to expand on the array use, it is not a good idea to use a hashmap to refer to players by name, as you could have two players with the same name, or two players who decide to just hit enter for their name, and then both players will refer to the same map entry. – Jamie Oct 17 '18 at 20:28
  • @Jamie I did not know you could define a HashMap without explicitly defining the datatype of the value. That will help me a lot! – thebugsdontwork Oct 17 '18 at 20:37
  • @JeroendeKlerk, yet that was not what @Jamie was getting at. `HashMap`s are like boxes with specific keys. When there is a possibility that the keys would be similar, it is not a good idea to use such a data structure. Create an array or in this case, just leave the players be as four distinct objects. `HashMap` is not a good idea for this problem. – jrook Oct 17 '18 at 21:15
  • Not sure why you would want to define the map like that, you won't be able to `put` anything into the map. The concrete type of the map will be `HashMap` anyway otherwise you won't be able to add the different types of players. – NickL Oct 17 '18 at 21:50
  • @NickL you are right, I am not sure what I was thinking. Should have just used HashMap. – Jamie Oct 18 '18 at 13:10