Skip to content

Instantly share code, notes, and snippets.

@Lhy121125
Created June 19, 2023 23:02
Show Gist options
  • Save Lhy121125/2a78a036da0f5cba42df258abee81552 to your computer and use it in GitHub Desktop.
Save Lhy121125/2a78a036da0f5cba42df258abee81552 to your computer and use it in GitHub Desktop.
/*
* SudokuPlayer.java
* Ray Zeng(Tianrui) & Nick Luo(Haiyu)
* All group members were present and contributing during all work on this project.
* We have neither received nor given any unauthorized aid in this assignment.
*/
package hw2;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.DecimalFormat;
public class SudokuPlayer implements Runnable, ActionListener {
// final values must be assigned in vals[][]
int[][] vals = new int[9][9];
Board board = null;
/// --- AC-3 Constraint Satisfication --- ///
// Useful but not required Data-Structures;
ArrayList<Integer>[] globalDomains = new ArrayList[81];
ArrayList<Integer>[] neighbors = new ArrayList[81];
Queue<Arc> globalQueue = new LinkedList<Arc>();
//Board of heuristic
int[] heuristic = new int[81];
//Array keep track of the frequency of values
int[] frequency = new int[10];
/*
* This method sets up the data structures and the initial global constraints
* (by calling allDiff()) and makes the initial call to backtrack().
* You should not change this method header.
*/
private final void AC3Init(){
//Do NOT remove these lines (required for the GUI)
board.Clear();
recursions = 0;
/**
* YOUR CODE HERE:
* Create Data structures ( or populate the ones defined above ).
* These will be the data structures necessary for AC-3.
**/
for(int i = 0; i < 81; i++) {
int x = i / 9;
int y = i % 9;
/*filled in the global domain of i*/
//already filled in;
if(vals[x][y] != 0) {
globalDomains[i] = new ArrayList<Integer>();
globalDomains[i].add(vals[x][y]);
}else {//filled in from 1 to 9;
for(int k = 1; k < 10; k++) {
if(globalDomains[i]==null) {
globalDomains[i] = new ArrayList<Integer>();
}
globalDomains[i].add(k);
}
}
}
//Fill globalQueue and neighbors with same row
for(int r = 0; r < 9; r++) {
/* create input parametes for neighbors and globalQueue*/
int[] row = new int[9];
for(int c = 0; c < 9; c++) {
row[c] = r * 9 + c;
}
allDiff(row);
}
//Fill globalQueue and neighbors with same col
for(int c = 0; c < 9; c++) {
/* create input parametes for neighbors and globalQueue*/
int[] col = new int[9];
for(int r = 0; r < 9; r++) {
col[r] = r * 9 + c;
}
allDiff(col);
}
//Fill globalQueue and neighbors with same box
int upLeft = -21;
for(int c = 0; c < 3; c++) {
upLeft += 18;//24
for(int r = 0; r< 3; r++) {
upLeft += 3; //0 3 6
/*fill in subGroup*/
int[] subGroup = new int[9];
for(int i = 0; i < 9; i++) {//6
// i 4
subGroup[i] = upLeft + i/3 * 9 + i % 3;//6 7 8 15 16
}
allDiff(subGroup);
}
}
// Initial call to backtrack() on cell 0 (top left)
boolean success = backtrack(0, globalDomains);
// Prints evaluation of run
Finished(success);
}
/*
* This method defines constraints between a set of variables.
* Refer to the book for more details. You may change this method header.
*/
private final void allDiff(int[] all){
// YOUR CODE HERE
for(int pos : all) {
for(int i : all) {
if(i == pos) continue;
if(neighbors[pos]==null) neighbors[pos] = new ArrayList<Integer>();
neighbors[pos].add(i);
globalQueue.add(new Arc(pos, i));
}
}
}
/*
* This is the backtracking algorithm. If you change this method header, you will have
* to update the calls to this method.
*/
private final boolean backtrack(int cell, ArrayList<Integer>[] Domains) {
//Do NOT remove
recursions +=1;
//int j = 0;
//System.out.
if(cell > 80) return true;
//If already set
if(vals[cell / 9][cell % 9] != 0){
return backtrack(cell + 1, Domains);
}
//Deep copy the domain
ArrayList<Integer>[] copy = new ArrayList[81];
for(int i = 0; i < 81; i++) {
copy[i] = new ArrayList<Integer>(Domains[i]);
}
//fail change copy back to Domain
//but here Domain is different from copy so its ok
if(!AC3(copy)) {
return false;
}//else successful continue on copy
// YOUR CODE HERE
int r = cell / 9;
int c = cell % 9;
//Check each values for cell's domain
ArrayList<Integer> tmp = new ArrayList<>(copy[cell]);
for(int val : tmp){
copy[cell].clear();
copy[cell].add(val);
//Recursive
if(backtrack(cell + 1, copy)){
vals[r][c] = val;
return true;
}
}
return false;
}
/*
* This is the actual AC3 Algorithm. You may change this method header.
*/
private final boolean AC3(ArrayList<Integer>[] Domains) {
//Initialize a new Queue and deep copy it
Queue<Arc> q = new LinkedList<Arc>();
for(Arc a : globalQueue) {
q.offer(new Arc(a.Xi,a.Xj));
}
// YOUR CODE HERE
while(!q.isEmpty()) {
Arc arc = q.poll();
if (Revise(arc, Domains)) {
if(Domains[arc.Xi].size() == 0) {
return false;
}
//Reinserting the arcs
for(int Xk : neighbors[arc.Xi]){
if(Xk != arc.Xj) {
q.offer(new Arc(Xk, arc.Xi));
//System.out.println("add");
}
}
}
}
return true;
}
/*
* This is the Revise() procedure. You may change this method header.
*/
private final boolean Revise(Arc t, ArrayList<Integer>[] Domains){
boolean revised = false;
ArrayList<Integer> Di = Domains[t.Xi];
ArrayList<Integer> Dj = Domains[t.Xj];
for(int i = 0; i < Di.size(); i++) {
int x= Di.get(i);
boolean found = false;
//If found y that satisfy x != y
for(int y: Dj){
if(y != x) {
found= true;
break;
}
}
//If not found, then remove i from Di's domain
if(!found) {
Di.remove(i);
revised = true;
}
}
// YOUR CODE HERE
return revised;
}
/*
* This is where you will write your custom solver.
* You should not change this method header.
* Use Forward checking and heuristic
*/
private final void customSolver(){
//set 'success' to true if a successful board
//is found and false otherwise.
boolean success = true;
board.Clear();
recursions = 0;
System.out.println("Running custom algorithm");
//-- Your Code Here --
//Fill globalDomains
for(int i = 0; i < 81; i++) {
int x = i / 9;
int y = i % 9;
/*filled in the global domain of i*/
//already filled in;
if(vals[x][y] != 0) {
globalDomains[i] = new ArrayList<Integer>();
globalDomains[i].add(vals[x][y]);
}else {//filled in from 1 to 9;
for(int k = 1; k < 10; k++) {
if(globalDomains[i]==null) {
globalDomains[i] = new ArrayList<Integer>();
}
globalDomains[i].add(k);
}
}
}
//Fill the neighbors
for(int r = 0; r < 9; r++) {
/* create input parametes for neighbors and globalQueue*/
int[] row = new int[9];
for(int c = 0; c < 9; c++) {
row[c] = r * 9 + c;
}
allDiff(row);
}
for(int c = 0; c < 9; c++) {
/* create input parametes for neighbors and globalQueue*/
int[] col = new int[9];
for(int r = 0; r < 9; r++) {
col[r] = r * 9 + c;
}
allDiff(col);
}
int upLeft = -21;
for(int c = 0; c < 3; c++) {
upLeft += 18;//24
for(int r = 0; r< 3; r++) {
upLeft += 3; //0 3 6
/*fill in subGroup*/
int[] subGroup = new int[9];
for(int i = 0; i < 9; i++) {//6
// i 4
subGroup[i] = upLeft + i/3 * 9 + i % 3;//6 7 8 15 16
}
allDiff(subGroup);
}
}
//Here are the heuristics for the most remaining values
/*count the frequency
for(int[] i: vals) {
for(int j: i) {
if(j!=0) {
frequency[j]++;
}
}
}*/
success = forwardBacktrack(0, globalDomains);
Finished(success);
}
//Backtrack algorithm Using forward checking
private final boolean forwardBacktrack(int cell, ArrayList<Integer>[] Domains) {
recursions++;
/*Here are the implementation of the Heuristic of most constraint variables, for some reasons it
*takes much longer time than simply using forwrd checking, although less recursive steps, I guess maybe
*because of the forloop used in getNextCell and updateHeuristic.
*/
//cell = getNextCell();
//updateHeuristic();
//if(cell == -1) return true;
//Return true after all cells have gone through
if(cell > 80) return true;
//If already set
if(vals[cell / 9][cell % 9] != 0){
//heuristic[cell] = -1;
return forwardBacktrack(cell+1, Domains);
}
int r = cell / 9;
int c = cell % 9;
//Backtrack to previous chosen variables by returning false
if(Domains[cell].isEmpty()) {
return false;
}
//Go through each value in the domain
ArrayList<Integer> tmp = new ArrayList<>(Domains[cell]);
for(int i=0; i<tmp.size(); i++) {
//Make a copy of Domains
ArrayList<Integer>[] copy = new ArrayList[81];
for(int m = 0; m < 81; m++) {
copy[m] = new ArrayList<Integer>(Domains[m]);
}
//Use forward checking to check
int val = tmp.get(i);
if(forwardChecking(cell,val,copy)) {
copy[cell].clear();
copy[cell].add(val);
//update domains of all unassigned neighbors
for(int nei : neighbors[cell]) {
if(copy[nei].contains(val)) {
copy[nei].remove(copy[nei].indexOf(val));
}
}
//Recursion
if(forwardBacktrack(cell+1,copy)) {
vals[r][c] = val;
return true;
}
}
else {
tmp.remove(i);
i--;
}
}
return false;
}
/*The method that update the heuristics
*However, this method is very inefficient that it go through every element in domain and neighbors of each
*value in domain, but if it doesn't update every time, it will make lead to errors to infinite loop since
*the ending case will never happen
*/
private void updateHeuristic(ArrayList<Integer>[] Domains) {
for(int i = 0;i<Domains.length;i++) {
int count = 0;
if(Domains[i].size()==1) {
heuristic[i] = -1;
continue;
}
for(int nei : neighbors[i]) {
if(Domains[nei].size()==1) count++;
}
heuristic[i] = count;
}
}
//The method return the cell-number of the variable with the most constraints
private int getNextCell() {
//heuristic[cell] = -1;
int max = heuristic[0];
int maxIndex = 0;
for(int i=0; i<81;i++) {
if(heuristic[i] > max) {
max = heuristic[i];
maxIndex = i;
}
}
return maxIndex;
}
//The method that return the least constraint value
private int getNextVal(ArrayList<Integer> d) {
int max = -10000;
for(int i = 0;i<d.size();i++) {
if(frequency[d.get(i)] > max) max = frequency[d.get(i)];
}
return max;
}
//The forward checking algorithm that check whether setting a value make its neighbor's domain become empty
private final boolean forwardChecking(int x, int value, ArrayList<Integer>[] Domains) {
for(int nei : neighbors[x]) {
if(Domains[nei].contains(value) && Domains[nei].size()==1) {
return false;
}
}
return true;
}
/// ---------- HELPER FUNCTIONS --------- ///
/// ---- DO NOT EDIT REST OF FILE --- ///
/// ---------- HELPER FUNCTIONS --------- ///
/// ---- DO NOT EDIT REST OF FILE --- ///
public final boolean valid(int x, int y, int val){
if (vals[x][y] == val)
return true;
if (rowContains(x,val))
return false;
if (colContains(y,val))
return false;
if (blockContains(x,y,val))
return false;
return true;
}
public final boolean blockContains(int x, int y, int val){
int block_x = x / 3;
int block_y = y / 3;
for(int r = (block_x)*3; r < (block_x+1)*3; r++){
for(int c = (block_y)*3; c < (block_y+1)*3; c++){
if (vals[r][c] == val)
return true;
}
}
return false;
}
public final boolean colContains(int c, int val){
for (int r = 0; r < 9; r++){
if (vals[r][c] == val)
return true;
}
return false;
}
public final boolean rowContains(int r, int val) {
for (int c = 0; c < 9; c++)
{
if(vals[r][c] == val)
return true;
}
return false;
}
private void CheckSolution() {
// If played by hand, need to grab vals
board.updateVals(vals);
/*for(int i=0; i<9; i++){
for(int j=0; j<9; j++)
System.out.print(vals[i][j]+" ");
System.out.println();
}*/
for (int v = 1; v <= 9; v++){
// Every row is valid
for (int r = 0; r < 9; r++)
{
if (!rowContains(r,v))
{
board.showMessage("Value "+v+" missing from row: " + (r+1));// + " val: " + v);
return;
}
}
// Every column is valid
for (int c = 0; c < 9; c++)
{
if (!colContains(c,v))
{
board.showMessage("Value "+v+" missing from column: " + (c+1));// + " val: " + v);
return;
}
}
// Every block is valid
for (int r = 0; r < 3; r++){
for (int c = 0; c < 3; c++){
if(!blockContains(r, c, v))
{
return;
}
}
}
}
board.showMessage("Success!");
}
/// ---- GUI + APP Code --- ////
/// ---- DO NOT EDIT --- ////
enum algorithm {
AC3, Custom
}
class Arc implements Comparable<Object>{
int Xi, Xj;
public Arc(int cell_i, int cell_j){
if (cell_i == cell_j){
try {
throw new Exception(cell_i+ "=" + cell_j);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
Xi = cell_i; Xj = cell_j;
}
public int compareTo(Object o){
return this.toString().compareTo(o.toString());
}
public String toString(){
return "(" + Xi + "," + Xj + ")";
}
}
enum difficulty {
easy, medium, hard, random
}
public void actionPerformed(ActionEvent e){
String label = ((JButton)e.getSource()).getText();
if (label.equals("AC-3"))
AC3Init();
else if (label.equals("Clear"))
board.Clear();
else if (label.equals("Check"))
CheckSolution();
//added
else if(label.equals("Custom"))
customSolver();
}
public void run() {
board = new Board(gui,this);
long start=0, end=0;
while(!initialize());
if (gui)
board.initVals(vals);
else {
board.writeVals();
System.out.println("Algorithm: " + alg);
switch(alg) {
default:
case AC3:
start = System.currentTimeMillis();
AC3Init();
end = System.currentTimeMillis();
break;
case Custom: //added
start = System.currentTimeMillis();
customSolver();
end = System.currentTimeMillis();
break;
}
CheckSolution();
if(!gui)
System.out.println("time to run: "+(end-start));
}
}
public final boolean initialize(){
switch(level) {
case easy:
vals[0] = new int[] {0,0,0,1,3,0,0,0,0};
vals[1] = new int[] {7,0,0,0,4,2,0,8,3};
vals[2] = new int[] {8,0,0,0,0,0,0,4,0};
vals[3] = new int[] {0,6,0,0,8,4,0,3,9};
vals[4] = new int[] {0,0,0,0,0,0,0,0,0};
vals[5] = new int[] {9,8,0,3,6,0,0,5,0};
vals[6] = new int[] {0,1,0,0,0,0,0,0,4};
vals[7] = new int[] {3,4,0,5,2,0,0,0,8};
vals[8] = new int[] {0,0,0,0,7,3,0,0,0};
break;
case medium:
vals[0] = new int[] {0,4,0,0,9,8,0,0,5};
vals[1] = new int[] {0,0,0,4,0,0,6,0,8};
vals[2] = new int[] {0,5,0,0,0,0,0,0,0};
vals[3] = new int[] {7,0,1,0,0,9,0,2,0};
vals[4] = new int[] {0,0,0,0,8,0,0,0,0};
vals[5] = new int[] {0,9,0,6,0,0,3,0,1};
vals[6] = new int[] {0,0,0,0,0,0,0,7,0};
vals[7] = new int[] {6,0,2,0,0,7,0,0,0};
vals[8] = new int[] {3,0,0,8,4,0,0,6,0};
break;
case hard:
vals[0] = new int[] {1,2,0,4,0,0,3,0,0};
vals[1] = new int[] {3,0,0,0,1,0,0,5,0};
vals[2] = new int[] {0,0,6,0,0,0,1,0,0};
vals[3] = new int[] {7,0,0,0,9,0,0,0,0};
vals[4] = new int[] {0,4,0,6,0,3,0,0,0};
vals[5] = new int[] {0,0,3,0,0,2,0,0,0};
vals[6] = new int[] {5,0,0,0,8,0,7,0,0};
vals[7] = new int[] {0,0,7,0,0,0,0,0,5};
vals[8] = new int[] {0,0,0,0,0,0,0,9,8};
break;
case random:
default:
ArrayList<Integer> preset = new ArrayList<Integer>();
while (preset.size() < numCells)
{
int r = rand.nextInt(81);
if (!preset.contains(r))
{
preset.add(r);
int x = r / 9;
int y = r % 9;
if (!assignRandomValue(x, y))
return false;
}
}
break;
}
return true;
}
public final boolean assignRandomValue(int x, int y){
ArrayList<Integer> pval = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9));
while(!pval.isEmpty()){
int ind = rand.nextInt(pval.size());
int i = pval.get(ind);
if (valid(x,y,i)) {
vals[x][y] = i;
return true;
} else
pval.remove(ind);
}
System.err.println("No valid moves exist. Recreating board.");
for (int r = 0; r < 9; r++){
for(int c=0;c<9;c++){
vals[r][c] = 0;
} }
return false;
}
private void Finished(boolean success){
if(success) {
board.writeVals();
//board.showMessage("Solved in " + myformat.format(ops) + " ops \t(" + myformat.format(recursions) + " recursive ops)");
board.showMessage("Solved in " + myformat.format(recursions) + " recursive ops");
} else {
//board.showMessage("No valid configuration found in " + myformat.format(ops) + " ops \t(" + myformat.format(recursions) + " recursive ops)");
board.showMessage("No valid configuration found");
}
recursions = 0;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Gui? y or n ");
char g=scan.nextLine().charAt(0);
if (g=='n')
gui = false;
else
gui = true;
if(gui) {
System.out.println("difficulty? \teasy (e), medium (m), hard (h), random (r)");
char c = '*';
while (c != 'e' && c != 'm' && c != 'n' && c != 'h' && c != 'r') {
c = scan.nextLine().charAt(0);
if(c=='e')
level = difficulty.valueOf("easy");
else if(c=='m')
level = difficulty.valueOf("medium");
else if(c=='h')
level = difficulty.valueOf("hard");
else if(c=='r')
level = difficulty.valueOf("random");
else{
System.out.println("difficulty? \teasy (e), medium (m), hard (h), random(r)");
}
}
SudokuPlayer app = new SudokuPlayer();
app.run();
}
else { //no gui
boolean again = true;
int numiters = 0;
long starttime, endtime, totaltime=0;
while(again) {
numiters++;
System.out.println("difficulty? \teasy (e), medium (m), hard (h), random (r)");
char c = '*';
while (c != 'e' && c != 'm' && c != 'n' && c != 'h' && c != 'r') {
c = scan.nextLine().charAt(0);
if(c=='e')
level = difficulty.valueOf("easy");
else if(c=='m')
level = difficulty.valueOf("medium");
else if(c=='h')
level = difficulty.valueOf("hard");
else if(c=='r')
level = difficulty.valueOf("random");
else{
System.out.println("difficulty? \teasy (e), medium (m), hard (h), random(r)");
}
}
System.out.println("Algorithm? AC3 (1) or Custom (2)");
if(scan.nextInt()==1)
alg = algorithm.valueOf("AC3");
else
alg = algorithm.valueOf("Custom");
SudokuPlayer app = new SudokuPlayer();
starttime = System.currentTimeMillis();
app.run();
endtime = System.currentTimeMillis();
totaltime += (endtime-starttime);
System.out.println("quit(0), run again(1)");
if (scan.nextInt()==1)
again=true;
else
again=false;
scan.nextLine();
}
System.out.println("average time over "+numiters+" iterations: "+(totaltime/numiters));
}
scan.close();
}
class Board {
GUI G = null;
boolean gui = true;
public Board(boolean X, SudokuPlayer s) {
gui = X;
if (gui)
G = new GUI(s);
}
public void initVals(int[][] vals){
G.initVals(vals);
}
public void writeVals(){
if (gui)
G.writeVals();
else {
for (int r = 0; r < 9; r++) {
if (r % 3 == 0)
System.out.println(" ----------------------------");
for (int c = 0; c < 9; c++) {
if (c % 3 == 0)
System.out.print (" | ");
if (vals[r][c] != 0) {
System.out.print(vals[r][c] + " ");
} else {
System.out.print("_ ");
}
}
System.out.println(" | ");
}
System.out.println(" ----------------------------");
}
}
public void Clear(){
if(gui)
G.clear();
}
public void showMessage(String msg) {
if (gui)
G.showMessage(msg);
System.out.println(msg);
}
public void updateVals(int[][] vals){
if (gui)
G.updateVals(vals);
}
}
class GUI {
// ---- Graphics ---- //
int size = 40;
JFrame mainFrame = null;
JTextField[][] cells;
JPanel[][] blocks;
public void initVals(int[][] vals){
// Mark in gray as fixed
for (int r = 0; r < 9; r++) {
for (int c = 0; c < 9; c++) {
if (vals[r][c] != 0) {
cells[r][c].setText(vals[r][c] + "");
cells[r][c].setEditable(false);
cells[r][c].setBackground(Color.lightGray);
}
}
}
}
public void showMessage(String msg){
JOptionPane.showMessageDialog(null,
msg,"Message",JOptionPane.INFORMATION_MESSAGE);
}
public void updateVals(int[][] vals) {
// System.out.println("calling update");
for (int r = 0; r < 9; r++) {
for (int c=0; c < 9; c++) {
try {
vals[r][c] = Integer.parseInt(cells[r][c].getText());
} catch (java.lang.NumberFormatException e) {
System.out.println("Invalid Board: row col: "+(r+1)+" "+(c+1));
showMessage("Invalid Board: row col: "+(r+1)+" "+(c+1));
return;
}
}
}
}
public void clear() {
for (int r = 0; r < 9; r++){
for (int c = 0; c < 9; c++){
if (cells[r][c].isEditable())
{
cells[r][c].setText("");
vals[r][c] = 0;
} else {
cells[r][c].setText("" + vals[r][c]);
}
}
}
}
public void writeVals(){
for (int r=0;r<9;r++){
for(int c=0; c<9; c++){
cells[r][c].setText(vals[r][c] + "");
} }
}
public GUI(SudokuPlayer s){
mainFrame = new javax.swing.JFrame();
mainFrame.setLayout(new BorderLayout());
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel gamePanel = new javax.swing.JPanel();
gamePanel.setBackground(Color.black);
mainFrame.add(gamePanel, BorderLayout.NORTH);
gamePanel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
gamePanel.setLayout(new GridLayout(3,3,3,3));
blocks = new JPanel[3][3];
for (int i = 0; i < 3; i++){
for(int j =2 ;j>=0 ;j--){
blocks[i][j] = new JPanel();
blocks[i][j].setLayout(new GridLayout(3,3));
gamePanel.add(blocks[i][j]);
}
}
cells = new JTextField[9][9];
for (int cell = 0; cell < 81; cell++){
int i = cell / 9;
int j = cell % 9;
cells[i][j] = new JTextField();
cells[i][j].setBorder(BorderFactory.createLineBorder(Color.BLACK));
cells[i][j].setHorizontalAlignment(JTextField.CENTER);
cells[i][j].setSize(new java.awt.Dimension(size, size));
cells[i][j].setPreferredSize(new java.awt.Dimension(size, size));
cells[i][j].setMinimumSize(new java.awt.Dimension(size, size));
blocks[i/3][j/3].add(cells[i][j]);
}
JPanel buttonPanel = new JPanel(new FlowLayout());
mainFrame.add(buttonPanel, BorderLayout.SOUTH);
//JButton DFS_Button = new JButton("DFS");
//DFS_Button.addActionListener(s);
JButton AC3_Button = new JButton("AC-3");
AC3_Button.addActionListener(s);
JButton Clear_Button = new JButton("Clear");
Clear_Button.addActionListener(s);
JButton Check_Button = new JButton("Check");
Check_Button.addActionListener(s);
//buttonPanel.add(DFS_Button);
JButton Custom_Button = new JButton("Custom");
Custom_Button.addActionListener(s);
//added
buttonPanel.add(AC3_Button);
buttonPanel.add(Custom_Button);
buttonPanel.add(Clear_Button);
buttonPanel.add(Check_Button);
mainFrame.pack();
mainFrame.setVisible(true);
}
}
Random rand = new Random();
// ----- Helper ---- //
static algorithm alg = algorithm.AC3;
static difficulty level = difficulty.easy;
static boolean gui = true;
static int numCells = 15;
static DecimalFormat myformat = new DecimalFormat("###,###");
//For printing
static int recursions;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment