Subtrees hinzugefügt

This commit is contained in:
Dirk Zechnall 2025-01-05 21:22:02 +01:00
parent 155d0786a6
commit 3cc08a2004
443 changed files with 131415 additions and 0 deletions

7
Quellcodes/Alg_DS_Freecell/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
**/*.sh
**/*.class
**/*.ctxt
repo.adoc
repo_subtree.adoc
/alt
/hide

View file

@ -0,0 +1,257 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.util.*;
/**
* Das Fenster, in dem das Freecell-Spiel dargestellt wird.
* Hier sollte nichts verändert werden.
*
* @version 10.10.2020
* @author Rainer Helfrich
*/
public class FreecellFrame extends JFrame {
public FreecellFrame(FreecellGame g) {
// Frame-Initialisierung
super();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
int frameWidth = 8*Karte.CARD_WIDTH+150;
int frameHeight = 640+2*Karte.CARD_HEIGHT;
setSize(frameWidth, frameHeight);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = (d.width - getSize().width) / 2;
int y = (d.height - getSize().height) / 2;
setLocation(x, y);
setTitle("Freecell");
setResizable(false);
Container cp = getContentPane();
cp.setLayout(null);
// Anfang Komponenten
JPanel jPanel1 = new FreecellPanel(g);
jPanel1.setBounds(0, 0, frameWidth, frameHeight);
jPanel1.setOpaque(true);
cp.add(jPanel1);
// Ende Komponenten
setVisible(true);
} // end of public FreecellFrame
// Ende Methoden
private class FreecellPanel extends JPanel implements MouseListener{
FreecellGame dasSpiel;
public FreecellPanel(FreecellGame g)
{
super( null, true);
dasSpiel = g;
this.addMouseListener(this);
markiert = null;
sourceArea = -1;
sourceIndex = -1;
}
public void paint(Graphics g) {
g.setColor(new Color(0, 100, 0));
g.fillRect(0,0,getWidth(),getHeight());
for (int i = 0; i < 4; i++) {
Karte k = dasSpiel.getKarte(FreecellGame.ZELLEN, i);
if (k == null)
{
g.setColor(new Color(0, 80, 0));
g.fillRoundRect(10+(Karte.CARD_WIDTH+10)*i, 20, Karte.CARD_WIDTH, Karte.CARD_HEIGHT, 8, 8);
g.setColor(Color.BLACK);
g.drawRoundRect(10+(Karte.CARD_WIDTH+10)*i, 20, Karte.CARD_WIDTH, Karte.CARD_HEIGHT, 8, 8);
} // end of if
else
{
k.zeichne(g, 10+(Karte.CARD_WIDTH+10)*i, 20);
}
} // end of for
for (int i = 0; i < 4; i++)
{
Karte k = dasSpiel.getKarte(FreecellGame.ABLAGESTAPEL, i);
if (k == null)
{
g.setColor(new Color(0, 80, 0));
g.fillRoundRect(4*Karte.CARD_WIDTH+90+(Karte.CARD_WIDTH+10)*i, 20, Karte.CARD_WIDTH, Karte.CARD_HEIGHT, 8, 8);
g.setColor(Color.BLACK);
g.drawRoundRect(4*Karte.CARD_WIDTH+90+(Karte.CARD_WIDTH+10)*i, 20, Karte.CARD_WIDTH, Karte.CARD_HEIGHT, 8, 8);
} // end of if
else
{
k.zeichne(g, 4*Karte.CARD_WIDTH+90+(Karte.CARD_WIDTH+10)*i, 20);
}
} // end of for
for (int i = 0; i < 8; i++) {
int hoehe = dasSpiel.getStapelHoehe(i);
for (int j = 0; j < hoehe; j++)
{
Karte k = dasSpiel.getKarteInStapel(i, hoehe-1-j);
k.zeichne(g, 35+(Karte.CARD_WIDTH+10)*i, Karte.CARD_HEIGHT+55+j*30);
}
} // end of for
}
Karte markiert;
int sourceArea;
int sourceIndex;
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1)
{
int area = getArea(e.getPoint());
if (area == FreecellGame.ABLAGESTAPEL)
{
return;
}
int index = getIndex(e.getPoint(), area);
if (index == FreecellGame.KEINER)
{
return;
}
if (dasSpiel.schnellerZug(area, index))
{
if (markiert != null)
{
markiert.setMarkiert(false);
markiert = null;
}
finishMove();
}
}
}
public void mouseEntered(MouseEvent e){
}
public void mousePressed(MouseEvent e){
}
private int getArea(Point p)
{
if (p.getY() >= 20 && p.getY() <= Karte.CARD_HEIGHT+20)
{
if (p.getX() >= 10 && p.getX() <= Karte.CARD_WIDTH*4+40)
{
return FreecellGame.ZELLEN;
} // end of if
if (p.getX() >= Karte.CARD_WIDTH*4+90 && p.getY() <= Karte.CARD_WIDTH*8+120)
{
return FreecellGame.ABLAGESTAPEL;
} // end of if
} // end of if
if (p.getY() >= Karte.CARD_HEIGHT+55 && p.getX() >= 35 && p.getX() <= Karte.CARD_WIDTH*8+105)
{
return FreecellGame.KASKADEN;
}
return FreecellGame.KEINER;
}
private int getIndex(Point p, int area)
{
if (area < 0)
{
return FreecellGame.KEINER;
}
int x = (int)p.getX();
if (area == FreecellGame.ZELLEN)
{
x -= 10;
} // end of if
if (area == FreecellGame.ABLAGESTAPEL)
{
x -= 4*Karte.CARD_WIDTH+90;
} // end of if
if (area == FreecellGame.KASKADEN)
{
x -= 35;
} // end of if
if (x % (Karte.CARD_WIDTH+10) < Karte.CARD_WIDTH)
{
return x / (Karte.CARD_WIDTH+10);
} // end of if
return FreecellGame.KEINER;
}
public void mouseReleased(MouseEvent e)
{
int area = getArea(e.getPoint());
int index = getIndex(e.getPoint(), area);
if (area == FreecellGame.KEINER || index == FreecellGame.KEINER) {
if (markiert != null)
markiert.setMarkiert(false);
markiert = null;
} // end of if
else if (markiert == null)
{
if (area == FreecellGame.ZELLEN || area == FreecellGame.KASKADEN)
{
markiert = dasSpiel.getKarte(area, index);
}
if (markiert != null)
{
markiert.setMarkiert(true);
sourceArea = area;
sourceIndex = index;
} // end of if
}
else
{
if (sourceArea == area && sourceIndex == index ||
dasSpiel.verschiebe(sourceArea, sourceIndex, area, index))
{
markiert.setMarkiert(false);
markiert = null;
}
}
finishMove();
}
private void finishMove()
{
if (markiert != null)
{
repaint();
return;
}
while(true)
{
paintImmediately(0, 0, getWidth(), getHeight());
if (dasSpiel.automatischerZug())
{
try
{
Thread.sleep(300);
}
catch(Exception x)
{
}
}
else
{
break;
}
}
if (dasSpiel.istGewonnen())
{
JOptionPane.showMessageDialog(null,"Gewonnen!","Spiel beendet", JOptionPane.INFORMATION_MESSAGE);
}
}
}
} // end of class FreecellFrame

