Writings on what I've learned as I study my two favorite programming languages C++ and Python.

Wednesday, May 28, 2008

C++ Conversion Functions

I have been using C++ for years now but I still couldn't claim mastery of all the syntax yet. Well, I haven't read a C++ book from cover to cover, that's my (shameful) excuse! In a way, however, it makes life with C++ more interesting every time you get to learn new things with it. Today, I bumped into conversion functions, which are typically used for cast conversion.

Let me show you this simple example to illustrate what conversion functions are:

class MyString
{
public:
MyString(const char * ch = "") : _value(ch) {}
virtual ~MyString();

operator const char * () { return _value; }

private:
const char * _value;
};

Here, the operator function is a conversion function that allows the MyString class to be cast as a const char *, as shown below:

#include <iostream>
#include <string>
#include "MyString.h"

int main ()
{
MyString ms("Hello World!");

std::cout << "MyString ms is " << ms << std::endl; //!==> USE CASE 1

ms = "hehehe";

std::cout << "MyString ms is " << ms << std::endl;

if (ms == "hehehe") //!==> USE CASE 2
std::cout << "ms matches const char * !!!" << std::endl;
else
std::cout << "nope." << std::endl;

std::string str = "hehehe";

if (str == static_cast<const char *>(ms)) //!==> USE CASE 3
std::cout << "ms matches std::string !!!" << std::endl;
else
std::cout << "nope." << std::endl;

return 0;
}

The output is as follows:

MyString ms is Hello World!
MyString ms is hehehe
ms matches const char * !!!
ms matches std::string !!!

As we can see, the conversion function allowed MyString to be treated as const char *. In use case 1, the streaming operator converts ms. In use case 2, we have the equality operator calling the conversion. In use case 3, however, std::string's equality operator does not call the conversion function. Hence, we need to cast it explicitly. Without the conversion function in MyString, the three use cases would have generated compilation errors.

That's all for now. Ta-ta!
-- Allister (http://cxxpython.blogspot.com)

Wednesday, May 7, 2008

Sudoku

I'm sort of in between projects right now. I finished my first project last week. The next one won't start till late this week. So to while the time away, I alternated between reading about C++ or Python and played sudoku. Yesterday I thought, "Hey why not try to create sudoku puzzles?" I know, it's been done before. But it's been a while now since I've written anything in Python, so there I go -- no cheat sheets from the Internet!

Okay, for those who don't know what sudoku is, the rule is simple. You have a 9x9 matrix board (similar to a crossword puzzle). Then you have 9 unique characters (normally numbers 1-9). You have to fill each position with a character, with the condition that each character is unique in the row, column, and 3x3 submatrix to which it belongs.

Obviously we'll have create a function that fills the board with the unique characters (we'll use numbers 1-9). Off the top of my head, we'll need a list of lists to represent the rows of the matrix and fill these rows with randomly selected numbers. For each row we provide the list of entries 1-9 that we can reduce according to the which numbers are already present in that row, column and 3x3 submatrix.

import random

def fill_board(board):
"Fill the sudoku board."
bsize = 9
gsize = 3
# initialize ...

Anticipating that this function will have to be called over several iterations, we'll initialize each row and submatrix according to the current contents of the (incomplete) board, resetting the incomplete rows to contain a character that we don't use in the game (here, -1).

# initialize
rows = board
subs = [ [] for i in range(bsize) ]
if len(rows) == bsize and len(rows[0]) == bsize:
# board already has some valid rows
for irow in range(bsize):
if -1 in rows[irow]:
# reset incomplete rows
rows[irow] = [-1 for j in range(bsize)]
continue
# copy existing (incomplete) submatrices
for icol in range(bsize):
isub = (irow//gsize) * gsize + (icol//gsize)
subs[isub].append(rows[irow][icol])
else:
# initialize an empty board
rows = [ [-1 for j in range(bsize)] for i in range(bsize) ]

Now we can complete the of the board:

# complete the board
for irow in range(bsize):
if -1 not in rows[irow]:
# skip a completed row
continue
else:
# reset an incomplete row
rows[irow] = [-1 for j in range(bsize)]

entries = range(1,1+bsize)

# create a list of possible entries to this row
for icol in range(bsize):

# determine to which submatrix the current entry belongs
isub = (irow//gsize) * gsize + (icol//gsize)
sub = subs[isub]

# get the current column
col = [ r[icol] for r in rows ]

# get the possible choice of entries
choices = [ e for e in entries if e not in sub and e not in col ]

# pick a possible entry
if len(choices) < 1:
continue
pick = random.sample(choices, 1)[0]

# record the new entry
rows[irow][icol] = pick
subs[isub].append(pick)

# remove it from the list of possible entries
entries.remove(pick)

# return the board
return rows

Thanks to Python's list comprehension feature, we can easily retrieve each column (see col = [...]) and the list of remaining valid characters (see choices = [...]) in just single lines. The new entry is then simply picked randomly afterwards.

As we've said earlier, using fill_board(board) just once could give an incomplete board, that is, some entries are still using the invalid character (-1). We therefore have to call this function several times.

def iterate_fill():
"A helper method to generate the board within a few attempts."
board = fill_board( [] )
counter = 0
limit = 25
while not is_board_filled(board):
if counter > limit:
break
board = fill_board( board )
counter = counter + 1
else:
return [True, board]

return [False, board]

def is_board_filled(board):
"Check if board is completely filled."
for row in board:
if -1 in row:
return False
return True

Note that we have to put a limit on the number of iterations as we can end up with incomplete rows that just won't fit with the rest of the board. It'd be better (quicker) in that case to just discard the whole board and start from scratch altogether. So we go back from the beginning until we finally get a complete sudoku matrix. Here's the function to do that and display (rather primitively) the output.

def generate():
"Call this function to produce the Sudoku board."
done, board = iterate_fill()

while not done:
done,board = iterate_fill()

for r in board:
print r

We can then save these functions in a module, say sudoku.py. To use it from within a Python session.

import sudoku
sudoku.generate()

The output will look like this:

[3, 7, 4, 1, 5, 8, 6, 9, 2]
[2, 6, 5, 9, 3, 4, 7, 1, 8]
[9, 8, 1, 6, 2, 7, 4, 3, 5]
[5, 9, 6, 2, 8, 1, 3, 7, 4]
[4, 1, 7, 3, 6, 5, 2, 8, 9]
[8, 3, 2, 7, 4, 9, 5, 6, 1]
[7, 5, 9, 4, 1, 3, 8, 2, 6]
[1, 2, 8, 5, 7, 6, 9, 4, 3]
[6, 4, 3, 8, 9, 2, 1, 5, 7]

The next step is hopefully straightforward. According to the desired level of difficulty, we can hide a certain number of entries in this board from the player. We could then add some fancy user interface, and so on. Maybe I could write more about it in the future. But this is all for now. Salut!

-- Allister (http://cxxpython.blogspot.com)

Friday, May 2, 2008

Using a C++ compiler with Eclipse on Windows

I installed the Eclipse CDT in my Windows PCs (both at home and in the office) and I realized that I could simply write C++ code but not build nor run them. The development tools that are so readily and easily available (and I sometimes take for granted) in Linux are simply not that out-of-the-box on Windows. I've installed Microsoft's Visual C++ 2008 at home but I have a difficulty making it work with Eclipse (because obviously they are competing products). So I fired off a google search for a free C++ compiler for Windows and the recommendation I got from what I've read: MinGW (Minimalist GNU for Windows).

So MinGW it is. (I've tried Cygwin, too, but you'll need to run the binaries using Cygwin as well, unlike MinGW which produces native Windows/DOS executables.) Here's what I did to install MinGW and make it work with Eclipse.

First, get the following files from MinGW's Sourceforge download site:
binutils-2.17.50-20060824-1.tar.gz
gcc-core-3.4.5-20060117-3.tar.gz
gcc-g++-3.4.5-20060117-3.tar.gz
gdb-5.2.1-1.exe
mingw32-make-3.81-20080326-2.tar.gz
mingw-runtime-3.14.tar.gz
mingw-utils-0.3.tar.gz
w32api-3.11.tar.gz
You can get newer versions, as long as they are "Current Releases" or you might be in for a nasty surprise later.

Create a folder C:\MinGW. Extract the *.tar.gz files (except gdb) into this folder. I recommend that you use WinRAR for the extraction as WinZip was known to have some issues. Simply run the gdb exe file (double click on it) and to install it as well at C:\MinGW.

After unpacking those files, we now have to make the compiler and other MinGW utilities visible to the rest of the system. Go to Start-> Settings-> Control Panel-> System. Click on Advanced tab, then click on the Environment Variables button. Create a "Path" user variable if don't have it yet and assign (or add) to it C:\MinGW\bin.

That's it, we've just installed MinGW! As a simple check, try opening a command prompt: Start-> Run... and type in "cmd". Or you can also just do Start-> Programs-> Accessories-> Command Prompt. In the command prompt, try typing "g++ -v", then Enter. You should see something like this:

H:\>g++ -v
Reading specs from C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/specs
Configured with: ../gcc-3.4.5-20060117-3/configure --with-gcc --with-gnu-ld
--with-gnu-as --host=mingw32 --target=mingw32 --prefix=/mingw --enable-threads
--disable-nls --enable-languages=c,c++,f77,ada,objc,java --disable-win32-registry
--disable-shared --enable-sjlj-exceptions --enable-libgcj --disable-java-awt
--without-x --enable-java-gc=boehm --disable-libgcj-debug --enable-interpreter
--enable-hash-synchronization --enable-libstdcxx-debug
Thread model: win32
gcc version 3.4.5 (mingw-vista special r3)

H:\>


Now using MinGW with Eclipse is just straightforward. Run Eclipse, and when you create a new C++ project, select the MinGW GCC as your toolchain. With this, you can create native Windows executables and libraries and debug them as well.

-- Allister (http://cxxpython.blogspot.com)

Sunday, April 27, 2008

C++ & Python

C++ and Python. These are two programming languages that have always interested me. C++ is the one that I use every day at work. Python is something that I have played with from time to time but never really got the chance to wield powerfully with my hands. Now that I have more regular working hours, I can now devote a few hours everyday playing with these two.

Although C++ is already quite a mature language, it is still quite a "growing" language with new developments coming up; interesting ones, particularly those that will soon be in the new C++0x standard.

Python is also more than 10 years old and is proven to be a powerful scripting language. And just like C++, interesting changes are on the way, hopefully with the release of Python 3000 in August this year.

The combination of C++ and Python is an even more interesting field, one that will surely be a rich ground for me to discover and write about. So stay tuned and let the fun begin.