// Sudoku-Projekt.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import javax.swing.event.*;
public class Sudoku extends JApplet //Hauptklasse => public von der Klasse JApplet (J => swing) abgeleitet
implements ActionListener{
// Member Variablen black
int Zahl = 11; //=> auf keinen Button (0-9) geklickt
int ZeilenIndex, SpaltenIndex, InputWert = 10;
//Public Variablen
public int TastenCode, AktivZeile = 9, AktivSpalte = 9;
public int EnteredFeldZeile = 9, EnteredFeldSpalte = 9; // Wert von 9 zuweisen => keine Spalte ausgewählt
public int ZahlCursor = 10, ZahlFeld;
public int[][] SpielFeldWerte = new int[9][9];//Array anlegen in dem die Werten des Spieles abgelegt werden
public int[][] SolvedWerte = new int[9][9];//Array in dem die Werte des Solvers abgelegt werden
//Konstanten
final int x0 = 300, y0 = 300; //Null-Koordinaten => Konstanten (final)
//Ursprung umsetzen: g.translate(150,150); => in paint Graphics() methode
//Schrift Arten
Font Ueberschrift = new Font("Serif", Font.BOLD, 20);
Font NormalSchrift = new Font("Monospaced", Font.PLAIN, 20);
Font fontTitle = new Font ("SansSerif", Font.BOLD, 20);
Font FeldAusgabe = new Font("Monospaced",Font.PLAIN + Font.ITALIC,17);
//Hintergrundfarben definieren:
Color BackCol = new Color(93,30,60);
Color GenCol = new Color(210,75,9);
Color SolCol = new Color(43,143,238);
Color HelCol = new Color(194,221,39);
//Panels
JPanel SudokuContent = new JPanel();
JPanel SpielFeld = new JPanel();
JPanel OLFeld = new JPanel();
JPanel OMFeld = new JPanel();
JPanel ORFeld = new JPanel();
JPanel MLFeld = new JPanel();
JPanel MMFeld = new JPanel();
JPanel MRFeld = new JPanel();
JPanel ULFeld = new JPanel();
JPanel UMFeld = new JPanel();
JPanel URFeld = new JPanel();
JPanel SudokuLöser = new JPanel();
CWait Delay = new CWait();
//CSudokuFeld c = new CSudokuFeld(); //Neue Instanz (c) der Klasse PaintCanvas
CSudokuSolve Solve = new CSudokuSolve();
//Buttons
private JButton Generator, Solver, Help, Lösen; //Funktionen Auswhal
JScrollBar SetDelay = new JScrollBar(SwingConstants.HORIZONTAL);
private JButton Z0, Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9;//ZahlenEingabe
public CPaintPanel[][] PanelFeld = new CPaintPanel[9][9];
/***************************************************************/
public void init(){
//SpielFeldWerte reseten:
for(int Zeilen = 0; Zeilen<9; Zeilen++){
for(int Spalten = 0; Spalten < 9; Spalten++){
SpielFeldWerte[Zeilen][Spalten] = 0; //Werte (initialisieren) löschen (0 => keine mögliche Zahl)
}
}
setSize(600,600);
//Haupt Panel => Beinhalted alle andern Panel
SudokuContent.setLayout(new FlowLayout());//Neuer Layout Manager einrichten
SudokuContent.setBackground(BackCol);//Hintergrundfarbe
//Die andern Panel einfügen
SudokuContent.add(SpielFeld);
SudokuContent.add(SudokuLöser);
add(SudokuContent);//HauptPanel einfügen
Lösen = new JButton("Lösen");
Lösen.addActionListener(this);
SudokuLöser.setLayout(new GridLayout(2,1,2,2));
SudokuLöser.setPreferredSize(new Dimension(150,60));
SudokuLöser.add(Lösen);
SudokuLöser.add(SetDelay);
//Das Pane Spielfeld enthält die neun Button Quadrate)
SpielFeld.setLayout(new GridLayout(3,3,2,2));
SpielFeld.setPreferredSize(new Dimension(362,362));
SpielFeld.setBackground(BackCol);
SpielFeld.setBorder(BorderFactory.createMatteBorder(15, 20, 10, 20, BackCol)); //Rahmen um das SpielFeld zeichnen
SpielFeld.setFont(NormalSchrift);
SpielFeld.add(OLFeld);
SpielFeld.add(OMFeld);
SpielFeld.add(ORFeld);
SpielFeld.add(MLFeld);
SpielFeld.add(MMFeld);
SpielFeld.add(MRFeld);
SpielFeld.add(ULFeld);
SpielFeld.add(UMFeld);
SpielFeld.add(URFeld);
//***************Button Quadrate: Alle Button Quadrate enthalten neun Buttons*********************
//Quadrat Oben Links
OLFeld.setLayout(new GridLayout(3,3,1,1));
OLFeld.setBackground(Color.black);
OLFeld.setFont(NormalSchrift);
for(ZeilenIndex = 0;ZeilenIndex<3;ZeilenIndex++){
for(SpaltenIndex = 0;SpaltenIndex<3;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
OLFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
//Quadrat Oben Mitte
OMFeld.setLayout(new GridLayout(3,3,1,1));
OMFeld.setBackground(Color.black);
OMFeld.setFont(NormalSchrift);
for(ZeilenIndex = 0;ZeilenIndex<3;ZeilenIndex++){
for(SpaltenIndex = 3;SpaltenIndex<6;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
OMFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
//Quadrat Oben Rechts
ORFeld.setLayout(new GridLayout(3,3,1,1));
ORFeld.setBackground(Color.black);
ORFeld.setFont(NormalSchrift);
for(ZeilenIndex = 0;ZeilenIndex<3;ZeilenIndex++){
for(SpaltenIndex = 6;SpaltenIndex<9;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
ORFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
//Quadrat Mitte Links
MLFeld.setLayout(new GridLayout(3,3,1,1));
MLFeld.setBackground(Color.black);
MLFeld.setFont(NormalSchrift);
for(ZeilenIndex = 3;ZeilenIndex<6;ZeilenIndex++){
for(SpaltenIndex = 0;SpaltenIndex<3;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
MLFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
//Quadrat Mitte Mitte
MMFeld.setLayout(new GridLayout(3,3,1,1));
MMFeld.setBackground(Color.black);
MMFeld.setFont(NormalSchrift);
for(ZeilenIndex = 3;ZeilenIndex<6;ZeilenIndex++){
for(SpaltenIndex = 3;SpaltenIndex<6;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
MMFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
//Quadrat Mitte Rechts
MRFeld.setLayout(new GridLayout(3,3,1,1));
MRFeld.setBackground(Color.black);
MRFeld.setFont(NormalSchrift);
for(ZeilenIndex = 3;ZeilenIndex<6;ZeilenIndex++){
for(SpaltenIndex = 6;SpaltenIndex<9;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
MRFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
//Quadrat Unten Links
ULFeld.setLayout(new GridLayout(3,3,1,1));
ULFeld.setBackground(Color.black);
ULFeld.setFont(NormalSchrift);
for(ZeilenIndex = 6;ZeilenIndex<9;ZeilenIndex++){
for(SpaltenIndex = 0;SpaltenIndex<3;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
ULFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
//Quadrat Unten Mitte
UMFeld.setLayout(new GridLayout(3,3,1,1));
UMFeld.setBackground(Color.black);
UMFeld.setFont(NormalSchrift);
for(ZeilenIndex = 6;ZeilenIndex<9;ZeilenIndex++){
for(SpaltenIndex = 3;SpaltenIndex<6;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
UMFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
//Quadrat Unten Rechts
URFeld.setLayout(new GridLayout(3,3,1,1));
URFeld.setBackground(Color.black);
URFeld.setFont(NormalSchrift);
for(ZeilenIndex = 6;ZeilenIndex<9;ZeilenIndex++){
for(SpaltenIndex = 6;SpaltenIndex<9;SpaltenIndex++){
PanelFeld[ZeilenIndex][SpaltenIndex] = new CPaintPanel();
PanelFeld[ZeilenIndex][SpaltenIndex].setFont(FeldAusgabe);
PanelFeld[ZeilenIndex][SpaltenIndex].ZahlOut(0);//initialisieren
URFeld.add(PanelFeld[ZeilenIndex][SpaltenIndex]);
}
}
}
public void paint(Graphics g){
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == Lösen){
//SolvedWerte mit Original-Werten überschreiben:
for(int Zeilen = 0; Zeilen<9; Zeilen++){
for(int Spalten = 0; Spalten < 9; Spalten++){
SolvedWerte[Zeilen][Spalten] = SpielFeldWerte[Zeilen][Spalten];
}
}
Solve.SolveBacktrack(0,0);
//Original-Werte mit Solved Werte initialisieren:
for(int Zeilen = 0; Zeilen<9; Zeilen++){
for(int Spalten = 0; Spalten < 9; Spalten++){
SpielFeldWerte[Zeilen][Spalten] = SolvedWerte[Zeilen][Spalten];
}
}
}
}
/*******************************************/
class CPaintPanel extends JPanel
{
private int OutputZahl;
private Color SchriftFarbe;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(SchriftFarbe);
if((OutputZahl < 10) && (OutputZahl > 0)){//Wenn OutputZahl gültig
g.drawString(""+OutputZahl,10,25);//Zahl ausgeben
}
if(OutputZahl == 0){ // Wenn Delete-Button betätigt oder keine Zahl eingegeben
g.drawString(""+OutputZahl,12,25);//Die Zahl mit der Hintergrundfarbe überschreiben
}
}
public void ZahlOut(int Zahl){ //Feld nicht Aktiv
OutputZahl = Zahl;
setBackground(Color.blue);
SchriftFarbe = Color.white; //Standart-Farbe
if(OutputZahl == 0){
SchriftFarbe = Color.blue;//Farbe des Hintergrund => unsichtbar
}
repaint();
}
public void ButActiv(int AZahl){ //Feld Aktiv
OutputZahl = AZahl;
setBackground(Color.white);
SchriftFarbe = Color.blue; //Output-Farbe
if(OutputZahl == 0){
SchriftFarbe = Color.white; //Farbe des Hintergrund => unsichtbar
}
repaint();
}
}/*****************************************/
/********************************/
class CSudokuSolve{
CSudokuSolve(){//Konstruktor
}
//Löst ein Sudoku mit der Backtracking-Methode
public void SolveBacktrack(int Zeile, int Spalte){
int ZeilenNr = Zeile;
int SpaltenNr = Spalte;
boolean passt, Finished;
int Werte = 1;
if(SpaltenNr > 8){//Zeilenende erreicht?
if(ZeilenNr > 7){//Spaltenende erreicht?
return; //Fertig => letztes Feld wurde erreicht
}
else{
ZeilenNr++;//Neue Zeile
SpaltenNr = 0;//Zeilen Anfang (Spalte 0)
}
}
if(SpielFeldWerte[ZeilenNr][SpaltenNr] == 0){ //Feld nicht beschrieben
while(Werte < 10){//Werte 1 bis 9 testen
passt = Kontrolle(ZeilenNr, SpaltenNr, Werte);//Überprüfen, passt der Wert ins Feld
if(passt){//Wert passt
SolvedWerte[ZeilenNr][SpaltenNr] = Werte; //Wert ins Feld schreiben
Graphics MyGraphic = PanelFeld[ZeilenNr][SpaltenNr].getGraphics();
MyGraphic.setColor(Color.blue);
MyGraphic.fillRect(0,0,40,40);//Vordere zahl löschen (sonst werden meherere Zahlne übereinander geschrieben)
MyGraphic.setColor(Color.white);
MyGraphic.drawString(""+SolvedWerte[ZeilenNr][SpaltenNr],10,25);//Zahl ausgeben
Delay.many_mSec();//Pause (ms)
SolveBacktrack(ZeilenNr,(SpaltenNr + 1));//Rekursion => nächstes Feld
//Passte im vorderen Feld kein Wert, gehts hier weiter => Backtrack
//Wurden all oberen Felder glöst?
Finished = true; //Variabel zur Kontroll ob die oben Felder gelöst wurden
for(int mZeile = 8; mZeile >= ZeilenNr; mZeile--){
for(int mSpalte = 8; mSpalte >= SpaltenNr; mSpalte--){
if(SolvedWerte[mZeile][mSpalte]==0){ //Obere Felder gelöst?
Finished = false;//ein Feld wurde nicht gelöst!
}
}
}
if(Finished){
return;
}
}
Werte++;//Nächst höherer Wert
}
if(SpielFeldWerte[ZeilenNr][SpaltenNr]> 0){
return;//Ist ein OriginalWert im Feld darf dieser nicht gelöscht werden
}
else{
SolvedWerte[ZeilenNr][SpaltenNr] = 0; //Wenn kein Wert passt, Feld wieder löschen
//return;//Zum Vorderen Feld zurückkehren
}
}
else{//Feld bereits beschrieben (mit Original-Wert):
//Dieses Feld überspringen
SolveBacktrack(ZeilenNr,SpaltenNr+1); //Rekursiv => nächstes Feld
//return;
}
return;
}
//Kontrolliert, ob eine bestimmte Zahl in ein bestimmtes Feld geschrieben werden darf
public boolean Kontrolle(int ZeilenNr, int SpaltenNr, int Zahl){
//gleiche Zahl in der gleichen Zeile?
for(int Spalte = 0; Spalte <9;Spalte++){
if(SolvedWerte[ZeilenNr][Spalte] == Zahl){
return false;
}
}
//gleiche Zahl in der gleichen Spalte?
for(int Zeile = 0; Zeile<9; Zeile++){
if(SolvedWerte[Zeile][SpaltenNr] == Zahl){
return false;
}
}
//Zahl im gleichen Quadrat?
//Berechnung welches Quadrat(Links, Mitte, Rechts)? => FeldPosX = (int)(FeldPosX/3)*3
//Berechnung welches Quadrat(Oben, Mitte, Unten)? => FeldPosY = (int)(FeldPosY/3)*3
int QuadratYPos = ((int)(ZeilenNr/3)*3); //Erstes Feld des Quadrates
int QuadratXPos = ((int)(SpaltenNr/3)*3);//Erstes Feld des Quadrates
int QuadratXMax = (QuadratXPos + 3); //Letztes Feld des Quadrates
int QuadratYMax = (QuadratYPos + 3);//Letztes Feld des Quadrates
for(int Zeile = QuadratYPos;Zeile < QuadratYMax; Zeile++){//Durchlaufen vom 1. bis zum letzten Feld
for(int Spalte = QuadratXPos;Spalte < QuadratXMax; Spalte++){
if(SolvedWerte[Zeile][Spalte] == Zahl){
return false;
}
}
}
//Die Zahl passt:
return true;
}
}/**********************************/
class CWait {
//public void setDelay(){
long Faktor = 1000;
//long Faktor = SetDelay.getValue();
//scale[0] = (((float) scaleP.getValue()) / 50) * (((float) scaleP.getValue()) / 50);
public void many_mSec(/*long s*/) {
try {
Thread.currentThread().sleep(Faktor * 1);
}
catch (InterruptedException e) {
}
}
}
}//Hauptklasse schliessen