Introduction
I wrote the original code for my Sudoku program using Visual Basic on Microsoft's Visual Studio IDE. This restricts the program to Windows.
To allow the code to execute successfully on Windows and Linux, I decided to use the portability of the C++ language.
I documented this in a previous article: cross_platform.aspx.
My approach received much criticism as the “same code” could not be compiled directly into a platform application.
I abstracted the program to a series of functions which can be interfaced to the native GUI toolkits.
The GUI interface needs only some buttons, an image box, and mouse position. It is used only to call the functions in the core C++ program.
In Windows, I still use the Visual Basic IDE to provide the GUI. The functions are provided by compiling the C++ core to a managed assembly DLL.
In Linux, I use Glade to develop the GUI and associated code. The functions are added to the GUI code directly.
The image of the Sudoku uses an uncompressed bitmap file in Windows BMP file format. This can be displayed in Windows and Linux. It can also be directly
worked on to produce the various images necessary for the program.
I still standby this method of generating cross-platform applications.
It is especially useful when we have:
- Most of the operational code able to be abstracted to a block of C++.
- Only a simple GUI is needed on the platform.
This does require individual compilation for each platform that it supports.
Another approach is to use code that can be directly run on any platform without special preparation. This could be software written in an interpreted language
for which run-time packages are needed.
I have been learning Java so I decided to rewrite my Sudoku program and make it truly platform independent.
Let's hope it will be “Write Once, Run Anywhere”, not “Write Once, Debug Everywhere”.
We can use Eclipse or the NetBeans IDE. Each has is own GUI toolkit. I do use Eclipse but I decided to use Java Foundation Classes (JFC) and Swing.
The code can be written and hacked with a text editor using javac to compile and java to run the application.
Game Code
The operational code needed to run the game is in:
public class Smethods
{
public static byte select(byte[][] sudoku, byte number, byte position, byte step)
{
if((sudoku[position*9 + number][step] == 0) || (sudoku[position*9 + number][step] > 9))
return step;
step += 1;
int count = 0;
for(count = 0; count < 729; count++)
sudoku[count][step] = sudoku[count][step - 1];
for(count = 0; count < 9; count++)
sudoku[position*9 + count][step] = 0;
byte row = (byte) (position/9);
for(count = 0; count < 9; count++)
sudoku[row * 81 + count * 9 + number][step] = 0;
byte column = (byte) (position%9);
for(count = 0; count < 9; count++)
sudoku[column * 9 + count * 81 + number][step] = 0;
int brow = (position/27)*243;
column = (byte) (((position%9)/3)*27);
byte incount;
for(incount = 0; incount < 3; incount++)
{
for(count = 0; count < 3; count++)
sudoku[brow + column + count * 9 + incount * 81 + number ][step] = 0;
}
sudoku[position*9 + number][step] = (byte) (number + 11);
return step;
}
}
I have only shown one method in the Smethods
class. We also have:
public static void start(byte[][] sudoku)
public static void trysudoku(byte[][] sudoku, byte startstep)
This provides all the calculations necessary to generate and solve Sudoku games.
Display Window
This is created by:
public class MySudoku
{
public static byte[][] sudoku = new byte[729][82];
public static byte step = 0;
private static final int WindowWidth = 777;
private static final int WindowHeight = 636;
public static void ShowGUI()
{
Smethods.start(sudoku);
final byte border = 14;
JFrame f = new JFrame("MySudoku");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage image = null;
try {
image = ImageIO.read(new File("sudoku.png"));
} catch (IOException e) {
}
f.setResizable(false);
f.setIconImage(image);
f.setSize(WindowWidth, WindowHeight);
f.setLocation(0, 0);
f.setLayout(new BorderLayout());
f.add(new SPanel(new Dimension(WindowWidth,border)), BorderLayout.NORTH);
f.add(new SPanel(new Dimension(WindowWidth,border)), BorderLayout.SOUTH);
f.add(new SPanel(new Dimension(border,WindowHeight)), BorderLayout.EAST);
f.add(new SPanel(new Dimension(0,WindowHeight)), BorderLayout.WEST);
DisplayPanel dp =new DisplayPanel();
dp.setBackground(Color.BLACK);
f.add(dp, BorderLayout.CENTER);
f.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ShowGUI();
}
});
}
}
Display Panel
This is where all the hard work is done to create the GUI. It positions and monitors the push buttons.
It paints the Sudoku game display:
public class DisplayPanel extends JPanel implements ActionListener
{
private static final long serialVersionUID = 1L;
private int DisplayWidth = 557;
private int DisplayHeight = 580;
private int ButtonsWidth = 200;
private final Color LB = new Color(0xAD,0xD8, 0xE6);
private final Color DB = new Color(0x1E,0x90, 0xFF);
private final Color P = new Color(0x80,0, 0x80);
public DisplayPanel()
{
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
selectNumber(e.getX(),e.getY());
}
});
this.setLayout(new BorderLayout());
JPanel pb = new JPanel();
pb.setPreferredSize(new Dimension(ButtonsWidth,DisplayHeight));
pb.setBackground(LB);
FlowLayout FL = new FlowLayout();
FL.setVgap(55);
FL.setHgap(100);
pb.setLayout(FL);
SButton EYS = new SButton("Enter Your Sudoku", "EYS");
EYS.addActionListener(this);
pb.add(EYS);
SButton SHS = new SButton("Start Hard Sudoku", "SHS");
SHS.addActionListener(this);
pb.add(SHS);
SButton SMS = new SButton("Start Medium Sudoku", "SMS");
SMS.addActionListener(this);
pb.add(SMS);
SButton SES = new SButton("Start Easy Sudoku", "SES");
SES.addActionListener(this);
pb.add(SES);
SButton GBS = new SButton("Go Back One Step", "GBS");
GBS.addActionListener(this);
pb.add(GBS);
SButton STS = new SButton("Solve This Sudoku", "STS");
STS.addActionListener(this);
pb.add(STS);
this.add(pb,BorderLayout.WEST);
}
}
The above only shows the constructor, we also have:
private void selectNumber(int x, int y)
public Dimension getPreferredSize()
protected void paintComponent(Graphics g)
public void actionPerformed(ActionEvent e)
We also have two other classes used to create push buttons and panels.
class SButton extends JButton
public class SPanel extends Panel
We then get the following window:
Conclusions
I have only been able to test it on Windows XP, Windows 7, and Vista. These machines had the correct Java runtime installed.
If someone could spare the time, it would be nice to know if it works on Linux or Mac.