Target
I wrote this program in a few free hours when I was on an excursion as "youth leader". I had created a game to explore the house, with a 40-field mechanic, using dice for advancing and question-based setbacks.
The dice and questions were managed outside the program. De-facto this was just to show progressions of the different teams on a screen.
The names of the team-members have been changed to protect the innocent. I tried to keep the Game configurable aside from the teams.
That said, let's jump into the code:
Code
Main-class:
/**
* Class for containing the main method. Will only start up the Screen and keep
* running until screen terminates (or rather signals execution stop)
*
* @author vogel612
*
*/
public class Program {
public static void main(String[] args) {
Screen screen = new Screen();
screen.startGame();
while (screen.isRunning()) {
}
}
}
I doubt there's much to say here. I am slightly unhappy about the program exit construction, but I doubt there's much to change here...
Display
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
/**
* Screen Class: Contains... everything frankly. Teams their colors a few settings and handlers for buttons.
* While that maybe isn't the best idea, the simplicity of the problem allows this.
*
* @author vogel612
*
*/
public class Screen extends JFrame {
private static final long serialVersionUID = 8208211925302053925L;
private static final Color teamOneColor = new Color(0.3f, 0.0f, 0.3f, 0.8f);
private static final Color teamTwoColor = new Color(0.0f, 0.3f, 0.3f, 0.8f);
private static final Color noTeamColor = new Color(0.8f, 0.8f, 0.8f);
private static final Color black = new Color(0.0f, 0.0f, 0.0f);
private enum Team {
Team_1(teamOneColor, "Male 1 & Female 1"), Team_2(teamTwoColor, "Male 2 & Female 2");
private final Color teamColor;
private int position;
private final String teamName;
Team(Color color, String name) {
this.teamName = name;
this.teamColor = color;
this.position = 0;
}
public int getPosition() {
return position;
}
public Color getColor() {
return teamColor;
}
public boolean advance(int by) {
if (by == 0 || by < -1) {
throw new IllegalArgumentException();
}
if (position + by > FIELD_COUNT) {
position = FIELD_COUNT;
return true;
}
this.position += by;
return false; // no game end
}
public String getTeamName() {
return teamName;
}
}
private static final int FIELD_COUNT = 40;
private static final int FIELD_WIDTH = 50;
private static final int FIELD_HEIGHT = 50;
private static final Dimension defaultFieldDimension = new Dimension(
FIELD_WIDTH, FIELD_HEIGHT);
private static final Dimension defaultWindowDimension = new Dimension(
((int) Math.sqrt(FIELD_COUNT) + 3) * FIELD_WIDTH,
((int) Math.sqrt(FIELD_COUNT) + 3) * FIELD_HEIGHT);
private final JComboBox<Team> teamInput = new JComboBox<>(Team.values());
private final JTextField textInput = new JTextField(1);
private final JButton submit = new JButton("OK");
private final EventQueue events = Toolkit.getDefaultToolkit()
.getSystemEventQueue();
private boolean isRunning = false;
private JPanel[] fields = new JPanel[FIELD_COUNT + 1];
public Screen() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle("Hausspiel Frankenhofen");
this.setPreferredSize(defaultWindowDimension);
this.setSize(defaultWindowDimension);
this.setLayout(new FlowLayout(FlowLayout.LEFT));
}
public void startGame() {
initialize();
this.setVisible(true);
this.isRunning = true;
repaintPositions();
}
private void repaintPositions() {
Arrays.stream(fields).forEach(f -> f.setBackground(noTeamColor));
Arrays.stream(Team.values()).forEach(
t -> fields[t.getPosition()].setBackground(t.getColor()));
this.repaint();
}
private void initialize() {
createFields();
}
private void createFields() {
for (int i = 0; i <= FIELD_COUNT; i++) {
JPanel field = new JPanel();
field.add(new JLabel((i == 0) ? "Start" : i + ""));
field.setName(i + "");
field.setSize(defaultFieldDimension);
field.setPreferredSize(defaultFieldDimension);
field.setBackground(noTeamColor);
field.setBorder(new LineBorder(black));
this.add(field);
fields[i] = field;
}
Arrays.stream(Team.values()).forEach(t -> {
JPanel legend = new JPanel() {
private static final long serialVersionUID = -2035379018013186886L;
{
JLabel teamLabel = new JLabel(t + ": " + t.getTeamName());
setBackground(t.getColor());
add(teamLabel);
}
};
this.add(legend);
});
submit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (textInput.getText().isEmpty()) {
return;
}
int advanceBy;
try {
advanceBy = Integer.parseInt(textInput.getText());
} catch (NumberFormatException ex) {
return;
}
Team team = (Team) teamInput.getSelectedItem();
if (team.advance(advanceBy)) {
showWinAlert(team);
}
repaintPositions();
textInput.setText("");
}
private void showWinAlert(Team team) {
JFrame winAlert = new JFrame("Gewonnen");
winAlert.setSize(new Dimension(300, 150));
winAlert.setLayout(new FlowLayout());
winAlert.add(new JLabel("Sieger: " + team.getTeamName()));
JButton dismiss = new JButton("OK");
dismiss.addActionListener(a -> {
events.postEvent(new WindowEvent(winAlert,
WindowEvent.WINDOW_CLOSING));
});
winAlert.add(dismiss);
SwingUtilities.invokeLater(() -> {
winAlert.setVisible(true);
});
}
});
this.add(submit);
this.add(textInput);
this.add(teamInput);
this.doLayout();
}
public boolean isRunning() {
return isRunning;
}
}
As mentioned in the javadoc, this class seems to be quite the god-object. It contains everything related to the game, that's not stored outside of the program. I am not interested in reviews concerning splitting this class up.
What's by far more interesting to me is the construction around the submit
action listener.
The program is designed for java 1.8
I'd be especially interested in my use of lambdas.
In action:
Here's a small screenshot of how this looks on my laptop: