JSudoku

Yet another Sudoku program

Main interface

Down to the basics, here’s what I did:

  1. Generate the whole board with backtracking, randomizing the number I chose at each step and remember the choice, this assures that the board is random, while still keep the algorithm run in an acceptable time (it doesn’t have to regenerate a long track of numbers if it get into some sticky situation). Sudoku board have to keep up with a number of rules that make up a complex vector class, lost in there and you’re done. The other method to generate the board was to swap the rows/column/numbers, it’s safe and much faster but it took more time to implement, and it generates only a subclass of the possible Sudoku class, but it’s a good choice if you don’t want recursive calls in your program.
  2. Difficulty: I implemented a simple, but it’s not good for real application, I think. A good difficulty implementation should have taken humans’ deduction rules into consideration (you should know what are these these if you’ve played Sudoku before), and the algorithm should also make sure that with the given cells, only one solution is possible, this is a continuous generate-remove-check for solutions-remove loop and it’s complex to implement. So, I have only removed a number of cells based on difficulty, the more difficulty chosen, the less given cell there are. This implementation suffers from the above points.
  3. Build a usable Sudoku class’ interface: I deducted from coding that you need to store both the solution and the playing board in the class, provide board and solution get method, the set move method for the board should only accept valid moves, this way you only need to count the number of moves played to know if the player have won or not. This has the drawback that you can’t store invalid values in the board (to visually notify the player of their wrong moves), but it keeps your code clean of unnecessary checks.
  4. Build the interface: If you choose to manually generate the JFrame, JButton and uses a loop to create JTextField, it saves time to point-and-click creating the cells, but you will have to manually calculate the button and frame’s position to get a nice interface; the other way around, you’ll have to create JTextFields 81 times. I choose a hybrid approach: use the designer to design the form, add a JPanel to it, and then add the JTextField in the user interface’s constructor.
  5. Just for kicks: I add a key press handler into the text fields, the handler catches input, and if it’s not a valid number, not correct according to Sudoku rules or some other reason, the cell will be highlighted so the user can see it easily, the hint function is implemented in this way too: it compares what the user have to the solution and highlight the differences.

Creating text fields

    /** Creates new form SudokuInterface */
    public SudokuInterface() {
        initComponents();

        // Automatically arranges the cells into a grid-like layout
        jPanel1.setLayout(new GridLayout(Sudoku.ROWS, Sudoku.COLUMNS));
        fields = new JTextField[Sudoku.ROWS * Sudoku.COLUMNS];
        for (int i = 0; i < Sudoku.ROWS * Sudoku.COLUMNS; i++) {
            fields[i] = new JTextField(1);
            fields[i].setSize(66, 66);
            fields[i].setFont(cellFont);
            fields[i].setName(Integer.toString(i));
            fields[i].addKeyListener(cellInputHander);
            fields[i].setHorizontalAlignment(JTextField.CENTER);
            fields[i].setEnabled(false);
            jPanel1.add(fields[i]);
        }

        // First screen
        String intro = "JSudoku";
        for (int i = 1; i < intro.length() + 1; i++) {
            fields[4 * Sudoku.ROWS + i].setText(intro.charAt(i - 1) + "");
        }

    }

Handling key input

    private final KeyListener cellInputHander = new KeyListener() {

        /**
         * Controls, the user's input, let them input invalid data and display it
         * to avoid confusing the user (higher usability), but this won't be
         * reflected in the actual game, we have to keep track of which cells are
         * invalid, resulting in this complex implementation
         */
        public void keyTyped(KeyEvent e) {
            e.consume();
            int move = 0;
            String moveString = e.getKeyChar() + "";
            try {
                move = Integer.parseInt(moveString);
            } catch (Exception exception) {
                return;
            }
            // If the move is invalid, do nothing, the key won't appear
            int cellIndex = Integer.parseInt(e.getComponent().getName());
            if (!game.set(cellIndex, move)) {
                ((JTextField)e.getSource()).setForeground(cellIncorrectForeground);
                jLabel3.setText("You have just performed an invalid move");
                isInvalid[cellIndex] = true;
            } else {
                ((JTextField)e.getSource()).setForeground(cellEnabledForeground);
                jLabel3.setText("");
                isInvalid[cellIndex] = false;
            }
            ((JTextField)e.getSource()).setText(moveString);
            if (game.won()) {
                JOptionPane.showMessageDialog(rootPane, "You have solved the puzzle!", "Congratulation", JOptionPane.INFORMATION_MESSAGE);
                newGame(lastDifficulty);
            }
        }

        public void keyPressed(KeyEvent e) {

        }

        public void keyReleased(KeyEvent e) {

        }
    };