View file

@ -0,0 +1,191 @@
import java.util.ArrayList;
import java.util.Random;
/**
* Das Spielfeld selbst
*
* @author Rainer Helfrich
* @version Oktober 2020
*/
public class FreecellGame
{
/**
* Die vier Zellen oben links
*/
private Karte[] zellen;
/**
* Die vier Stapel oben rechts
*/
private Stack<Karte>[] ablagestapel;
/**
* Die acht Stapel unten, auf denen die Karten zu Beginn liegen
*/
private Stack<Karte>[] kaskaden;
/**
* Konstanten, die für die verschiedenen Ablegebereiche stehen.
*/
public static final int ZELLEN = 0;
public static final int ABLAGESTAPEL = 1;
public static final int KASKADEN = 2;
public static final int KEINER = -1;
/**
* Erzeugt ein neues Spiel mit einer zufälligen Ausgangssituation.
*/
public FreecellGame()
{
this(new Random());
}
/**
* Erzeugt ein neues Spiel mit einer vorgegebenen Nummer.
* Ein Spiel mit einer bestimmten Nummer beginnt immer in der gleichen Ausgangssituation.
* @param nummer Legt fest, welche Ausgangssituation verwendet wird.
*/
public FreecellGame(int nummer)
{
this(new Random(nummer));
}
/**
* Erzeugt ein neues Spiel
* @param r Der Zufallsgenerator, der zum zufälligen Füllen der Kaskaden verwendet wird.
*/
private FreecellGame(Random r)
{
zellen = new Karte[4];
ablagestapel = new Stack[4];
kaskaden = new Stack[8];
ArrayList<Integer> zahlen = new ArrayList<Integer>(52);
for (int i = 0; i < 52; i++) {
zahlen.add(i);
}
//# TODO: Erzeugen Sie die Stacks für den Ablagestapel und die Kaskaden
//# Ende TODO
for (int i = 0; i < kaskaden.length; i++)
{
for (int j = 0; j < ((i < 4) ? 7 : 6); j++) {
int rnd = r.nextInt(zahlen.size());
Karte k = new Karte(zahlen.get(rnd));
zahlen.remove(rnd);
if (kaskaden[i] != null)
{
kaskaden[i].push(k);
}
}
}
new FreecellFrame(this);
}
/**
* Gibt die oberste Karte aus dem angegebenen Bereich zurück
* @param bereich Kann ZELLEN, ABLAGESTAPEL oder KASKADEN sein.
* @param index Kann 0 bis 7 (für Kaskaden) bzw. 0 bis 3 (andere Bereiche) sein. Gibt an, welches Feld des Bereichs gewünscht wird.
* @return Die oberste Karte, sofern eine dort liegt. null sonst.
*/
public Karte getKarte(int bereich, int index)
{
//# TODO: Sorgen Sie dafür, dass die (oberste) Karte aus dem gewünschten Bereich zurückgegeben wird.
//# Wenn ein Stapel leer ist, soll null zurückgegeben werden.
return null;
}
/**
* Gibt die Höhe der Kaskade mit der gegebenen Nummer zurück
* @param index Kann 0 bis 7 sein. Gibt an, welche Kaskade gewünscht wird.
* @return Die Höhe der Kaskade.
*/
public int getStapelHoehe(int index)
{
//# TODO: Lassen Sie zurückgeben, wie hoch der Stapel der Kaskade mit der Nummer index ist.
return 0;
}
/**
* Gibt die n-te Karte von oben in der Kaskade mit der Nummer index zurück.
* Die Parameter sind immer in gültigen Bereichen, wenn die Methode von FreecellFrame aufgerufen wird.
* @param index Kann 0 bis 7 sein. Gibt an, welche Kaskade gewünscht wird.
* @param n Kann 0 bis getStapelHoehe(index)-1 sein. Gibt an, welche Karte darin gewünscht wird.
* @return Die gewünschte Karte
*/
public Karte getKarteInStapel(int index, int n)
{
//# TODO: Lassen Sie die n-te Karte aus der Kaskade mit der Nummer index zurückgeben.
//# n ist dabei von oben gezählt, d.h. die oberste Karte hat den Index 0.
//# n ist immer ein gültiger Index, d.h. die Zahl liegt zwischen 0 und Höhe-1
return null;
}
/**
* Gibt zurück, ob das Spiel gewonnen ist.
* @return true, wenn das Spiel gewonnen ist; false sonst
*/
public boolean istGewonnen()
{
//# TODO: Lassen Sie zurückgeben, ob das Spiel gewonnen ist.
//# Das Spiel ist gewonnen, wenn die Zellen keine Karte enthalten und alle Kaskaden leer sind.
//# Umgekehrt: Falls eine Zelle oder eine Kaskade noch eine Karte enthält, ist das Spiel noch nicht gewonnen.
return false;
}
/**
* Verschiebt eine Karte
* @param vonBereich Kann ZELLEN oder KASKADEN sein. Gibt an, <b>aus</b> welchem Bereich die Karte verschoben wird.
* @param vonIndex Kann 0 bis 7 (für Kaskaden) bzw. 0 bis 3 (für Zellen) sein. Gibt an, <b>von</b> welchem Feld des Bereichs die Karte verschoben wird.
* @param nachBereich Kann ZELLEN, ABLAGESTAPEL oder KASKADEN sein. Gibt an, <b>zu</b> welchem Bereich die Karte verschoben wird.
* @param nachIndex Kann 0 bis 7 (für Kaskaden) bzw. 0 bis 3 (andere Bereiche) sein. Gibt an, <b>zu</b> welchem Feld des Bereichs die Karte verschoben wird.
* @return true, wenn die Verschiebung gültig und erfolgreich war; false sonst
*/
public boolean verschiebe(int vonBereich, int vonIndex, int nachBereich, int nachIndex)
{
//# TODO: Verschieben Sie eine Karte.
//# vonBereich kann dabei ZELLEN oder KASKADEN sein, vonIndex ist ein jeweils gültiger Index (0 bis 3 für Zellen, 0 bis 7 für Kaskaden)
//# nachBereich kann ZELLEN, KASKADEN oder ABLAGESTAPEL sein, nachIndex ist ein jeweils gültiger Index
//# Sorgen Sie dafür, dass die Karten an Ihrem Ursprungsort auch entfernt wird!
//# Geben Sie true zurück, wenn die Verschiebung gültig und erfolgreich war, sonst false
return false;
}
/**
* Führt einen automatischen Zug aus, wenn dies möglich ist.
* @return true, wenn ein automatischer Zug möglich war; false sonst
*/
public boolean automatischerZug()
{
//# TODO: (optional) Lassen Sie einen automatischen Zug ausführen.
//# Eine Karte kann automatisch von einer Zelle oder einer Kaskade auf einen Ablagestapel gelegt werden, wenn...
//# - sie ein As oder eine 2 ist oder
//# - ihr Wert um höchstens 2 größer ist als die niederwertigste Karte auf allen Ablagestapeln
//# Geben Sie true zurück, wenn ein automatischer Zug möglich war, sonst false.
return false;
}
/**
* Führt einen schnellen Zug aus, wenn dies möglich ist.
* @param bereich Kann ZELLEN oder KASKADEN sein. Gibt an, <b>aus</b> welchem Bereich die Karte verschoben wird.
* @param index Kann 0 bis 7 (für Kaskaden) bzw. 0 bis 3 (für Zellen) sein. Gibt an, <b>von</b> welchem Feld des Bereichs die Karte verschoben wird.
* @return true, wenn ein schneller Zug möglich war; false sonst
*/
public boolean schnellerZug(int bereich, int index)
{
//# TODO: (optional) Lassen Sie einen "schnellen Zug" ausführen. "Schnelle Züge" werden durch einen Doppelklick ausgeführt.
//# Ein schneller Zug verschiebt die Karte
//# - von einer Kaskade auf eine freie Zelle oder
//# - von einer Zelle auf einen passenden Ablagestapel
//# bereich kann dabei ZELLEN oder KASKADEN sein, index ist ein jeweils gültiger Index (0 bis 3 für Zellen, 0 bis 7 für Kaskaden)
//# Geben Sie true zurück, wenn ein schneller Zug möglich war, sonst false.
return false;
}
}

