Eine einfache Implementierung des Gomoku-Views liegt in
View.java
vor. Sie enthält zwei Testtreiber: Der erste ist autonom, d.h. stellt nur ein
Brett mit besetzten Figuren dar. Die Größe des Bretts und des Feld sowie die
Figur stehen als Konstanten fest.
package view; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import model.BesetztException; import model.IModel; import model.Spieler; import model.Model; // nur zu Testzwecken
/** View.java * Einfaches graphisches View für Gomoku mit MVC * Stellt das Spielbrett und eine Informationstafel auf einem swing.JFrame dar. * Auf der Informationstafel wird während des Spiels "Stein setzen: " (mit "O" oder "X" je nach dem nächsten Spielers) dargestellt. * Am Ende des Spiels steht dort "o gewinnt" bzw. "x gewinnt", je nach Sieger. Die Koordinaten der Endpunkte der Siegerlinie werden auch angegeben. * Die Brettgröße (Anzahl der Felder) und die Feldgröße (in Pixeln) wird als Konstruktorparameter angegeben. * Beenden erfolgt durch Schließen des Fensters. * @author Prof. Dr. Andreas Solymosi, Beuth-Hochschule für Technik, (c) 2012, solymosi@tfh-berlin.de * @version 5/1/12 */
public class View extends JPanel implements IView { private static final long serialVersionUID = 1L; private static final String steinSetzen = "Stein setzen: ", // Texte für die Informationstafel feldBesetzt = "Feld besetzt -" + steinSetzen, gewinnt = " gewinnt";
private int höhe, breite; // dargestellte Brettgröße private IModel model; // Konstruktorparameter private Panel panel; // für die Darstellung des Bretts private JLabel label; // Informationstafel
/* * @param model * @param höhe Anzahl der Felder * @param breite Anzahl der Felder * @param feldgröße in Pixeln; wird nur lokal gebraucht */ public View(final IModel model, int höhe, int breite, int feldgröße) { this.model = model; this.höhe = höhe; this.breite = breite;
super.setLayout(new BorderLayout()); this.label = new JLabel(steinSetzen + model.nächster()); super.add(label, BorderLayout.NORTH); this.panel = new Panel(); panel.setPreferredSize(new Dimension(feldgröße*höhe, feldgröße*breite)); super.add(panel, BorderLayout.CENTER);
JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.getContentPane().add(this); frame.pack(); frame.setVisible(true); }
@Override public Dimension brettgröße() { return new Dimension(höhe, breite); }
@Override public void neuZeichnen() { if (model.sieger() != Spieler.LEER) label.setText(model.sieger() + gewinnt); else label.setText(steinSetzen + model.nächster()); this.repaint(); }
public void feldBesetzt(int x, int y) { label.setText(feldBesetzt + model.nächster() + " " + x + "/" + y); this.repaint(); }
private class Panel extends JPanel { // Brett @Override public void paintComponent(Graphics g) { super.paintComponent(g); int dx = this.getWidth() / höhe; int dy = this.getHeight() / breite;
// Gitter zeichnen: g.setColor(Color.BLACK); for (int zeile = 1; zeile < höhe; zeile++) for (int spalte = 1; spalte < breite; spalte++) { // nur zwischen den Feldern g.drawLine(zeile*dx, 0, zeile*dx, getHeight()); g.drawLine(0, spalte*dy, getWidth(), spalte*dy); }
// auf besetzte Felder Figuren zeichnen: for (int zeile = 0; zeile < höhe; zeile++) for (int spalte = 0; spalte < breite; spalte++) { // Figuren an der Siegerlinie rot zeichnen, andere schwarz: g.setColor(model.siegerlinie(zeile, spalte) ? Color.red : Color.black); if (model.besetztVon(zeile, spalte) == Spieler.X) { // Kreuz zeichnen final int x0 = zeile*dx, y0 = spalte*dy; g.drawLine(x0, y0, x0+dx, y0+dy); g.drawLine(x0, y0+dy, x0+dx, y0); } else if (model.besetztVon(zeile, spalte) == Spieler.O) // Kreis zeichnen g.drawOval(zeile*dx, spalte*dy, dx, dy); } } }
/* Zwei Testreiber: * 1. autonom mit Dummy-Model * 2. mit zufallsgesteuertem Model wenn Kommandozeilenparameter besetzt: * @param kzp[0] Bretthöhe, Anzahl der Felder * @param kzp[1] Brettbreite, Anzahl der Felder * @param kzp[2] Feldgröße, Anzahl der Pixel * @param kzp[3] "X" wenn X anfängt, sonst fängt O an * @param kzp[4] Wartezeit zwischen den Zügen in Millisekunden */ public static void main(String[] kzp) throws InterruptedException {
if (kzp.length == 0) { // autonomer Test mit Dummy-Model final int breite = 5, höhe = 6, feldgröße = 100; final Spieler besetzung = Spieler.O; IView view = new View(new IModel() { public Spieler besetztVon(int zeile, int spalte) { return besetzung; } public Spieler nächster() { return Spieler.O; } public void start() { } public void steinSetzen(int zeile, int spalte) throws BesetztException { } public Spieler sieger() { return Spieler.O; } public boolean siegerlinie(int zeile, int spalte) { return false; }}, höhe, breite, feldgröße); view.neuZeichnen();
} else {
// Zufallsgesteuerter Test mit Model int höhe = kzp.length > 0 ? Integer.parseInt(kzp[0]) : 20, // Bretthöhe, Anzahl der Felder, Standardwert = 20 breite = kzp.length > 1 ? Integer.parseInt(kzp[1]) : 20, // Brettbreite, Anzahl der Felder, Standardwert = 20 feldgröße = kzp.length > 2 ? Integer.parseInt(kzp[1]) : 50; // Feldgröße, Anzahl der Pixel, Standardwert = 20 boolean xFängtAn = kzp.length > 3 ? kzp[3].charAt(0) == 'X' : false; // Standardwert: O fängt an int pause = kzp.length > 4 ? Integer.parseInt(kzp[4]) : 100; // Standardwert: 0,1 Sekunden
IModel model = new Model(xFängtAn); View view = new View(model, höhe, breite, feldgröße); // Testling Random r = new Random(new java.util.Date().getTime()); while (true) { int zeile = Math.abs(r.nextInt() % höhe), spalte = Math.abs(r.nextInt() % breite); // Zufallszahl zwischen 0 und 20 (bzw. höhe/breite) try { model.steinSetzen(zeile, spalte); } catch (BesetztException e) { // } view.neuZeichnen(); Thread.sleep(pause); if (model.sieger() != Spieler.LEER) { // Spiel ist zu Ende view.label.setText(model.sieger() + gewinnt + ": " + zeile + "#" + spalte); // privater Zugriff break; } } } } }
Eine fortschrittlichere View-Implementierung würde das Brett unbegrenzt und auf dem Bildschirm verschiebbar darstellen. Anstelle von einfachen Figuren könnten schönere Ikone verwendet werden.
Version: 5. Februar 2012
© Prof. Solymosi, 20102 Beuth-Hochschule für Technik Berlin, Fachbereich VI (Informatik und Medien)
solymosibht-berlin.de