Folge dem Video um zu sehen, wie unsere Website als Web-App auf dem Startbildschirm installiert werden kann.
Anmerkung: Diese Funktion ist in einigen Browsern möglicherweise nicht verfügbar.
import java.io.FileWriter;
import java.io.File;
import java.io.IOException;
import java.awt.geom.Line2D;
import java.awt.Graphics2D;
import java.awt.Graphics;
import javax.swing.*;
import java.awt.event.*;
import java.util.HashMap;
import java.util.Formatter;
import static java.awt.Color.*;
import static sudokupuzzle.Puzzle.*;
/**
* The main class for running the Sudoku program. The idea is
* that the program presents you with a Sudoku puzzle to solve. The user
* has some control over how difficult the puzzle is by choosing how many
* blank cells there are.
*
* The program can check a partially completed puzzle for duplicate values
* (row, column or region).
*
* The program allows the user to associate notes with cells
* to indicate values that they think are likely or unlikely. Notes are
* accessed by right-clicking a cell. Cells with notes are
* highlighted.
*
* The time taken to complete a puzzle is displayed.
*/
public class SudokuView extends javax.swing.JFrame {
/**
* Normal constructor.
*/
public SudokuView() {
initComponents();
openNotes = new HashMap<CellCoordinates, CellNoteView>();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jPanel4 = new javax.swing.JPanel();
jPanel2 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
btnDown = new javax.swing.JButton();
txtNumberOfBlanks = new javax.swing.JTextField();
btnUp = new javax.swing.JButton();
btnGetPuzzle = new javax.swing.JButton();
btnCheck = new javax.swing.JButton();
jButton3 = new javax.swing.JButton();
jButton2 = new javax.swing.JButton();
jPanel3 = new javax.swing.JPanel();
jLabel2 = new javax.swing.JLabel();
lblTimer = new javax.swing.JLabel();
btnPauseRestart = new javax.swing.JButton();
jPanel1 = new JPanel(){
public void paint(Graphics g){
super.paint(g);
paint(g);
}
};
//post create
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Sudoku Puzzle");
jPanel4.setLayout(new java.awt.GridLayout(2, 0));
jPanel2.setOpaque(false);
jPanel2.setPreferredSize(new java.awt.Dimension(800, 50));
jLabel1.setFont(new java.awt.Font("Verdana", 0, 14));
jLabel1.setText("Blanks");
jPanel2.add(jLabel1);
btnDown.setFont(new java.awt.Font("Verdana", 0, 14));
btnDown.setText("<<");
btnDown.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnDownActionPerformed(evt);
}
});
jPanel2.add(btnDown);
txtNumberOfBlanks.setFont(new java.awt.Font("Verdana", 0, 14));
txtNumberOfBlanks.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
txtNumberOfBlanks.setText("9");
txtNumberOfBlanks.setPreferredSize(new java.awt.Dimension(30, 30));
txtNumberOfBlanks.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtNumberOfBlanksActionPerformed(evt);
}
});
jPanel2.add(txtNumberOfBlanks);
btnUp.setFont(new java.awt.Font("Verdana", 0, 14));
btnUp.setText(">>");
btnUp.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnUpActionPerformed(evt);
}
});
jPanel2.add(btnUp);
btnGetPuzzle.setFont(new java.awt.Font("Verdana", 0, 14));
btnGetPuzzle.setText("Get Puzzle");
btnGetPuzzle.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnGetPuzzleActionPerformed(evt);
}
});
jPanel2.add(btnGetPuzzle);
btnCheck.setFont(new java.awt.Font("Verdana", 0, 14));
btnCheck.setText("Check");
btnCheck.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCheckActionPerformed(evt);
}
});
jPanel2.add(btnCheck);
jButton3.setFont(new java.awt.Font("Verdana", 0, 14));
jButton3.setText("Blank Page");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton3ActionPerformed(evt);
}
});
jPanel2.add(jButton3);
jButton2.setFont(new java.awt.Font("Verdana", 0, 14));
jButton2.setText("Save");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton2ActionPerformed(evt);
}
});
jPanel2.add(jButton2);
jPanel4.add(jPanel2);
jPanel3.setPreferredSize(new java.awt.Dimension(400, 30));
jLabel2.setFont(new java.awt.Font("Verdana", 0, 14));
jLabel2.setText("elapsed");
jPanel3.add(jLabel2);
lblTimer.setBackground(new java.awt.Color(51, 51, 51));
lblTimer.setFont(new java.awt.Font("Verdana", 0, 14));
lblTimer.setForeground(new java.awt.Color(255, 255, 255));
lblTimer.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
lblTimer.setOpaque(true);
lblTimer.setPreferredSize(new java.awt.Dimension(50, 18));
jPanel3.add(lblTimer);
btnPauseRestart.setFont(new java.awt.Font("Verdana", 0, 14));
btnPauseRestart.setText("Pause");
btnPauseRestart.setEnabled(false);
btnPauseRestart.setPreferredSize(new java.awt.Dimension(90, 27));
btnPauseRestart.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnPauseRestartActionPerformed(evt);
}
});
jPanel3.add(btnPauseRestart);
jPanel4.add(jPanel3);
getContentPane().add(jPanel4, java.awt.BorderLayout.NORTH);
jPanel1.setPreferredSize(new java.awt.Dimension(420, 420));
//post init
txtCell = new JTextField[9][9];
for (int i = 0; i < txtCell.length; i++) {
for (int j = 0; j < txtCell[0].length; j++) {
txtCell[i][j] = new JTextField();
txtCell[i][j].setHorizontalAlignment(javax.swing.JTextField.RIGHT);
txtCell[i][j].setFont(new java.awt.Font("Verdana", 0, 14));
txtCell[i][j].setPreferredSize(new java.awt.Dimension(30, 30));
txtCell[i][j].setEditable(false);
txtCell[i][j].addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
txtCellMouseClicked(evt);
}
});
jPanel1.add(txtCell[i][j]);
}
}
jPanel1.setLayout(new java.awt.GridLayout(9, 9));
getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
pack();
}// </editor-fold>//GEN-END:initComponents
/**
* The Pause/Restart button has been clicked to pause or restart the
* timer.
* @param evt The ActionEvent
*/
private void btnPauseRestartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPauseRestartActionPerformed
if (tim != null && tim.isRunning()) { // timer is running so need to pause
tim.stop();
btnPauseRestart.setText("Restart");
}
else { // not running so need to restart
startTiming(true);
btnPauseRestart.setText("Pause");
}
}//GEN-LAST:event_btnPauseRestartActionPerformed
/**
* The Check button has been pressed so the puzzle needs to be checked for
* duplicates. If there are no duplicates and no empty cells then the
* puzzle has been solved.
* @param evt The ActionEvent
*/
private void btnCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheckActionPerformed
char [] [] grid = new char [txtCell.length] [txtCell[0].length];
for (int i = 0; i < txtCell.length; i++) {
for (int j = 0; j < txtCell[0].length; j++) {
if (!txtCell[i][j].getText().trim().equals("")) { // something in the cell
grid [i][j] = txtCell[i][j].getText().charAt(0);
} else { // cell is empty
grid [i][j] = EMPTY_CELL;
}
// Set background for cell. GREEN means it has a note,
// WHITE means no note and is editable, LIGHT_GRAY means
// it is one of the fixed cells in the puzzle and so can't
// be edited.
if (txtCell[i][j].isEditable()) {
if (cellNotes.getNote(new CellCoordinates(i + 1, j + 1)) != null) { // it has a note
txtCell[i][j].setBackground(GREEN);
}
else { // no note
txtCell[i][j].setBackground(WHITE);
}
}
else {
txtCell[i][j].setBackground(LIGHT_GRAY);
}
}
}
JOptionPane.showMessageDialog(null,"Some Boxes are still empty");
// Use the Puzzle class to find if there are any duplicates and set
// the background to red of any duplicates found.
Puzzle p = new Puzzle (grid);
int [][][]duplicates = p.getCoordinatesOfDuplicates();
if (duplicates != null) {
for (int [][] coords : duplicates) {
txtCell[coords[0][0]][coords[0][1]].setBackground(RED);
txtCell[coords[1][0]][coords[1][1]].setBackground(RED);
}
}
if (p.isSolved()) {
tim.stop();
btnPauseRestart.setText("Pause");
btnPauseRestart.setEnabled(false);
JOptionPane.showMessageDialog(null,"Solved in " + (System.currentTimeMillis() - startTime) + " millisecs");
}
}//GEN-LAST:event_btnCheckActionPerformed
/**
* The "get puzzle" button has been clicked and so a new Puzzle must
* be generated and displayed.
* @param evt The ActionEvent
*/
private void btnGetPuzzleActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGetPuzzleActionPerformed
// Generate a puzzle with the number of blanks requested by the user.
PuzzleGenerator pg = new PuzzleGenerator();
int numBlanks = Integer.parseInt(txtNumberOfBlanks.getText());
int blanks = Integer.parseInt(txtNumberOfBlanks.getText());
if(blanks <= 0)
{
JOptionPane.showMessageDialog(null, "The Value is less or equal to 0");
} else if (blanks >= 81)
{
JOptionPane.showMessageDialog(null, "The Value is bigger or equal then 81");
}
else{
Puzzle p = new Puzzle(pg.getPuzzle(numBlanks));
cellNotes = new CellNotes();
// Get the values of the cells from the generated puzzle
// and display them. The fixed values that have been
// generated are not editable and have a LIGHT_GRAY background. The blanks
// are editable and have a WHITE background.
for (int i = 0; i < txtCell.length; i++) {
for (int j = 0; j < txtCell[0].length; j++) {
int value = p.getCell(i, j);
if (value != EMPTY_CELL) {
txtCell[i][j].setText("" + value);
txtCell[i][j].setEditable(false);
txtCell[i][j].setBackground(LIGHT_GRAY);
}
else {
txtCell[i][j].setText("");
txtCell[i][j].setEditable(true);
txtCell[i][j].setBackground(WHITE);
}
}
}
// Get rid of any notes windows that may still be open from a
// previous puzzle.
for (CellNoteView cnv: openNotes.values()) {
cnv.dispose();
}
openNotes = new HashMap<CellCoordinates, CellNoteView>();
// Initialise the timer
btnPauseRestart.setText("Pause");
btnPauseRestart.setEnabled(true);
if (tim != null) { // Stop any previous timer if still running.
tim.stop();
}
startTiming(false);
}
}//GEN-LAST:event_btnGetPuzzleActionPerformed
private void btnDownActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDownActionPerformed
int blanks = Integer.parseInt(txtNumberOfBlanks.getText());
blanks--;
txtNumberOfBlanks.setText(blanks + "");
}//GEN-LAST:event_btnDownActionPerformed
private void btnUpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUpActionPerformed
int blanks = Integer.parseInt(txtNumberOfBlanks.getText());
blanks++;
txtNumberOfBlanks.setText(blanks + "");
}//GEN-LAST:event_btnUpActionPerformed
private void txtNumberOfBlanksActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtNumberOfBlanksActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_txtNumberOfBlanksActionPerformed
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
chooser.showSaveDialog(this);
File file = chooser.getSelectedFile();
try {
outFile = new FileWriter(file);
for (int i = 0; i < txtCell.length; i++) {
for (int j = 0; j < txtCell[0].length; j++) {
outFile.write(txtCell[i][j].getText());
}}
outFile.close();
}
catch (IOException e) {
JOptionPane.showMessageDialog(this, "File Error");
}
}//GEN-LAST:event_jButton2ActionPerformed
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
if(evt.getSource()==jButton3){
for (int i = 0; i < txtCell.length; i++) {
for (int j = 0; j < txtCell[0].length; j++) {
txtCell[i][j].setText("");
txtCell[i][j].setEditable(false);
txtCell[i][j].setBackground(LIGHT_GRAY);
}
}}
}//GEN-LAST:event_jButton3ActionPerformed
/**
* One of the cells has been clicked. If it is a right-click on an
* editable cell then display the CellNoteView for the user to view
* and/or amend the notes for this cell.
* @param evt The MouseEvent.
*/
private void txtCellMouseClicked(java.awt.event.MouseEvent evt) {
// Get the JTextBox that has been clicked.
JTextField txtCellClicked = (JTextField) evt.getSource();
// We will only do anything if an editable cell has been clicked
// and it is a right-click (evt.BUTTON3)
if (!txtCellClicked.isEditable() || evt.getButton() != MouseEvent.BUTTON3 )
return;
int x = 0, y = 0;
// Find the x, y co-ordinates of the cell clicked
for (int i = 0; i < txtCell.length; i++) {
for (int j = 0; j < txtCell[0].length; j++) {
if (txtCellClicked == txtCell[i][j]) {
x = i + 1;
y = j + 1;
}
}
}
// Get the CellNoteView window for the cell that has been clicked
// if it already has one open.
CellNoteView cellNoteView = openNotes.get(new CellCoordinates(x, y));
if (cellNoteView == null) { // not already open so open it
if (cellNotes == null) {
cellNotes = new CellNotes();
}
// Create the note window and make it visible
cellNoteView = new CellNoteView(this, new CellCoordinates(x, y), cellNotes);
cellNoteView.pack();
cellNoteView.setVisible(true);
openNotes.put(new CellCoordinates(x, y), cellNoteView);
txtCellClicked.setBackground(GREEN); // indicate that there is a note
} else { // already open - so bring it to the front
cellNoteView.toFront();
}
}
/**
* Called by a CellNoteView to indicate that it is closing.
* @param coords The co-ordinates of the cell whose note is closing.
* @param isEmpty If true it means the note is empty. If false it means
* that the notes for this cell has content.
*/
public void cellNoteViewClosing(CellCoordinates coords, boolean isEmpty) {
// If the note is empty (i.ep. doesn't contain any information) then set
// it back to WHITE from GREEN
if (isEmpty) {
txtCell[coords.getX() - 1][coords.getY() - 1].setBackground(WHITE);
}
// Remove it from the collection of open notes.
openNotes.remove(coords);
}
/**
* Start the timer running for the puzzle.
* @param restart If true it means that the timer is being restarted (i.ep.
* it was previsiously running and then paused). If false
* it means the timer is being started for the first time.
*/
private void startTiming(boolean restart) {
if (restart) { // restarting after a pause so adjust
startTime += (System.currentTimeMillis() - currentTime);
} else { // starting for the first time
startTime = System.currentTimeMillis();
}
lblTimer.setText("0");
/* this timer will go off every 10th of a second
* and the timerHasPinged() method will be called
*/
tim = new Timer(100, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
timerHasPinged();
}
});
tim.start();
}
/**
* Called automatically when the timer expires. The time display
* should be updated.
*/
public void timerHasPinged() {
currentTime = System.currentTimeMillis();
// How long has been taken so far?
long secsTaken = (currentTime - startTime) / 1000;
long minsTaken = secsTaken / 60;
secsTaken %= 60;
// Format the time as m:ss
Formatter fmt = new Formatter();
fmt.format("%d:%02d", minsTaken, secsTaken);
lblTimer.setText(fmt.toString());
}
/**
* Main entry point for the program.
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SudokuView().setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnCheck;
private javax.swing.JButton btnDown;
private javax.swing.JButton btnGetPuzzle;
private javax.swing.JButton btnPauseRestart;
private javax.swing.JButton btnUp;
private javax.swing.JButton jButton2;
private javax.swing.JButton jButton3;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel3;
private javax.swing.JPanel jPanel4;
private javax.swing.JLabel lblTimer;
private javax.swing.JTextField txtNumberOfBlanks;
// End of variables declaration//GEN-END:variables
// Two-dimensional array of JTextFields representing the Sudoku
// puzzle grid.
private JTextField [] [] txtCell;
// Cells can have notes attached by the user. cellNotes is used to hold them.
private CellNotes cellNotes;
private FileWriter outFile;
private JFileChooser chooser = new JFileChooser();
// When the user right-clicks a cell a window opens to display the note.
// openNotes keeps a record of all currently open notes windows.
private HashMap<CellCoordinates, CellNoteView> openNotes;
// variables for managing the clock
private long startTime,
currentTime,
totalTime;
private Timer tim; // timer used to manage the clock;
/*
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Line2D x1 = new Line2D.Float(0, 266, 798, 266);
Line2D x2 = new Line2D.Float(0, 404, 798, 404);
Line2D y1 = new Line2D.Float(271, 128, 271, 541);
Line2D y2 = new Line2D.Float(535, 128, 535, 541);
g2.draw(x1);
g2.draw(x2);
g2.draw(y1);
g2.draw(y2);
}
*/
public synchronized void paint(final Graphics g) {
super.paint(g);
g.drawLine(0, 266, 798, 266);
g.drawLine(0, 404, 798, 404);
g.drawLine(271, 128, 271, 541);
g.drawLine(535, 128, 535, 541);
}
}
jPanel1 = new JPanel(){
public void paint(Graphics g){
super.paint(g);
paint(g);
}
};
public void paint(final Graphics g) {
super.paint(g);
g.drawLine(0, 266, 798, 266);
g.drawLine(0, 404, 798, 404);
g.drawLine(271, 128, 271, 541);
g.drawLine(535, 128, 535, 541);
}