View file

@ -0,0 +1,122 @@
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
/**
* Die Klasse Karte repräsentiert eine Karte im Spiel
*
* @author Rainer Helfrich
* @version Oktober 2020
*/
public class Karte
{
/**
* Konstanten für die vier Kartenfarben
*/
public static final int PIK = 0;
public static final int KREUZ = 1;
public static final int HERZ = 2;
public static final int KARO = 3;
/**
* Konstanten für die Maße der Karte
*/
public static final int CARD_WIDTH = 100;
public static final int CARD_HEIGHT = 150;
final private int farbe;
final private int wert;
private BufferedImage image;
private boolean markiert;
/**
* Erzeugt eine neue Karte
* @param nummer Das als Zahl codierte Bild der Karte
*/
public Karte(int nummer)
{
final String[] suits = { "spades", "clubs", "hearts", "diamonds"};
farbe = nummer / 13;
wert = nummer % 13 + 1;
markiert = false;
String path = "";
try
{
path = "img/"+String.format("%02d", wert)+"_of_"+suits[farbe]+".png";
image = ImageIO.read(new File(path));
}catch(Exception x){
System.out.println(path);
System.out.println(x.getMessage());
}
}
/**
* Zeichnet die Karte an der Position (x,y) auf das Graphics-Objekt g.
* Sollte nicht direkt aufgerufen werden.
* @param g Das Graphics-Objekt, auf das gezeichnet wird
* @param x Die x-Koordinate der oberen linken Ecke
* @param y Die y-Koordinate der oberen linken Ecke
*/
public void zeichne(Graphics g, int x, int y)
{
if (image != null) {
g.drawImage(image, x, y, CARD_WIDTH, CARD_HEIGHT, null);
} // end of if
else
{
g.setColor(Color.RED);
g.fillRoundRect(x, y, CARD_WIDTH, CARD_HEIGHT, 8, 8);
}
g.setColor(markiert ? Color.BLUE : Color.BLACK);
((Graphics2D)g).setStroke(new BasicStroke(markiert ? 5 : 1));
g.drawRoundRect(x, y, CARD_WIDTH, CARD_HEIGHT, 8, 8);
((Graphics2D)g).setStroke(new BasicStroke(1));
}
/**
* Gibt an, ob die Karte vom Spieler markiert (angeklickt) wurde
*/
public boolean getMarkiert()
{
return markiert;
}
/**
* Setzt die Karte auf markiert/unmarkiert
* @param b true = markiert; false = unmarkiert
*/
public void setMarkiert(boolean b)
{
markiert = b;
}
/**
* Gibt den Zahlwert der Karte zurück
* @return Der Zahlwert der Karte (1 = As, 2-10, 11 = Bube, 12 = Dame, 13 = König)
*/
public int getWert()
{
return wert;
}
/**
* Gibt die Farbe der Karte zurück
* @return Einer der Werte PIK, KREUZ, HERZ, KARO
*/
public int getFarbe()
{
return farbe;
}
/**
* Gibt zurück, ob es sich um eine rote Karte (Herz oder Karo) handelt
* @return true für eine rote Karte, false für eine schwarze
*/
public boolean istRot()
{
return farbe == HERZ || farbe == KARO;
}
}

