Practice coding in Java by writing a game

Writing simple games is a fun way to learn a new programming language. Put that principle to work to get started with Java.
58 readers like this.

My article about learning different programming languages lists five things you need to understand when starting a new language. An important part of learning a language, of course, is knowing what you intend to do with it.

I've found that simple games are both fun to write and useful in exploring a language's abilities. In this article, I demonstrate how to create a simple guessing game in Java.

Install Java

To do this exercise, you must have Java installed. If you don't have it, check out these links to install Java on Linux, macOS, or Windows.

After installing it, run this Java command in a terminal to confirm the version you installed:

$ java -version

Guess the number

This "guess the number" program exercises several concepts in programming languages: how to assign values to variables, how to write statements, and how to perform conditional evaluation and loops. It's a great practical experiment for learning a new programming language.

Here's my Java implementation:

package com.example.guess;

import java.util.Random;
import java.util.Scanner;
    
class Main {
    private static final Random r = new Random();
    private static final int NUMBER = r.nextInt(100) + 1;
    private static int guess = 0;

    public static void main(String[] args) {  
    	Scanner player = new Scanner(System.in);
	    System.out.println("number is " + String.valueOf(NUMBER)); //DEBUG
	    while ( guess != NUMBER ) {
	    // prompt player for guess
            System.out.println("Guess a number between 1 and 100");
            guess = player.nextInt();
	    if ( guess > NUMBER ) {
		System.out.println("Too high");
	    } else if ( guess < NUMBER ) {
		System.out.println("Too low");
	    } else {
		System.out.println("That's right!");
		System.exit(0);
	    }
	}
  }
}

That's about 20 lines of code, excluding whitespace and trailing braces. Structurally, however, there's a lot going on, which I'll break down here.

Package declaration

The first line, package com.example.guess, is not strictly necessary in a simple one-file application like this, but it's a good habit to get into. Java is a big language, and new Java is written every day, so every Java project needs to have a unique identifier to help programmers tell one library from another.

When writing Java code, you should declare a package it belongs to. The format for this is usually a reverse domain name, such as com.opensource.guess or org.slf4j.Logger. As usual for Java, this line is terminated by a semicolon.

Import statements

The next lines of the code are import statements, which tell the Java compiler what libraries to load when building the executable application. The libraries I use here are distributed along with OpenJDK, so you don't need to download them yourself. Because they're not strictly a part of the core language, you do need to list them for the compiler.

The Random library provides access to pseudo-random number generation, and the Scanner library lets you read user input in a terminal.

Java class

The next part creates a Java class. Java is an object-oriented programming language, so its quintessential construct is a class. There are some very specific code ideas suggested by a class, and if you're new to programming, you'll pick up on them with practice. For now, think of a class as a box into which you place variables and code instructions, almost as if you were building a machine. The parts you place into the class are unique to that class, and because they're contained in a box, they can't be seen by other classes. More importantly, since there is only one class in this sample game, a class is self-sufficient: It contains everything it needs to perform its particular task. In this case, its task is the whole game, but in larger applications, classes often work together in a sort of daisy-chain to produce complex jobs.

In Java, each file generally contains one class. The class in this file is called Main to signify that it's the entry-point for this application. In a single-file application such as this, the significance of a main class is difficult to appreciate, but in a larger Java project with dozens of classes and source files, marking one Main is helpful. And anyway, it's easy to package up an application for distribution with a main class defined.

Java fields

In Java, as in C and C++, you must declare variables before using them. You can define "fields" at the top of a Java class. The word "field" is just a fancy term for a variable, but it specifically refers to a variable assigned to a class rather than one embedded somewhere in a function.

This game creates three fields: Two to generate a pseudo-random number, and one to establish an initial (and always incorrect) guess. The long string of keywords (private static final) leading up to each field may look confusing (especially when starting out with Java), but using a good IDE like Netbeans or Eclipse can help you navigate the best choice.

It's important to understand them, too. A private field is one that's available only to its own class. If another class tries to access a private field, the field may as well not exist. In a one-class application such as this one, it makes sense to use private fields.

A static field belongs to the class itself and not to a class instance. This doesn't make much difference in a small demo app like this because only one instance of the class exists. In a larger application, you may have a reason to define or redefine a variable each time a class instance is spawned.

