Hallo liebe Community!
Ich habe folgendes Problem: Zurzeit programmiere ich an meinem Vier gewinnt.
Die meisten Probleme konnte ich selbst lösen, aber zurzeit stehe ich gerade an bei einem Problem.
Es geht um Threads. Ich habe in meinem Programm einen Thread für die Animation zum Einwerfen.
Wenn ich diesen Thread im Synchronized block ausführe also mit start() führt er den Inhalt der run Methode nicht aus. Mache ich das ganze ohne Synchronized kann ich nicht gewährleisten das das Programm richtig läuft, da ich keine Möglichkeit habe es zu schaffen einen Einwurf nach dem anderen zu machen.
Java Code steht am Ende des beitrags
Probiert es mal ohne Synchronized Block und ihr werdet sehen was ich meine. Dann arbeitet das programm nicht richtig. btw das ist keine Hausübung ich mache das freiwillig und zum Spaß
Falls es Verbesserungsvorschläge gibt ich bin immer für welche offen
Bin ja nicht perfekt
mfg,
Vancold
PS: JAVA code steht unterhalb ;P
Leider ist es nicht fertig Dokumentiert. Wenn ihr fragen habt bitte einfach fragen
Ich habe folgendes Problem: Zurzeit programmiere ich an meinem Vier gewinnt.
Die meisten Probleme konnte ich selbst lösen, aber zurzeit stehe ich gerade an bei einem Problem.
Es geht um Threads. Ich habe in meinem Programm einen Thread für die Animation zum Einwerfen.
Wenn ich diesen Thread im Synchronized block ausführe also mit start() führt er den Inhalt der run Methode nicht aus. Mache ich das ganze ohne Synchronized kann ich nicht gewährleisten das das Programm richtig läuft, da ich keine Möglichkeit habe es zu schaffen einen Einwurf nach dem anderen zu machen.
Java Code steht am Ende des beitrags
Probiert es mal ohne Synchronized Block und ihr werdet sehen was ich meine. Dann arbeitet das programm nicht richtig. btw das ist keine Hausübung ich mache das freiwillig und zum Spaß
Falls es Verbesserungsvorschläge gibt ich bin immer für welche offen
Bin ja nicht perfekt
mfg,
Vancold
PS: JAVA code steht unterhalb ;P
Leider ist es nicht fertig Dokumentiert. Wenn ihr fragen habt bitte einfach fragen
Java:
package vierGewinnt;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* VGPanelklasse
*
* Diese Klasse beinhaltet die GUI-Componenten + der zugehörigen Listener.
* Sie hat die Aufgabe das eigentliche Spiel + Funktionen des Spiels darzustellen.
*
* @author Rene Polak
* @version 2010-11-17
*/
public class VGPanel extends JPanel {
// Komponenten für die GUI
private JPanel groupPanel1,groupPanel2,groupPanel3;
private JButton reset;
private JLabel spieleStatus;
// Mouse & Buttonlistener
private MouseHandler mh;
private ButtonHandler bh;
// Spielfelder (JPanels)
private Feld[] einwurfsFelder;
private Feld[][] felder;
// Speichert welcher Spieler gerade am Zug ists
private int spieler;
// Thread welcher die Steine, die zum Gewinn geführt haben, blinken lässt
private BlinkThread bt;
private WurfAnimationsThread wat;
// Schaltervariable (Siehe Zeile 92)
private boolean schalter;
/**
* Defaultkonstruktor
*/
public VGPanel() {
// Layout des Obejkts setzten
this.setLayout(new BorderLayout());
this.schalter = false;
this.spieler = 1;
// gruppierungsPanel mit GridLayout 6*7 initialisieren und Hintergrundfarbe setzen
this.groupPanel1 = new JPanel(new GridLayout(6,7,5,5));
this.groupPanel1.setBackground(Color.BLUE);
// MouseListener intialisieren
mh = new MouseHandler();
// Das zwei Dimensionale feld Array initialisieren
this.felder = new Feld[6][7];
// Felder Intialisieren und dem groupPanel 1 hinzufügen
for(int i = 0; i < this.felder.length; i++) {
for(int j = 0; j < this.felder[i].length; j++) {
this.felder[i][j] = new Feld(Feld.LEER,Color.BLUE);
this.groupPanel1.add(this.felder[i][j]);
}
}
// GroupPanel 2 mit GridLayout 1*6 initialisieren & Hintergrundfarbe setzen
this.groupPanel2 = new JPanel(new GridLayout(1,6,5,5));
this.groupPanel2.setBackground(Color.WHITE);
// Felder Array intialisieren
this.einwurfsFelder = new Feld[7];
//
for(int i = 0; i < einwurfsFelder.length; i++ ) {
this.einwurfsFelder[i] = new Feld(Feld.LEER,Color.WHITE);
this.einwurfsFelder[i].addMouseListener(mh);
this.groupPanel2.add(this.einwurfsFelder[i]);
}
this.bh = new ButtonHandler();
this.reset = new JButton("Neustarten");
this.reset.addActionListener(bh);
this.reset.setPreferredSize(new Dimension(120,30));
this.spieleStatus = new JLabel("Spieler 1");
this.spieleStatus.setPreferredSize(new Dimension(150,30));
this.groupPanel3 = new JPanel(new FlowLayout(FlowLayout.CENTER));
this.groupPanel3.add(reset);
this.groupPanel3.add(spieleStatus);
this.groupPanel2.setPreferredSize(new Dimension(300,35));
this.add(groupPanel2,BorderLayout.NORTH);
this.add(groupPanel1, BorderLayout.CENTER);
this.add(groupPanel3,BorderLayout.SOUTH);
}
private boolean gewonnen() {
/*
* Diese Schalter ist dazu da um den Spieler abzuhalten Spielsteine nach dem Sieg zu setzen
* Da der Thread den Zustand kurzzeitig auf 0 setzt ist es wieder möglich Steine zu setzen.
* Darum wird ein Schalter aktiviert der die Unterbindet.
*/
if(schalter != true) {
for(int i = 0; i < felder.length; i++) {
for(int j = 0; j < 4; j++) {
if((felder[i][j].getZustand()== 1)&&(felder[i][j+1].getZustand()== 1)&&(felder[i][j+2].getZustand()== 1)&&(felder[i][j+3].getZustand()== 1)) {
Feld[] reihe = new Feld[4];
reihe[0] = felder[i][j];
reihe[1] = felder[i][j+1];
reihe[2] = felder[i][j+2];
reihe[3] = felder[i][j+3];
bt = new BlinkThread(reihe,spieler);
bt.start();
schalter = true;
return true;
}
if((felder[i][j].getZustand()== 2)&&(felder[i][j+1].getZustand()== 2)&&(felder[i][j+2].getZustand()== 2)&&(felder[i][j+3].getZustand()== 2)) {
Feld[] reihe = new Feld[4];
reihe[0] = felder[i][j];
reihe[1] = felder[i][j+1];
reihe[2] = felder[i][j+2];
reihe[3] = felder[i][j+3];
bt = new BlinkThread(reihe,spieler);
bt.start();
schalter = true;
return true;
}
}
}
for(int i = 0; i < felder[0].length; i++) {
for(int j = 0; j < 3; j++) {
if((felder[j][i].getZustand()== 1)&&(felder[j+1][i].getZustand()== 1)&&(felder[j+2][i].getZustand()== 1)&&(felder[j+3][i].getZustand()== 1)) {
Feld[] reihe = new Feld[4];
reihe[0] = felder[j][i];
reihe[1] = felder[j+1][i];
reihe[2] = felder[j+2][i];
reihe[3] = felder[j+3][i];
bt = new BlinkThread(reihe,spieler);
bt.start();
schalter = true;
return true;
}
if((felder[j][i].getZustand()== 2)&&(felder[j+1][i].getZustand()== 2)&&(felder[j+2][i].getZustand()== 2)&&(felder[j+3][i].getZustand()== 2)) {
Feld[] reihe = new Feld[4];
reihe[0] = felder[j][i];
reihe[1] = felder[j+1][i];
reihe[2] = felder[j+2][i];
reihe[3] = felder[j+3][i];
bt = new BlinkThread(reihe,spieler);
bt.start();
schalter = true;
return true;
}
}
}
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 3; j++) {
if((felder[j][i].getZustand()== 1)&&(felder[j+1][i+1].getZustand()== 1)&&(felder[j+2][i+2].getZustand()== 1)&&(felder[j+3][i+3].getZustand()== 1)) {
Feld[] reihe = new Feld[4];
reihe[0] = felder[j][i];
reihe[1] = felder[j+1][i+1];
reihe[2] = felder[j+2][i+2];
reihe[3] = felder[j+3][i+3];
bt = new BlinkThread(reihe,spieler);
bt.start();
schalter = true;
return true;
}
if((felder[j][i].getZustand()== 2)&&(felder[j+1][i+1].getZustand()== 2)&&(felder[j+2][i+2].getZustand()== 2)&&(felder[j+3][i+3].getZustand()== 2)) {
Feld[] reihe = new Feld[4];
reihe[0] = felder[j][i];
reihe[1] = felder[j+1][i+1];
reihe[2] = felder[j+2][i+2];
reihe[3] = felder[j+3][i+3];
bt = new BlinkThread(reihe,spieler);
bt.start();
schalter = true;
return true;
}
}
}
for(int i = felder.length-1; i >= 3 ; i--) {
for(int j = 0; j < 4; j++) {
if((felder[i][j].getZustand()== 1)&&(felder[i-1][j+1].getZustand()== 1)&&(felder[i-2][j+2].getZustand()== 1)&&(felder[i-3][j+3].getZustand()== 1)) {
Feld[] reihe = new Feld[4];
reihe[0] = felder[i][j];
reihe[1] = felder[i-1][j+1];
reihe[2] = felder[i-2][j+2];
reihe[3] = felder[i-3][j+3];
bt = new BlinkThread(reihe,spieler);
bt.start();
schalter = true;
return true;
}
if((felder[i][j].getZustand()== 2)&&(felder[i-1][j+1].getZustand()== 2)&&(felder[i-2][j+2].getZustand()== 2)&&(felder[i-3][j+3].getZustand()== 2)) {
Feld[] reihe = new Feld[4];
reihe[0] = felder[i][j];
reihe[1] = felder[i-1][j+1];
reihe[2] = felder[i-2][j+2];
reihe[3] = felder[i-3][j+3];
bt = new BlinkThread(reihe,spieler);
bt.start();
schalter = true;
return true;
}
}
}
} else {
return true;
}
return false;
}
public boolean unentschieden() {
int anzahl = felder.length*felder[0].length;
int zaehler = 0;
for(int i = 0; i < felder.length; i++) {
for(int j = 0; j < felder[i].length; j++) {
if(felder[i][j].getZustand() == 1 ||felder[i][j].getZustand() == 2) {
zaehler += 1;
}
}
}
if(zaehler == anzahl) {
return true;
} else {
return false;
}
}
private class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
for(int i = 0; i < felder.length; i ++) {
for(int j = 0; j < felder[i].length; j++) {
felder[i][j].setZustand(0);
felder[i][j].repaint();
spieler = 1;
spieleStatus.setText("Spieler 1");
bt.stop();
schalter = false;
}
}
}
}
private class MouseHandler extends MouseAdapter {
public void mouseEntered(MouseEvent e) {
for(int i = 0; i < einwurfsFelder.length; i++) {
if(e.getSource() == einwurfsFelder[i]) {
einwurfsFelder[i].setZustand(spieler);
einwurfsFelder[i].repaint();
}
}
}
public void mousePressed(MouseEvent e) {
int reihe = 0;
if(!gewonnen() && !unentschieden()) {
for(int i = 0; i < einwurfsFelder.length; i++) {
if(e.getSource() == einwurfsFelder[i]) {
reihe = i;
}
}
Feld[] slots = new Feld[felder[0].length];
for(int i = 0; i < slots.length-1; i++) {
slots[i] = felder[i][reihe];
}
wat = new WurfAnimationsThread(slots,spieler);
synchronized(wat) {
wat.start();
try {
wat.wait();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
if(gewonnen()) {
spieleStatus.setText("Spieler " + spieler + " hat gewonnen!");
} else {
if(!unentschieden()) {
if(spieler == 1) {
spieler = 2;
spieleStatus.setText("Spieler 2");
einwurfsFelder[reihe].setZustand(spieler);
einwurfsFelder[reihe].repaint();
} else {
spieler = 1;
spieleStatus.setText("Spieler 1");
einwurfsFelder[reihe].setZustand(spieler);
einwurfsFelder[reihe].repaint();
}
}else {
spieleStatus.setText("Unentschieden!");
}
}
}
}
public void mouseExited(MouseEvent e) {
for(int i = 0; i < einwurfsFelder.length; i++) {
if(e.getSource() == einwurfsFelder[i]) {
einwurfsFelder[i].setZustand(Feld.LEER);
einwurfsFelder[i].repaint();
}
}
}
}
}
Java:
package vierGewinnt;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
/**
* Feldklasse
*
* Diese Klasse erbt von JPanel, und erweitert diese
* um 2 Attribute und 3 Konstanten.
* Sie hat 2 Konstruktoren und eine paint Methode.
* Diese Klasse hat die Aufgabe einen Spielfeld dazustellen,
* welches 3 Zustände haben kann.
*
* 1) Ein leeres Spielfeld mit blauem Hintergrund
*
* 2) Ein Spielfeld mit rotem Stein in der Mitte
*
* 3) Oder ein Spielfeld mit gelben Stein in der Mitte
*
* Das wird mit der Methode paint(Grahphics g) & einer Zustandsvariable realisiert.
* Sie überprüft welchen Zustand das JPanel hat und zeichnet die einzelnen Komponent auf das Panel.
*
* Weiters besitzt Sie für alle Attribute zugehörige Setter und Gettermethoden
*
* @author Rene Polak
* @version 2010-11-17
*
*/
public class Feld extends JPanel {
// Statische Konstanten; Sie stellen die Zustände da die das Feld einnehmen kann
public static final int LEER = 0;
public static final int ROT = 1;
public static final int GELB = 2;
// Zustand den das Feld einnimmt
private int zustand;
// Hintergrundfarbe des Panels
private Color hintergrund;
/**
* Defaultkonstruktor
*
* Erstellt ein leeres Feld.
*/
public Feld() {
this.zustand = LEER; // Der Zustand 0 bedeutet Leer
this.hintergrund = Color.WHITE;
}
/**
* Erstellt ein Feld mit Zustand & Hintergrundfarbe
*
* @param zustand status in dem sich das Feld befinden soll
* @param hintergrund Farbe die der Hintergrund des Panels haben soll
*
* 0 = Leer; 1 = Rot; 2 = Gelb
*/
public Feld(int zustand,Color hintergrund) {
this.zustand = zustand;
this.hintergrund = hintergrund;
this.repaint(); // Das frisch erstelle Panel neuzeichnen
}
/**
* Zeichnet einen Spielstein oder einen leere Kreis in das JPanel je nach dem Zustand
* 0 = Weißer Kreis; 1 = Roter Spielstein; 2 = Gelber Spielstein
*
* @param g Graphics Objekt mit dem gezeichnet wird
*/
public void paint(Graphics g) {
switch(this.zustand) { // Der interne Zustand;
case LEER: // Wenn der Zustand Leer entspricht dann
// Setzt die Farbe des Graphics-Objekt auf die Hintergrundfarbe im Objekt
g.setColor(this.hintergrund);
// Zeichnet ein Rechteck das bei 0,0 beginnt und so lang und so breit wie das Panel ist
g.fillRect(0, 0, this.getWidth(), this.getHeight());
// Setzt die Farbe des Graphics-Objekt auf Weiß
g.setColor(Color.WHITE);
// Zeichnet einen kreis der bei 0,0 beginnt und so lang und so breit wie das Panel ist
g.fillOval(0,0,this.getWidth(),this.getHeight());
break;
case ROT: // Wenn der Zustand Rot entspricht dann
// Setzt die Farbe des Graphics-Objekt auf die Hintergrundfarbe im Objekt
g.setColor(this.hintergrund);
// Zeichnet ein Rechteck,welches bei 0,0 beginnt und so lang und so breit wie das Panel ist
g.fillRect(0, 0, this.getWidth(), this.getHeight());
// Setzt die Farbe des Graphics-Objekt auf Rot
g.setColor(Color.RED);
// Zeichnet einen roten Kreis, welcher bei 0,0 beginnt und so lang und so breit wie das Panel ist.
g.fillOval(0,0,this.getWidth(),this.getHeight());
// Setzt die Farbe des Graphics-Objekt auf Schwarz
g.setColor(Color.BLACK);
// Zeichnet 2 Schwarze Kreise, einen äußeren und einen etwas kleineren innen
g.drawOval(0, 0, this.getWidth(), this.getHeight());
g.drawOval(5, 5, (this.getWidth()-10), (this.getHeight()-10));
break;
case GELB: // Wenn der Zustand Rot entspricht dann
// Setzt die Farbe des Graphics-Objekt auf die Hintergrundfarbe im Objekt
g.setColor(this.hintergrund);
// Zeichnet ein Rechteck,welches bei 0,0 beginnt und so lang und so breit wie das Panel ist
g.fillRect(0, 0, this.getWidth(), this.getHeight());
// Setzt die Farbe des Graphics-Objekt auf Gelb
g.setColor(Color.YELLOW);
// Zeichnet einen gelben Kreis, welcher bei 0,0 beginnt und so lang und so breit wie das Panel ist.
g.fillOval(0,0,this.getWidth(),this.getHeight());
// Setzt die Farbe des Graphics-Objekt auf Schwarz
g.setColor(Color.BLACK);
// Zeichnet 2 Schwarze Kreise, einen äußeren und einen etwas kleineren innen
g.drawOval(0, 0, this.getWidth(), this.getHeight());
g.drawOval(5, 5, (this.getWidth()-10), (this.getHeight()-10));
break;
}
}
/**
* Setzt den Zustand des JPanel und refresht den Inhalt anschließend
*
* @param zustand Zustand den das JPanel haben soll
*/
public void setZustand(int zustand) {
this.zustand = zustand;
this.repaint();
}
/**
* Gibt den Zustand des aktuellen JPanels zurück
*
* @return int; Gibt den Zustand des JPanels zurück
*
* 0 = Leer; 1 = Rot; 2 = GELB
*/
public int getZustand() {
return this.zustand;
}
/**
* Setzt die Hintergrundfarbe des Obejekts
*
* @param hintergrund Hintegrundfarbe die das Feld haben soll
*/
public void setHintergrund(Color hintergrund) {
this.hintergrund = hintergrund;
}
/**
* Gibt die derzeitige Hintergrundfarbe des Obejkts zurück
*
* @return Color; Die Hintergrundfarbe des Objekts
*/
public Color getHintergrund() {
return this.hintergrund;
}
}
Java:
package vierGewinnt;
public class WurfAnimationsThread extends Thread {
private Feld[] reihe;
private int spieler;
public WurfAnimationsThread() {
this.reihe = new Feld[1];
this.spieler = 1;
}
public WurfAnimationsThread(Feld[] reihe, int spieler) {
this.reihe = reihe;
this.spieler = spieler;
}
private boolean reiheIstVoll() {
for(int i = 0; i < reihe.length; i++) {
if((reihe[i].getZustand()==1) || (reihe[i].getZustand()== 2)) {
return true;
} else {
return false;
}
}
return false;
}
public void run() {
if(!reiheIstVoll()) {
for(int i = 0; i < reihe.length-1; i++) {
if(reihe[i].getZustand() == 0) {
reihe[i].setZustand(spieler);
try {
this.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
reihe[i].setZustand(Feld.LEER);
}
}
for(int j = reihe.length-2; j >= 0; j--) {
if(reihe[j].getZustand()== 0) {
reihe[j].setZustand(spieler);
break;
}
}
}
synchronized(this) {
this.notify();
}
}
}
Java:
package vierGewinnt;
/**
* Blinkthread
*
* Diese Klasse erbt von Thread.
* Sie erweitert den Thread um 2 Attribute & 2 Konstruktoren
* Sie hat die Aufgabe die Spielsteine die zum Sieg eines Spieler geführt haben,
* blinken zu lassen.Zuerst wartet der Thread 350 ms und setzt dann den die Felder auf 0,
* d.h Leer, wartet wieder 350 ms und setzt dann die Felder auf die Farbe des Gewinners,
* solange bis der Thread abgebrochen wird.
*
* @author Rene Polak
* @version 2010-11-17
*/
public class BlinkThread extends Thread {
// Beinhaltet die 4 Felder die zum Sieg eines Spielers geführt haben
private Feld[] felder;
// Der Gewinner der Partie (ist für die setZustand() Methode wichtig)
private int gewinner;
/**
* Defaultkonstruktor
*/
public BlinkThread() {
this.felder = new Feld[3];
this.gewinner = 1;
}
/**
* Diese Konstruktor erstellt ein BlinkThread mit einem Feld[] und dem gewinner der Partie.
* Das Feld[] felder beinhaltet dabei die Spielsteine die blinken sollen.
*
* @param felder Array welches die Steine beinhaltet die blinken sollen
* @param gewinner Gewinner der Partie (Ist für den zweiten Zustand beim Blinken wichtig)
*/
public BlinkThread(Feld[] felder,int gewinner) {
this.felder = felder;
this.gewinner = gewinner;
}
public void run() {
while(true) { // Endlosschleife
// Der Thread versucht 350 ms zu warten
try {
this.sleep(350); // Lässt den Thread 350 ms "schlafen"
} catch (InterruptedException e) { // Wenn etwas schief geht die entsprechende Meldung ausgeben
e.printStackTrace(); // Fehlermeldung
}
// Zustand der Felder auf Leer setzen und neuzeichnen
felder[0].setZustand(0);
felder[0].repaint();
felder[1].setZustand(0);
felder[1].repaint();
felder[2].setZustand(0);
felder[2].repaint();
felder[3].setZustand(0);
felder[3].repaint();
// Der Thread versucht 350 ms zu warten
try {
this.sleep(350); // Lässt den Thread 350 ms "schlafen"
} catch (InterruptedException e) { // Wenn etwas schief geht die entsprechende Meldung ausgeben
e.printStackTrace(); // Fehlermeldung
}
// Zustand der Felder auf den Zustand des Gewinners setzen und neuzeichnen
felder[0].setZustand(gewinner);
felder[0].repaint();
felder[1].setZustand(gewinner);
felder[1].repaint();
felder[2].setZustand(gewinner);
felder[2].repaint();
felder[3].setZustand(gewinner);
felder[3].repaint();
}
}
}
Java:
package vierGewinnt;
import javax.swing.JFrame;
/**
* Frameklasse
*
* Sie intialsiert das Panel und ist das Hauptfenster.
* In ihr wird das Panel hineingeladen und angezeigt.
* Weiters beinhaltet sie die main Methode welche das Frame ausführt
*
* @author Rene Polak
* @version 2010-11-17
*/
public class VGFrame extends JFrame {
// Das Panel, welches im Konstruktor in das Frame geladen wird
private VGPanel vgp;
/**
* Main methode
*
* Sie führt das Programm aus durch intialisierung des VGFrames
*
* @param args String[]; Dieser Parameter binhaltet alle Argumente die über die Konsole übergeben wurden
*/
public static void main(String[] args) {
new VGFrame(); // Initialisierung des JFrames
}
/**
* Defaultkonstruktor
*/
public VGFrame() {
// Initialisieren des JPanels
this.vgp = new VGPanel();
//hinzufügen des JPanel zum Frame
this.add(vgp);
// Titel des JFrames setzen
this.setTitle("Vier gewinnt");
// Größe des JFrames setzen
this.setSize(300,335);
// Verhalten im Fall der SchließenOperation setzen ( In dem Fall das Fenster schließen)
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
// Größenveränderung ausstellen
this.setResizable(false);
// Das JFrame sichtbar setzen
this.setVisible(true);
}
}