View file

@ -0,0 +1,8 @@
PROJEKTBEZEICHNUNG: Freecell
PROJEKTZWECK: Implementieren Sie die Patience Freecell
VERSION oder DATUM: Oktober 2020
WIE IST DAS PROJEKT ZU STARTEN: Erzeugen Sie ein neues Objekt vom Typ FreecellGame (mit dem int-Parameter kann man steuern, welche Ausgangssituation erzeugt werden soll; lässt man ihn weg, ist die Ausgangssituation zufällig)
AUTOR(EN): Rainer Helfrich, ZPG Informatik
Quelle der Spielkarten-Bilder:
https://commons.wikimedia.org/wiki/File:English_pattern_playing_cards_deck.svg (Public Domain)

View file

@ -0,0 +1,32 @@
/**
* Abstrakte Basisklasse für Stacks
*
* @author Rainer Helfrich
* @version Oktober 2020
*/
public abstract class Stack<T>
{
/**
* Gibt zurück, ob der Stack leer ist
* @return true, wenn der Stack leer ist; false sonst
*/
public abstract boolean isEmpty();
/**
* Legt ein neues Element auf den Stack
* @param x Das neue Element
*/
public abstract void push(T x);
/**
* Entfernt das oberste Element vom Stack (falls der Stack nicht leer ist) und gibt es zurück
* @return Das bisherige oberste Element
*/
public abstract T pop();
/**
* Gibt das oberste Element des Stacks zurück (falls der Stack nicht leer ist)
* @return Das oberste Element
*/
public abstract T top();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View file

@ -0,0 +1,3 @@
Quelle: https://commons.wikimedia.org/wiki/File:English_pattern_playing_cards_deck.svg
Public Domain
Modifikationen von Rainer Helfrich (in Einzelbilder zerlegt)

View file

@ -0,0 +1,68 @@
#BlueJ package file
dependency1.from=FreecellFrame
dependency1.to=FreecellGame
dependency1.type=UsesDependency
dependency2.from=FreecellFrame
dependency2.to=Karte
dependency2.type=UsesDependency
dependency3.from=FreecellGame
dependency3.to=Karte
dependency3.type=UsesDependency
dependency4.from=FreecellGame
dependency4.to=Stack
dependency4.type=UsesDependency
dependency5.from=FreecellGame
dependency5.to=FreecellFrame
dependency5.type=UsesDependency
editor.fx.0.height=0
editor.fx.0.width=0
editor.fx.0.x=0
editor.fx.0.y=0
objectbench.height=93
objectbench.width=760
package.divider.horizontal=0.6
package.divider.vertical=0.8
package.editor.height=393
package.editor.width=649
package.editor.x=340
package.editor.y=126
package.frame.height=600
package.frame.width=800
package.numDependencies=5
package.numTargets=4
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.height=58
readme.name=@README
readme.width=47
readme.x=10
readme.y=10
target1.height=50
target1.name=FreecellFrame
target1.showInterface=false
target1.type=ClassTarget
target1.width=110
target1.x=130
target1.y=20
target2.height=50
target2.name=Karte
target2.showInterface=false
target2.type=ClassTarget
target2.width=80
target2.x=400
target2.y=90
target3.height=50
target3.name=FreecellGame
target3.showInterface=false
target3.type=ClassTarget
target3.width=110
target3.x=240
target3.y=190
target4.height=50
target4.name=Stack
target4.showInterface=false
target4.type=AbstractTarget
target4.width=80
target4.x=400
target4.y=20

View file

@ -0,0 +1,101 @@
/**
* Ein Stack basierend auf einem Array
*
* @author Rainer Helfrich
* @version Oktober 2020
*/
public class ArrayStack<T> extends Stack<T>
{
/**
* Enthält die Nutzdaten
*/
private Object[] daten;
/**
* Die Zahl gibt an, wie viele Elemente auf dem Stack liegen und damit auch,
* wie viele Werte im Datenarray gültig sind.
*/
private int anzahl;
/**
* Erzeugt einen neuen leeren Stack
*/
public ArrayStack()
{
daten = new Object[10];
anzahl = 0;
}
/**
* Gibt das oberste Element des Stacks zurück (falls der Stack nicht leer ist)
* @return Das oberste Element
*/
public T top()
{
if (!isEmpty())
{
return (T)daten[anzahl-1];
}
return null;
}
/**
* Entfernt das oberste Element vom Stack (falls der Stack nicht leer ist) und gibt es zurück
* @return Das bisherige oberste Element
*/
public T pop()
{
if (!isEmpty())
{
anzahl--;
return (T)daten[anzahl];
}
return null;
}
/**
* Legt ein neues Element auf den Stack
* @param x Das neue Element
*/
public void push(T wert)
{
if (anzahl == daten.length)
{
Object[] tmp = new Object[2*daten.length];
System.arraycopy(daten, 0, tmp, 0, daten.length);
daten = tmp;
}
daten[anzahl] = wert;
anzahl++;
}
/**
* Gibt zurück, ob der Stack leer ist
* @return true, wenn der Stack leer ist; false sonst
*/
public boolean isEmpty()
{
return anzahl == 0;
}
/**
* Gibt den Stack in String-Form aus.
* @return Die String-Repräsentation des Stacks
*/
@Override
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("[ ");
for (int i = 0; i < anzahl; i++)
{
if (i > 0)
{
b.append(", ");
}
b.append(daten[i]);
}
b.append(" <");
return b.toString();
}
}