Like I said, there’s plenty of room for improvement, so here’s the source code if you want to do just that 😉

Object oriented experiment

class Shape {
    // This method will be overridden by its children, even if it's not abstract
    // and its children have not specified @Override
    void draw() {
        System.out.println("Shape drawn");
    };

    @Override
    protected Object clone() {
        return null;
    }
}

class Rectangle extends Shape {
    void draw() {
        System.out.println("Draw rectangle!");
        super.draw();
    }

    // We can change the return type and access of a overridden method from its
    // parent class! Note that access modifier must be the same or more relaxing
    // like private -> protected -> public, but not the other direction
    @Override
    public Rectangle clone() {
        return null;
    }
}
class Triangle extends Shape {
    void draw() {
        System.out.println("Draw Triangle!");
    }
}
class Circle extends Shape {
    void draw() {
        System.out.println("Draw Circle!");
    }
}
public class AbstractClass {
    public static void main(String[] args) {
        Shape s = new Circle();
        s.draw();
        s = new Triangle();
        s.draw();
        s = new Rectangle();
        s.draw();
        
    }
}

Load data into controls in asp.net

Usually when working on windows form, I use this to do the work

        DropDownList1.DataSource = new ApplicationTableAdapter().GetDataBySystemID(1);
        DropDownList1.DataTextField = "Name";
        DropDownList1.DataValueField = "ID";

But surprisingly, when switched to ASP.NET, the above code no longer works, at first I thought it was a problem with the paradigm so I tried to store the data as a session variable but that didn’t work either, until I tried this

        DropDownList1.DataSource = new ApplicationTableAdapter().GetDataBySystemID(1);
        DropDownList1.DataTextField = "Name";
        DropDownList1.DataValueField = "ID";
        DropDownList1.DataBind();

One extra line.

KTouch lession maker

Some of you might have landed on this article searching for the book instead, here it is 🙂

I have been trying to improve my typing by learning Dvorak and so far I’ve been to be able to type more accurately (I’m not talking about speed here :p). I have been using the Grass Soft touch typing program to train on Windows, it is pretty useful except for the limited word list. They claimed that they have included 500 most used word in English. That just doesn’t seem enough to me!

Besides, I have also started to use Linux and I needed a program that will keep me busy on the new platform. Of course in the open source world there’s always a lot of option too choose from, most of them are free too. I have chosen KTouch as it seems to be under active development and also endorsed by KDE.

KTouch with my customized lesson

So far, it’s a great program! It automatically detects your keyboard layout and select the appropriate starting lesson. It have two lesson for Dvorak: ABCD and computer generated. Despite the name, the computer generated lesson does not change as you take it because it’s just a file pre-rendered by the developer. I hit the same obstacle I did with the previous touch typing program: no variety.

Fortunately KTouch allows you to load external lesson files (they are just XML files) and text file; but due to poor application design, the text file won’t let you type the whole file but only the first few sentences. Which means if you want to practice with a long text, you’ll have to split them manually into multiple files.

<?xml version="1.0" encoding="utf-8"?><KTouchLecture>
<Title>Puzo, Mario - The Godfather.txt</Title>
<Comment>This is a lession created from Puzo, Mario - The Godfather.txt</Comment>
<FontSuggestions>Courier 10 Pitch</FontSuggestions>
<Levels>
<Level>
<LevelComment>level 1</LevelComment>
<NewCharacters>a lot :)</NewCharacters>
<Line>Chapter 1</Line>
<Line>Amerigo Bonasera sat in New York Criminal Court Number 3 and waited for</Line>
<Line>justice; vengeance on the men who had so cruelly hurt his daughter, who had</Line>
<Line>tried to dishonor her.</Line>
<Line>The judge, a formidably heavy-featured man, rolled up the sleeves of his black</Line>
<Line>robe as if to physically chastise the two young men standing before the bench.</Line>
</Level>
</Levels></KTouchLecture>

Structure of XML lesson files

So I made a program with C# to make KTouch lesson out of text files. Thanks to C#’s ability to process strings and XML, this has been a fairly easy task, here’s the code:

            const int LinePerLevel = 6;
            const int CharactersPerLine = 80;
            FileInfo Info = new FileInfo(Filename);
            string[] RawData = File.ReadAllLines(Filename, Encoding.Default);
            XmlTextWriter Writer = new XmlTextWriter(Filename + ".xml", Encoding.UTF8);
            Writer.WriteStartDocument();
            Writer.WriteStartElement("KTouchLecture");
            Writer.WriteRaw("rn");
            {
                Writer.WriteElementString("Title", Info.Name);
                Writer.WriteRaw("rn");
                Writer.WriteElementString("Comment", "This is a lession created from " + Info.Name);
                Writer.WriteRaw("rn");
                Writer.WriteElementString("FontSuggestions", "Courier 10 Pitch");
                Writer.WriteRaw("rn");

                Writer.WriteStartElement("Levels");
                Writer.WriteRaw("rn");
                {
                    int LevelCount = 1;
                    int LineCount = 0;
                    string[] LevelLines = new string[LinePerLevel];
                    string Buffer = "";
                    for (int i = 0; i < RawData.Length; i++)
                    {
                        string TrimmedLine = RawData[i].Trim();
                        if (string.IsNullOrEmpty(TrimmedLine))
                            continue;

                        TrimmedLine = TrimmedLine.Replace('“', '"');
                        TrimmedLine = TrimmedLine.Replace('”', '"');
                        TrimmedLine = TrimmedLine.Replace('’', ''');
                        TrimmedLine = TrimmedLine.Replace('‘', ''');
                        TrimmedLine = TrimmedLine.Replace("t", "");

                        if (Buffer.Length > 0 && (Buffer[Buffer.Length - 1] == '.' || Buffer[Buffer.Length - 1] == '?' || Buffer[Buffer.Length - 1] == '!'))
                            Buffer = Buffer + " " + TrimmedLine;
                        else
                            Buffer = Buffer + TrimmedLine;

                        while (LineCount < LinePerLevel && Buffer.Length > CharactersPerLine)
                        {
                            int CutOffSpacePos = Buffer.LastIndexOf(" ", CharactersPerLine - 1);
                            LevelLines[LineCount++] = Buffer.Substring(0, CutOffSpacePos);
                            Buffer = Buffer.Substring(CutOffSpacePos + 1);
                        }

                        if (Buffer.Length < = CharactersPerLine && LineCount < LinePerLevel)
                        {
                            LevelLines[LineCount++] = Buffer;
                            Buffer = "";
                        }

                        if (LineCount >= LinePerLevel)
                        {
                            Writer.WriteStartElement("Level");
                            Writer.WriteRaw("rn");
                            {
                                Writer.WriteElementString("LevelComment", "level " + LevelCount.ToString());
                                Writer.WriteRaw("rn");
                                Writer.WriteElementString("NewCharacters", "a lot :)");
                                Writer.WriteRaw("rn");
                                for (int j = 0; j < LevelLines.Length; j++)
                                {
                                    Writer.WriteElementString("Line", LevelLines[j]);
                                    Writer.WriteRaw("rn");
                                }
                            }
                            Writer.WriteEndElement();
                            LevelCount++;
                            LineCount = 0;
                        }
                    }

                    while (!string.IsNullOrEmpty(Buffer))
                    {
                        while (LineCount < LinePerLevel && Buffer.Length > CharactersPerLine)
                        {
                            int CutOffSpacePos = Buffer.LastIndexOf(" ", CharactersPerLine - 1);
                            LevelLines[LineCount++] = Buffer.Substring(0, CutOffSpacePos);
                            Buffer = Buffer.Substring(CutOffSpacePos + 1);
                        }

                        if (Buffer.Length < = CharactersPerLine && LineCount < LinePerLevel)
                        {
                            LevelLines[LineCount++] = Buffer;
                            Buffer = "";
                        }

                        if (LineCount >= LinePerLevel)
                        {
                            Writer.WriteStartElement("Level");
                            Writer.WriteRaw("rn");
                            {
                                Writer.WriteElementString("LevelComment", "level " + LevelCount.ToString());
                                Writer.WriteRaw("rn");
                                Writer.WriteElementString("NewCharacters", "a lot :)");
                                Writer.WriteRaw("rn");
                                for (int j = 0; j < LevelLines.Length; j++)
                                {
                                    Writer.WriteElementString("Line", LevelLines[j]);
                                    Writer.WriteRaw("rn");
                                }
                            }
                            Writer.WriteEndElement();
                            LevelCount++;
                            LineCount = 0;
                        }
                    }
                }
                Writer.WriteEndElement();
            }
            Writer.WriteEndElement();
            Writer.WriteEndDocument();
            Writer.Close();

It does:

  • Convert Unicode punctuations to their ordinary counterpart. For example “ and ” will be converted to “
  • Trim and combine different lines from different paragraphs to they’ll fit into the line format of KTouch. KTouch does not work well with long lines (you can’t see much toward the end of the line) so by default the line is trimmed at 80 characters

For a text source to practice, I decided to drop by project Gutenberg (FYI they digitize out-of-copyright books). They offer a range of about 3000 books in a dozen of languages to choose from. The books are mostly in plain text format, which is just perfect for this purpose.

The first novel I have chosen to type is Godfather by Mario Puzo 🙂 If you want to have a ride too then here’s the lesson maker’s source and here’s the lesson file for Godfather (note that due to bugs in KTouch, some characters toward the end of each lesson will disappear). The lesson file has over 2000 levels available for practicing.

Advanced C# splash screen

I once posted about how to make a splash screen with C#; yet it’s still a rectangle. While it’s true that you can replace my picture with something that have curvy edges, you’ll have aliased edges i.e. crooked and crude pixels around the edges.

Example of an aliased picture, the edges are not smooth and you can't see through the semitransparent parts

There’s a solution: alpha-blend the picture and you can see through the form; pixels with alpha value of neither 0 or 255 will be mixed appropriately with the background.

Alpha-blended picture. The edges are smoother and you can see through the form

To achieve this, you have to write your custom painting function with windows API, specifically this one

[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

Which can be a daunting task. Luckily we have someone from Visual C# kicks did the hard work and released the source for public use! But that’s not the end of my story just yet. I wanted the splash screen to fades in and out. The timing part was easy, just a timer and several more lines of code and it’s done.

        enum Phases {
            FadeIn,
            Hold,
            FadeOut
        };
        Phases CurrentPhase = Phases.FadeIn;
        int FadeInStep = 0;
        const int FadeInLast = 20;
        int HoldStep = 0;
        const int HoldLast = 80;
        int FadeOutStep = 20;
        const int FadeOutLast = 0;
        const int OpacityMultiplier = 5;

        private void timerFade_Tick(object sender, EventArgs e)
        {
            if (CurrentPhase == Phases.FadeIn)
            {
                if (FadeInStep < FadeInLast)
                {
                    FadeInStep++;
                    this.Opacity = (OpacityMultiplier * FadeInStep) / 100.0;
                }
                else
                    CurrentPhase = Phases.Hold;
            }
            else if (CurrentPhase == Phases.Hold)
            {
                if (HoldStep < HoldLast)
                {
                    HoldStep++;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    CurrentPhase = Phases.FadeOut;
            }
            else if (CurrentPhase == Phases.FadeOut)
            {
                {
                    FadeOutStep--;
                    this.Opacity = (OpacityMultiplier * FadeOutStep) / 100.0;
                }
                else
                    this.Close();
            }

I have even altered the custom paint code to utilize the form’s transparency factor

                //Set up blending options
                API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
                blend.BlendOp = API.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = (byte)(255 * this.Opacity);
                blend.AlphaFormat = API.AC_SRC_ALPHA;

                API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, this.BackColor.ToArgb(), ref blend, API.ULW_ALPHA);

But that didn’t work to my expectation! The form is fading in and out gradually but the alpha blending effect is lost.

Fugly!

After fiddling around, I figured out that the custom paint code somehow didn’t override all the necessary painting functions and the setter of this.Opacity call those functions every time it’s changed. Searching around the list of functions can be overridden I found nothing interesting

That function doesn't help...

So I created a new variable and leave the form’s default Opacity alone. After all, if I have adjusted transparency myself in the custom paint function, who needs .NET’s alpha-blend-incapable render? The code above becomes:

        double MyOpacity = 0;

            if (CurrentPhase == Phases.FadeIn)
            {
                if (FadeInStep < FadeInLast)
                {
                    FadeInStep++;
                    MyOpacity = (OpacityMultiplier * FadeInStep) / 100.0;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    CurrentPhase = Phases.Hold;
            }
            else if (CurrentPhase == Phases.Hold)
            {
                if (HoldStep < HoldLast)                 {                     HoldStep++;                     this.UpdateFormDisplay(this.BackgroundImage);                 }                 else                     CurrentPhase = Phases.FadeOut;             }             else if (CurrentPhase == Phases.FadeOut)             {                 if (FadeOutStep > FadeOutLast)
                {
                    FadeOutStep--;
                    MyOpacity = (OpacityMultiplier * FadeOutStep) / 100.0;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    this.Close();
            }
        }
                //Set up blending options
                API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
                blend.BlendOp = API.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = (byte)(255 * MyOpacity);
                blend.AlphaFormat = API.AC_SRC_ALPHA;

                API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, this.BackColor.ToArgb(), ref blend, API.ULW_ALPHA);

And Voilà!

Alpha blended splash against my blog in the background, you can see through the semi-transparent form

You can get the project, source code and complied binary here.