A final field cannot have its value changed. This application demonstrates this perfectly: The random number never changes during the game (a moving target wouldn't be very fair), while the player's guess must change or the game wouldn't be winnable. For that reason, the random number established at the beginning of the game is final, but the guess is not.

Pseudo-random numbers

Two fields create the random number that serves as the player's target. The first creates an instance of the Random class. This is essentially a random seed from which you can draw a pretty unpredictable number. To do this, list the class you're invoking followed by a variable name of your choice, which you set to a new instance of the class: Random r = new Random();. Like other Java statements, this terminates with a semicolon.

To draw a number, you must create another variable using the nextInt() method of Java. The syntax looks a little different, but it's similar: You list the kind of variable you're creating, you provide a name of your choice, and then you set it to the results of some action: int NUMBER = r.nextInt(100) + 1;. You can (and should) look at the documentation for specific methods, like nextInt(), to learn how they work, but in this case, the integer drawn from the r random seed is limited up to 100 (that is, a maximum of 99). Adding 1 to the result ensures that a number is never 0 and the functional maximum is 100.

Obviously, the decision to disqualify any number outside of the 1 to 100 range is a purely arbitrary design decision, but it's important to know these constraints before sitting down to program. Without them, it's difficult to know what you're coding toward. If possible, work with a person whose job it is to define the application you're coding. If you have no one to work with, make sure to list your targets first—and only then put on your "coder hat."

Main method

By default, Java looks for a main method (or "function," as they're called in many other languages) to run in a class. Not all classes need a main method, but this demo app only has one method, so it may as well be the main one. Methods, like fields, can be made public or private and static or non-static, but the main method must be public and static for the Java compiler to recognize and utilize it.

Application logic

For this application to work as a game, it must continue to run while the player takes guesses at a secret pseudo-random number. Were the application to stop after each guess, the player would only have one guess and would very rarely win. It's also part of the game's design that the computer provides hints to guide the player's next guess.

A while loop with embedded if statements achieves this design target. A while loop inherently continues to run until a specific condition is met. (In this case, the guess variable must equal the NUMBER variable.) Each guess can be compared to the target NUMBER to prompt helpful hints.

Syntax

The main method starts by creating a new Scanner instance. This is the same principle as the Random instance used as a pseudo-random seed: You cite the class you want to use as a template, provide a variable name (I use player to represent the person entering guesses), and then set that variable to the results of running the class' main method. Again, if you were coding this on your own, you'd look at the class' documentation to get the syntax when using it.

This sample code includes a debugging statement that reveals the target NUMBER. That makes the game moot, but it's useful to prove to yourself that it's working correctly. Even this small debugging statement reveals some important Java tips: System.out.println is a print statement, and the valueOf() method converts the integer NUMBER to a string to print it as part of a sentence rather than an element of math.

The while statement begins next, with the sole condition that the player's guess is not equal to the target NUMBER. This is an infinite loop that can end only when it's false that guess does not equal NUMBER.

In this loop, the player is prompted for a number. The Scanner object, called player, takes any valid integer entered by the player and puts its value into the guess field.

The if statement compares guess to NUMBER and responds with System.out.println print statements to provide feedback to the human player.

If guess is neither greater than nor less than NUMBER, then it must be equal to it. At this point, the game prints a congratulatory message and exits. As usual with POSIX application design, this game exits with a 0 status to indicate success.

Run the game

To test your game, save the sample code as Guess.java and use the Java command to run it:

$ java ./Guess.java
number is 38
Guess a number between 1 and 100
1
Too low
Guess a number between 1 and 100
39
Too high
Guess a number between 1 and 100
38
That's right!
$ 

Just as expected!

Package the game

While it isn't as impressive on a single-file application like this as it is on a complex project, Java makes packaging very easy. For the best results, structure your project directory to include a place for your source code, a place for your compiled class, and a manifest file. In practice, this is somewhat flexible, and using an IDE does most of the work for you. It's useful to do it by hand once in a while, though.

Create a project folder if you haven't already. Then create one directory called src to hold your source files. Save the sample code in this article as src/Guess.java:

$ mkdir src
$ mv sample.java src/Guess.java

Now, create a directory tree that mirrors the name of your Java package, which appears at the very top of your code:

$ head -n1 src/Guess.java
package com.example.guess;
$ mkdir -p com/example/guess

Create a new file called Manifest.txt with just one line of text in it:

$ echo "Manifest-Version: 1.0" > Manifest.txt

Next, compile your game into a Java class. This produces a file called Main.class in com/example/guess:

$ javac src/Guess.java -d com/example/guess
$ ls com/example/guess/
Main.class

You're all set to package your application into a JAR (Java archive). The jar command is a lot like the tar command, so many of the options may look familiar:

$ jar cfme Guess.jar \
Manifest.txt \
com.example.guess.Main \
com/example/guess/Main.class

From the syntax of the command, you may surmise that it creates a new JAR file called Guess.jar with its required manifest data located in Manifest.txt. Its main class is defined as an extension of the package name, and the class is com/example/guess/Main.class.

You can view the contents of the JAR file:

$ jar tvf Guess.jar
     0 Wed Nov 25 10:33:10 NZDT 2020 META-INF/
    96 Wed Nov 25 10:33:10 NZDT 2020 META-INF/MANIFEST.MF
  1572 Wed Nov 25 09:42:08 NZDT 2020 com/example/guess/Main.class

And you can even extract it with the xvf options.

Run your JAR file with the java command:

$ java -jar Guess.jar

Copy your JAR file from Linux to a macOS or Windows computer and try running it. Without recompiling, it runs as expected. This may seem normal if your basis of comparison is, say, a simple Python script that happens to run anywhere, but imagine a complex project with several multimedia libraries and other dependencies. With Java, those dependencies are packaged along with your application, and it all runs on any platform. Welcome to the wonderful world of Java!

What to read next

Why I use Java

There are probably better languages than Java, depending on work requirements. But I haven't seen anything yet to pull me away.

Seth Kenlon
Seth Kenlon is a UNIX geek, free culture advocate, independent multimedia artist, and D&D nerd. He has worked in the film and computing industry, often at the same time.

2 Comments

If you are introducing Java to younger children an alternative to consider is using the block based Alice (https://www.alice.org/) from Carnegie Mellon Uni

That's a great tip, Peter. I've heard of Alice but I haven't tried it yet. I remember enjoying Greenfoot (greenfoot.org) too.

Thanks for this comment, it gives me something to experiment with over the holiday break!

In reply to by peter_cheer

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.