View file

@ -0,0 +1,257 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.util.*;
/**
* Das Fenster, in dem das Freecell-Spiel dargestellt wird.
* Hier sollte nichts verändert werden.
*
* @version 10.10.2020
* @author Rainer Helfrich
*/
public class FreecellFrame extends JFrame {
public FreecellFrame(FreecellGame g) {
// Frame-Initialisierung
super();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
int frameWidth = 8*Karte.CARD_WIDTH+150;
int frameHeight = 640+2*Karte.CARD_HEIGHT;
setSize(frameWidth, frameHeight);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = (d.width - getSize().width) / 2;
int y = (d.height - getSize().height) / 2;
setLocation(x, y);
setTitle("Freecell");
setResizable(false);
Container cp = getContentPane();
cp.setLayout(null);
// Anfang Komponenten
JPanel jPanel1 = new FreecellPanel(g);
jPanel1.setBounds(0, 0, frameWidth, frameHeight);
jPanel1.setOpaque(true);
cp.add(jPanel1);
// Ende Komponenten
setVisible(true);
} // end of public FreecellFrame
// Ende Methoden
private class FreecellPanel extends JPanel implements MouseListener{
FreecellGame dasSpiel;
public FreecellPanel(FreecellGame g)
{
super( null, true);
dasSpiel = g;
this.addMouseListener(this);
markiert = null;
sourceArea = -1;
sourceIndex = -1;
}
public void paint(Graphics g) {
g.setColor(new Color(0, 100, 0));
g.fillRect(0,0,getWidth(),getHeight());
for (int i = 0; i < 4; i++) {
Karte k = dasSpiel.getKarte(FreecellGame.ZELLEN, i);
if (k == null)
{
g.setColor(new Color(0, 80, 0));
g.fillRoundRect(10+(Karte.CARD_WIDTH+10)*i, 20, Karte.CARD_WIDTH, Karte.CARD_HEIGHT, 8, 8);
g.setColor(Color.BLACK);
g.drawRoundRect(10+(Karte.CARD_WIDTH+10)*i, 20, Karte.CARD_WIDTH, Karte.CARD_HEIGHT, 8, 8);
} // end of if
else
{
k.zeichne(g, 10+(Karte.CARD_WIDTH+10)*i, 20);
}
} // end of for
for (int i = 0; i < 4; i++)
{
Karte k = dasSpiel.getKarte(FreecellGame.ABLAGESTAPEL, i);
if (k == null)
{
g.setColor(new Color(0, 80, 0));
g.fillRoundRect(4*Karte.CARD_WIDTH+90+(Karte.CARD_WIDTH+10)*i, 20, Karte.CARD_WIDTH, Karte.CARD_HEIGHT, 8, 8);
g.setColor(Color.BLACK);
g.drawRoundRect(4*Karte.CARD_WIDTH+90+(Karte.CARD_WIDTH+10)*i, 20, Karte.CARD_WIDTH, Karte.CARD_HEIGHT, 8, 8);
} // end of if
else
{
k.zeichne(g, 4*Karte.CARD_WIDTH+90+(Karte.CARD_WIDTH+10)*i, 20);
}
} // end of for
for (int i = 0; i < 8; i++) {
int hoehe = dasSpiel.getStapelHoehe(i);
for (int j = 0; j < hoehe; j++)
{
Karte k = dasSpiel.getKarteInStapel(i, hoehe-1-j);
k.zeichne(g, 35+(Karte.CARD_WIDTH+10)*i, Karte.CARD_HEIGHT+55+j*30);
}
} // end of for
}
Karte markiert;
int sourceArea;
int sourceIndex;
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1)
{
int area = getArea(e.getPoint());
if (area == FreecellGame.ABLAGESTAPEL)
{
return;
}
int index = getIndex(e.getPoint(), area);
if (index == FreecellGame.KEINER)
{
return;
}
if (dasSpiel.schnellerZug(area, index))
{
if (markiert != null)
{
markiert.setMarkiert(false);
markiert = null;
}
finishMove();
}
}
}
public void mouseEntered(MouseEvent e){
}
public void mousePressed(MouseEvent e){
}
private int getArea(Point p)
{
if (p.getY() >= 20 && p.getY() <= Karte.CARD_HEIGHT+20)
{
if (p.getX() >= 10 && p.getX() <= Karte.CARD_WIDTH*4+40)
{
return FreecellGame.ZELLEN;
} // end of if
if (p.getX() >= Karte.CARD_WIDTH*4+90 && p.getY() <= Karte.CARD_WIDTH*8+120)
{
return FreecellGame.ABLAGESTAPEL;
} // end of if
} // end of if
if (p.getY() >= Karte.CARD_HEIGHT+55 && p.getX() >= 35 && p.getX() <= Karte.CARD_WIDTH*8+105)
{
return FreecellGame.KASKADEN;
}
return FreecellGame.KEINER;
}
private int getIndex(Point p, int area)
{
if (area < 0)
{
return FreecellGame.KEINER;
}
int x = (int)p.getX();
if (area == FreecellGame.ZELLEN)
{
x -= 10;
} // end of if
if (area == FreecellGame.ABLAGESTAPEL)
{
x -= 4*Karte.CARD_WIDTH+90;
} // end of if
if (area == FreecellGame.KASKADEN)
{
x -= 35;
} // end of if
if (x % (Karte.CARD_WIDTH+10) < Karte.CARD_WIDTH)
{
return x / (Karte.CARD_WIDTH+10);
} // end of if
return FreecellGame.KEINER;
}
public void mouseReleased(MouseEvent e)
{
int area = getArea(e.getPoint());
int index = getIndex(e.getPoint(), area);
if (area == FreecellGame.KEINER || index == FreecellGame.KEINER) {
if (markiert != null)
markiert.setMarkiert(false);
markiert = null;
} // end of if
else if (markiert == null)
{
if (area == FreecellGame.ZELLEN || area == FreecellGame.KASKADEN)
{
markiert = dasSpiel.getKarte(area, index);
}
if (markiert != null)
{
markiert.setMarkiert(true);
sourceArea = area;
sourceIndex = index;
} // end of if
}
else
{
if (sourceArea == area && sourceIndex == index ||
dasSpiel.verschiebe(sourceArea, sourceIndex, area, index))
{
markiert.setMarkiert(false);
markiert = null;
}
}
finishMove();
}
private void finishMove()
{
if (markiert != null)
{
repaint();
return;
}
while(true)
{
paintImmediately(0, 0, getWidth(), getHeight());
if (dasSpiel.automatischerZug())
{
try
{
Thread.sleep(300);
}
catch(Exception x)
{
}
}
else
{
break;
}
}
if (dasSpiel.istGewonnen())
{
JOptionPane.showMessageDialog(null,"Gewonnen!","Spiel beendet", JOptionPane.INFORMATION_MESSAGE);
}
}
}
} // end of class FreecellFrame

View file

@ -0,0 +1,378 @@
import java.util.ArrayList;
import java.util.Random;
/**
* Das Spielfeld selbst
*
* @author Rainer Helfrich
* @version Oktober 2020
*/
public class FreecellGame
{
/**
* Die vier Zellen oben links
*/
private Karte[] zellen;
/**
* Die vier Stapel oben rechts
*/
private Stack<Karte>[] ablagestapel;
/**
* Die acht Stapel unten, auf denen die Karten zu Beginn liegen
*/
private Stack<Karte>[] kaskaden;
/**
* Konstanten, die für die verschiedenen Ablegebereiche stehen.
*/
public static final int ZELLEN = 0;
public static final int ABLAGESTAPEL = 1;
public static final int KASKADEN = 2;
public static final int KEINER = -1;
/**
* Erzeugt ein neues Spiel mit einer zufälligen Ausgangssituation.
*/
public FreecellGame()
{
this(new Random());
}
/**
* Erzeugt ein neues Spiel mit einer vorgegebenen Nummer.
* Ein Spiel mit einer bestimmten Nummer beginnt immer in der gleichen Ausgangssituation.
* @param nummer Legt fest, welche Ausgangssituation verwendet wird.
*/
public FreecellGame(int nummer)
{
this(new Random(nummer));
}
/**
* Erzeugt ein neues Spiel
* @param r Der Zufallsgenerator, der zum zufälligen Füllen der Kaskaden verwendet wird.
*/
private FreecellGame(Random r)
{
zellen = new Karte[4];
ablagestapel = new Stack[4];
kaskaden = new Stack[8];
ArrayList<Integer> zahlen = new ArrayList<Integer>(52);
for (int i = 0; i < 52; i++) {
zahlen.add(i);
}
//# TODO: Erzeugen Sie die Stacks für den Ablagestapel und die Kaskaden
for (int i = 0; i < ablagestapel.length; i++) {
ablagestapel[i] = new ArrayStack<Karte>();
}
for (int i = 0; i < kaskaden.length; i++) {
kaskaden[i] = new ArrayStack<Karte>();
}
//# Ende TODO
for (int i = 0; i < kaskaden.length; i++)
{
for (int j = 0; j < ((i < 4) ? 7 : 6); j++) {
int rnd = r.nextInt(zahlen.size());
Karte k = new Karte(zahlen.get(rnd));
zahlen.remove(rnd);
if (kaskaden[i] != null)
{
kaskaden[i].push(k);
}
}
}
new FreecellFrame(this);
}
/**
* Gibt die oberste Karte aus dem angegebenen Bereich zurück
* @param bereich Kann ZELLEN, ABLAGESTAPEL oder KASKADEN sein.
* @param index Kann 0 bis 7 (für Kaskaden) bzw. 0 bis 3 (andere Bereiche) sein. Gibt an, welches Feld des Bereichs gewünscht wird.
* @return Die oberste Karte, sofern eine dort liegt. null sonst.
*/
public Karte getKarte(int bereich, int index)
{
//# TODO: Sorgen Sie dafür, dass die (oberste) Karte aus dem gewünschten Bereich zurückgegeben wird.
//# Wenn ein Stapel leer ist, soll null zurückgegeben werden.
if (bereich == ZELLEN)
{
return zellen[index];
}
if (bereich == KASKADEN && !kaskaden[index].isEmpty())
{
return kaskaden[index].top();
}
if (bereich == ABLAGESTAPEL && !ablagestapel[index].isEmpty())
{
return ablagestapel[index].top();
}
return null;
}
/**
* Gibt die Höhe der Kaskade mit der gegebenen Nummer zurück
* @param index Kann 0 bis 7 sein. Gibt an, welche Kaskade gewünscht wird.
* @return Die Höhe der Kaskade.
*/
public int getStapelHoehe(int index)
{
//# TODO: Lassen Sie zurückgeben, wie hoch der Stapel der Kaskade mit der Nummer index ist.
int size = 0;
Stack<Karte> temp = new ArrayStack<Karte>();
Stack<Karte> s = kaskaden[index];
while(!s.isEmpty())
{
temp.push(s.pop());
size++;
}
while(!temp.isEmpty())
{
s.push(temp.pop());
}
return size;
}
/**
* Gibt die n-te Karte von oben in der Kaskade mit der Nummer index zurück.
* Die Parameter sind immer in gültigen Bereichen, wenn die Methode von FreecellFrame aufgerufen wird.
* @param index Kann 0 bis 7 sein. Gibt an, welche Kaskade gewünscht wird.
* @param n Kann 0 bis getStapelHoehe(index)-1 sein. Gibt an, welche Karte darin gewünscht wird.
* @return Die gewünschte Karte
*/
public Karte getKarteInStapel(int index, int n)
{
//# TODO: Lassen Sie die n-te Karte aus der Kaskade mit der Nummer index zurückgeben.
//# n ist dabei von oben gezählt, d.h. die oberste Karte hat den Index 0.
//# n ist immer ein gültiger Index, d.h. die Zahl liegt zwischen 0 und Höhe-1
Stack<Karte> temp = new ArrayStack<Karte>();
Stack<Karte> s = kaskaden[index];
for (int i = 0; i < n; i++)
{
temp.push(s.pop());
}
Karte k = s.top();
while(!temp.isEmpty())
{
s.push(temp.pop());
}
return k;
}
/**
* Gibt zurück, ob das Spiel gewonnen ist.
* @return true, wenn das Spiel gewonnen ist; false sonst
*/
public boolean istGewonnen()
{
//# TODO: Lassen Sie zurückgeben, ob das Spiel gewonnen ist.
//# Das Spiel ist gewonnen, wenn die Zellen keine Karte enthalten und alle Kaskaden leer sind.
//# Umgekehrt: Falls eine Zelle oder eine Kaskade noch eine Karte enthält, ist das Spiel noch nicht gewonnen.
for (Karte k : zellen)
{
if (k != null)
{
return false;
}
}
for (Stack<Karte> s : kaskaden)
{
if (!s.isEmpty())
{
return false;
}
}
return true;
}
/**
* Verschiebt eine Karte
* @param vonBereich Kann ZELLEN oder KASKADEN sein. Gibt an, <b>aus</b> welchem Bereich die Karte verschoben wird.
* @param vonIndex Kann 0 bis 7 (für Kaskaden) bzw. 0 bis 3 (für Zellen) sein. Gibt an, <b>von</b> welchem Feld des Bereichs die Karte verschoben wird.
* @param nachBereich Kann ZELLEN, ABLAGESTAPEL oder KASKADEN sein. Gibt an, <b>zu</b> welchem Bereich die Karte verschoben wird.
* @param nachIndex Kann 0 bis 7 (für Kaskaden) bzw. 0 bis 3 (andere Bereiche) sein. Gibt an, <b>zu</b> welchem Feld des Bereichs die Karte verschoben wird.
* @return true, wenn die Verschiebung gültig und erfolgreich war; false sonst
*/
public boolean verschiebe(int vonBereich, int vonIndex, int nachBereich, int nachIndex)
{
//# TODO: Verschieben Sie eine Karte.
//# vonBereich kann dabei ZELLEN oder KASKADEN sein, vonIndex ist ein jeweils gültiger Index (0 bis 3 für Zellen, 0 bis 7 für Kaskaden)
//# nachBereich kann ZELLEN, KASKADEN oder ABLAGESTAPEL sein, nachIndex ist ein jeweils gültiger Index
//# Sorgen Sie dafür, dass die Karten an Ihrem Ursprungsort auch entfernt wird!
//# Geben Sie true zurück, wenn die Verschiebung gültig und erfolgreich war, sonst false
Karte k = null;
if (vonBereich == ZELLEN)
{
k = zellen[vonIndex];
}
else if (vonBereich == KASKADEN && !kaskaden[vonIndex].isEmpty())
{
k = kaskaden[vonIndex].top();
}
else
{
return false;
}
boolean erfolg = false;
if (nachBereich == ZELLEN)
{
erfolg = (zellen[nachIndex] == null);
if (erfolg)
{
zellen[nachIndex] = k;
}
}
if (nachBereich == KASKADEN)
{
if (kaskaden[nachIndex].isEmpty())
{
erfolg = true;
}
else
{
Karte kk = kaskaden[nachIndex].top();
erfolg = (kk.getWert() == k.getWert()+1 && kk.istRot() != k.istRot());
}
if (erfolg)
{
kaskaden[nachIndex].push(k);
}
}
if (nachBereich == ABLAGESTAPEL)
{
if (ablagestapel[nachIndex].isEmpty())
{
erfolg = (k.getWert() == 1);
}
else
{
Karte kk = ablagestapel[nachIndex].top();
erfolg = (kk.getFarbe() == k.getFarbe() && kk.getWert() == k.getWert()-1);
}
if (erfolg)
{
ablagestapel[nachIndex].push(k);
}
}
if (erfolg)
{
if (vonBereich == ZELLEN)
{
zellen[vonIndex] = null;
}
else
{
kaskaden[vonIndex].pop();
}
}
return erfolg;
}
/**
* Führt einen automatischen Zug aus, wenn dies möglich ist.
* @return true, wenn ein automatischer Zug möglich war; false sonst
*/
public boolean automatischerZug()
{
//# TODO: (optional) Lassen Sie einen automatischen Zug ausführen.
//# Eine Karte kann automatisch von einer Zelle oder einer Kaskade auf einen Ablagestapel gelegt werden, wenn...
//# - sie ein As oder eine 2 ist oder
//# - ihr Wert um höchstens 2 größer ist als die niederwertigste Karte auf allen Ablagestapeln
//# Geben Sie true zurück, wenn ein automatischer Zug möglich war, sonst false.
int min = 15;
for (Stack<Karte> s : ablagestapel)
{
if (s.isEmpty())
{
min = 0;
break;
}
if (s.top().getWert() < min)
{
min = s.top().getWert();
}
}
for (int i = 0; i < zellen.length; i++)
{
if (zellen[i] != null && zellen[i].getWert() <= min+2 && verschiebeAutomatisch(zellen[i]))
{
zellen[i] = null;
return true;
}
}
for (Stack<Karte> s : kaskaden)
{
if (!s.isEmpty() && s.top().getWert() <= min+2 && verschiebeAutomatisch(s.top()))
{
s.pop();
return true;
}
}
return false;
}
private boolean verschiebeAutomatisch(Karte k)
{
if (k.getWert() == 1)
{
for (Stack<Karte> s: ablagestapel)
{
if (s.isEmpty())
{
s.push(k);
return true;
}
}
}
else
{
for (Stack<Karte> s: ablagestapel)
{
if (!s.isEmpty() && s.top().getFarbe() == k.getFarbe() && s.top().getWert()+1 == k.getWert())
{
s.push(k);
return true;
}
}
}
return false;
}
/**
* Führt einen schnellen Zug aus, wenn dies möglich ist.
* @param bereich Kann ZELLEN oder KASKADEN sein. Gibt an, <b>aus</b> welchem Bereich die Karte verschoben wird.
* @param index Kann 0 bis 7 (für Kaskaden) bzw. 0 bis 3 (für Zellen) sein. Gibt an, <b>von</b> welchem Feld des Bereichs die Karte verschoben wird.
* @return true, wenn ein schneller Zug möglich war; false sonst
*/
public boolean schnellerZug(int bereich, int index)
{
//# TODO: (optional) Lassen Sie einen "schnellen Zug" ausführen. "Schnelle Züge" werden durch einen Doppelklick ausgeführt.
//# Ein schneller Zug verschiebt die Karte
//# - von einer Kaskade auf eine freie Zelle oder
//# - von einer Zelle auf einen passenden Ablagestapel
//# bereich kann dabei ZELLEN oder KASKADEN sein, index ist ein jeweils gültiger Index (0 bis 3 für Zellen, 0 bis 7 für Kaskaden)
//# Geben Sie true zurück, wenn ein schneller Zug möglich war, sonst false.
if (bereich == ZELLEN && zellen[index] != null)
{
Karte k = zellen[index];
zellen[index] = null;
return verschiebeAutomatisch(k);
}
if (bereich == KASKADEN && !kaskaden[index].isEmpty())
{
for (int i = 0; i < zellen.length; i++)
{
if (zellen[i] == null)
{
zellen[i] = kaskaden[index].pop();
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,116 @@
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
public class Karte
{
/**
* Konstanten für die vier Kartenfarben
*/
public static final int PIK = 0;
public static final int KREUZ = 1;
public static final int HERZ = 2;
public static final int KARO = 3;
/**
* Konstanten für die Maße der Karte
*/
public static final int CARD_WIDTH = 100;
public static final int CARD_HEIGHT = 150;
final private int farbe;
final private int wert;
private BufferedImage image;
private boolean markiert;
/**
* Erzeugt eine neue Karte
* @param nummer Das als Zahl codierte Bild der Karte
*/
public Karte(int nummer)
{
final String[] suits = { "spades", "clubs", "hearts", "diamonds"};
farbe = nummer / 13;
wert = nummer % 13 + 1;
markiert = false;
String path = "";
try
{
path = "img/"+String.format("%02d", wert)+"_of_"+suits[farbe]+".png";
image = ImageIO.read(new File(path));
}catch(Exception x){
System.out.println(path);
System.out.println(x.getMessage());
}
}
/**
* Zeichnet die Karte an der Position (x,y) auf das Graphics-Objekt g.
* Sollte nicht direkt aufgerufen werden.
* @param g Das Graphics-Objekt, auf das gezeichnet wird
* @param x Die x-Koordinate der oberen linken Ecke
* @param y Die y-Koordinate der oberen linken Ecke
*/
public void zeichne(Graphics g, int x, int y)
{
if (image != null) {
g.drawImage(image, x, y, CARD_WIDTH, CARD_HEIGHT, null);
} // end of if
else
{
g.setColor(Color.RED);
g.fillRoundRect(x, y, CARD_WIDTH, CARD_HEIGHT, 8, 8);
}
g.setColor(markiert ? Color.BLUE : Color.BLACK);
((Graphics2D)g).setStroke(new BasicStroke(markiert ? 5 : 1));
g.drawRoundRect(x, y, CARD_WIDTH, CARD_HEIGHT, 8, 8);
((Graphics2D)g).setStroke(new BasicStroke(1));
}
/**
* Gibt an, ob die Karte vom Spieler markiert (angeklickt) wurde
*/
public boolean getMarkiert()
{
return markiert;
}
/**
* Setzt die Karte auf markiert/unmarkiert
* @param b true = markiert; false = unmarkiert
*/
public void setMarkiert(boolean b)
{
markiert = b;
}
/**
* Gibt den Zahlwert der Karte zurück
* @return Der Zahlwert der Karte (1 = As, 2-10, 11 = Bube, 12 = Dame, 13 = König)
*/
public int getWert()
{
return wert;
}
/**
* Gibt die Farbe der Karte zurück
* @return Einer der Werte PIK, KREUZ, HERZ, KARO
*/
public int getFarbe()
{
return farbe;
}
/**
* Gibt zurück, ob es sich um eine rote Karte (Herz oder Karo) handelt
* @return true für eine rote Karte, false für eine schwarze
*/
public boolean istRot()
{
return farbe == HERZ || farbe == KARO;
}
}

View file

@ -0,0 +1,8 @@
PROJEKTBEZEICHNUNG: Freecell
PROJEKTZWECK: Implementieren Sie die Patience Freecell
VERSION oder DATUM: Oktober 2020
WIE IST DAS PROJEKT ZU STARTEN: Erzeugen Sie ein neues Objekt vom Typ FreecellGame (mit dem int-Parameter kann man steuern, welche Ausgangssituation erzeugt werden soll; lässt man ihn weg, ist die Ausgangssituation zufällig)
AUTOR(EN): Rainer Helfrich, ZPG Informatik
Quelle der Spielkarten-Bilder:
https://commons.wikimedia.org/wiki/File:English_pattern_playing_cards_deck.svg (Public Domain)

View file

@ -0,0 +1,32 @@
/**
* Abstrakte Basisklasse für Stacks
*
* @author Rainer Helfrich
* @version Oktober 2020
*/
public abstract class Stack<T>
{
/**
* Gibt zurück, ob der Stack leer ist
* @return true, wenn der Stack leer ist; false sonst
*/
public abstract boolean isEmpty();
/**
* Legt ein neues Element auf den Stack
* @param x Das neue Element
*/
public abstract void push(T x);
/**
* Entfernt das oberste Element vom Stack (falls der Stack nicht leer ist) und gibt es zurück
* @return Das bisherige oberste Element
*/
public abstract T pop();
/**
* Gibt das oberste Element des Stacks zurück (falls der Stack nicht leer ist)
* @return Das oberste Element
*/
public abstract T top();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Some files were not shown because too many files have changed in this diff Show more