Archive for the ‘Works’ Category

goproblems.com sorter

Tuesday, October 10th, 2006 by Agro Rachmatullah

goproblems.com is a wonderful community site containing thousands of… well… go problems. Problems are presented and solved using a Java applet. For me, the best thing about the site is that it is downloadable.

The downloaded problems can be navigated using the “previous” and “next” button. However, it iterates through problem id, which for me isn’t very useful.

My idea is to traverse the problems from the easiest to the hardest. My first solution was to copy-paste the contents of the “all problems” index into a spreadsheet and sort them there. Because the links in the speadsheet is clickable, I would navigate the problems from the spreadsheet.

My second solution was to use the sorted spreadsheet data to generate a set of htmls which allows me to traverse the problems without leaving the browser. Because OpenOffice.org Calc uses XML, parsing it was quite doable (I didn’t use System.XML, just some ad hoc parsing). The result was a frame based solution. The original goproblems.com page is contained in a frame and there is another frame for navigating backwards/forward. Bad usability because there were two sets of navigational buttons and the difference wasn’t obvious. Not to mention that frames are ugly.

Some days ago I downloaded a the latest goproblems.com snapshot (around 1000 new problems from my last one). I then finally forced myself to make a final solution. It was essentially a complete rewrite. I made the program read the difficulty directly from the html files, removing the need for manual sorting inside OOo Calc. I also made the program modify the URL of the already-existing navigational buttons, removing the need for frames.

So, here’s the result:

Front page of sorted goproblems.com

The program is here and the source code is here. It is made in C# so Mono or Microsoft .NET needs to be installed. To run it, just type:

gpsorter [input-directory] [output-directory]

or using Mono:

mono gpsorter.exe [input-directory] [output-directory]

Where [input-directory] is the directory of the unpacked and orginal goproblems.com.

Memorizing kanji stroke order: Mnemosyne + StrokeReplayer

Tuesday, October 3rd, 2006 by Agro Rachmatullah

I learned all grade 1 and 2 kanji some time ago. I could recognize the shape, know at least one reading and its meaning, and draw it properly. However, because lack of usage, I now forget how to write many of the kanji.

To not let it happen again, I’m going to mnemosyne all of them. Here’s how it looks in Mnemosyne:

Mnemosyne asking me how to write a kanji

When faced with kanji writing questions, I must switch to a program I developed for this purpose, StrokeReplayer:

StrokeReplayer

I then draw the kanji in the top left canvas by holding the left mouse button. Right clicking will delete the last stroke and middle clicking will delete all the strokes. The stroke order and direction can be replayed:

StrokeReplayer replaying a stroke

How do I know whether I answered correctly? Just enter the kanji or its JIS code in the textbox and the references will appear:

StrokeReplayer showing Taka stroke order

The default is Taka which uses Java applet. To see the reference from KanjiCafe which is an animated GIF image, just click its link:

StrokeReplayer showing KanjiCafe stroke order

The last reference is just a still text which shows how the character is rendered in two fonts (MS Gothic and MS Mincho):

StrokeReplayer showing still text

I’ll probably add other kanji stroke order database when I download them.

After the review, I must go back to Mnemosyne to grade myself. The answer section of Mnemosyne shows the correct character. This is so that I do not accidentally test the wrong character, for example 生 instead of 活 which both sounds and mean the same (ignoring nuances). The difference is in its grade which is shown in the category, but I can picture myself overlooking it or forgetting which is which.

Yes, this process is more complicated than it should be. Mnemosyne seriously needs plugin support or at least hyperlink and applet support.

Anyway, I’ve finished drilling my first 1500 words. I’m too lazy to give an accurate count, but I seem to score above 95% in my first drill (both the Japanese to English and the reverse version). Many mistakes are because of string inequality, for example answering “left” instead of “left hand side” and “to think” insead of “to think about”. After that I just repeat the stuffs I got wrong. I then repeat the whole thing again and again until I decided that it was enough.

I’m now writing the stroke order of grade 2 kanji in my reference book, moving them from the mixed and messy “reference & practice” book. After that I’ll add them to Mnemosyne. I’ve done the same thing for grade 1 some days ago.

After the grade 2 kanji is done I’ll finally advance to learn something new: grade 3 kanji!

PS: The stroke replayer is pretty cool. Since the example used a really dull character here’s another one:

StrokeReplayer replaying 愛

Starting a new process on the .NET Framework

Saturday, September 30th, 2006 by Agro Rachmatullah

To run another program from a .NET program, call the System.Diagnostics.Process.Start method. An example C# program is:

using System.Diagnostics;

class RunNewProcessTest
{
	static void Main()
	{
		Process.Start("notepad");
	}
}

In the example, Notepad will be invoked.

A document can be given to the start method (for example “c:\test.txt”). If there is an associated application for the file, the application will launch. Else an exception will be thrown.

If any arguments must be given to the invoked process, put it in the second argument of the Start method. An example is:

Process.Start("notepad", "c:\\test.txt");

(Note: backslash (’\') must be escaped)

In this regard, the Process.Start method is different from C or C++’s system function (defined on stdlib.h (C) or cstdlib (C++)), which would be:

system("notepad c:\\test.txt");

Embedding a resource into a .NET assembly and loading it

Saturday, September 30th, 2006 by Agro Rachmatullah

Sometimes our program needs resources in the form of files. An example is icons to show on buttons. Another example is the text of GNU GPL for display on a certain dialog box. Kanji dictionaries might use the text-based kanjidic file.

The obvious approach is to put the files on the file system. The advantage is that the resources can be updated or replaced easily. The disadvantage is file system clutter and external dependency (remove the resources and the program won’t run).

The other solution is to embed the resources in the executable or library itself. In this way, the executable/library will be self-contained.

Here’s how to do it in .NET using C#.

For the purpose of this guide, suppose the file to embed is test.txt which contains:

Line 1 of test.txt
Line 2 of test.txt

To embed the file into an assembly, just add the switch /res:FILENAME when compiling. For example, if the source code is Embed.cs then the command to compile should be:

csc /res:test.txt Embed.cs

(Replace csc with mcs if Mono’s compiler is used)

If the file is disassembled using Mono’s monodis, this will be found:

.mresource public 'test.txt'
{
}

which indicates that the file test.txt is indeed embedded into the assembly.

An example of a program which loads the resource is:

using System;
using System.IO;
using System.Reflection;

class Embed
{
  static void Main()
  {
    Assembly a = Assembly.GetAssembly(typeof(Embed));
    using(Stream s = a.GetManifestResourceStream("test.txt"))
    {
      using(StreamReader sr = new StreamReader(s))
      {
        Console.WriteLine(sr.ReadToEnd());
      }
    }
  }
}

The class from the System namespace that is used is Console. From System.IO is Stream and StreamReader while from System.Reflection is Assembly.

First, load the assembly that contains the resouce. Because the only class in the assembly is Embed, it is used to get the assembly:

Assembly a = Assembly.GetAssembly(typeof(Embed));

Now is the real meat. To open the stream to a resource in the assembly, call GetManifestResourceStream:

using(Stream s = a.GetManifestResourceStream("test.txt"))

The Stream object returned is just like a Stream object when a file is loaded from the file system. After that it’s just normal I/O.

If for some reason the embedded filename must differ from the original filename, use the option:

/res:FILENAME,EMBEDDED_FILENAME

McCune-Reischauer Converter

Wednesday, September 27th, 2006 by Agro Rachmatullah

I like to use the McCune-Reischauer form of Korean Go players’ name because that’s what Sensei’s Library use for page titles. Therefore, it is “Yi Se-tol” not “Lee Sedol” and “Yi Ch’ang-ho” not “Lee Changho”. Unlike other romanizations, we can reconstruct the hangul correctly from its McC-R form.

It was a pain in the arm to write articles containing Korean Go player names because I had to repeatedly look at the reference and do lots of “find & replace”. Therefore I made a small tool to do that job:

$ mcrconverter --help
This program will change Korean Go player names in a file into
their McCune-Reischauer form.

Usage:
mcrconverter [options] file:
    change the contents of a file
or
mcrconverter [options] folder:
    change the contents of SGF files in a folder

Options can be:
–change-file-name:
    also changes the file/folder name
–recursive:
    search for files inside subfolders recursively

Other than useful for writing articles, this tool can also be used to mass-rename the contents of an sgf file, and even the filename itself.

The source and executable are here (requires .NET Framework 2.0).

Conditional execution in bash

Sunday, September 24th, 2006 by Agro Rachmatullah

For some reason, I needed to run a program, but not if another program is running (can be the same program).

After googling for a bash tutorial, I was able to create the script:

ps aux > psinfo
cat psinfo | grep FORBIDDEN_PROGRAM > programinfo

if [ `wc -l < programinfo` = "0" ]
then
	PROGRAM_TO_RUN
fi

ps is used to list all processes running on the system. grep is used to display all occurences of the string FORBIDDEN_PROGRAM from the output of ps. The output of ps isn’t directly piped to grep, e.g “ps aux | grep FORBIDDEN_PROGRAM” because of the unpredictable behaviour of piping. Sometimes “grep FORBIDDEN_PROGRAM” is started before ps, making 1 entry of the string FORBIDDEN_PROGRAM in the output of ps if FORBIDDEN_PROGRAM is not running. However, sometimes grep is started after ps, which gives a count of 0 if FORBIDDEN_PROGRAM is not running.

wc is used to count the number of lines in a file (and is able to count other things too).

Terjemahan artikel utama IGN “Goama” 22

Tuesday, September 19th, 2006 by Agro Rachmatullah

Sekolah Baduk (Igo) Yu Ch’ang-hyeok

(Diterjemahkan ke bahasa Inggris dari majalah Korea “Baduk World” Mei 2004 oleh Alexandre Dinerchtein)

Yu Ch’ang-hyeok, dan-9 (salah satu pemain terkuat Korea di pertengahan 1990-an) membuka sekolah Igo anak-anak pada April 2004 bersama sahabat terbaiknya, Ch’oe Kyu-pyeong, dan-9. Ini bukanlah sekolah pertama mereka. Sebelumnya mereka pernah mendirikan klub untuk pemain muda profesional, yang berjalan sangat sukses selama 16 tahun. Kami mengunjungi sekolah mereka dan mewawancarai pendirinya.

Sekolah ini dibagi menjadi beberapa ruang kecil. Saat memasuki ruang pertama, kami melihat 4 pemain pro: Park Yeong-hun, dan-5 (sekarang dan-9), Yi Cheong-u, dan-4 (dan-5 pada 2005), Kim Eunseon, dan Kim Sesil (keduanya wanita, sama-sama dan-1). Ch’oe Kyu-pyeong, dan-9 adalah guru utama Park waktu dia masih amatir. Sepertinya, Park sekarang lebih kuat.

Saat ini hanya ada 7 murid. Mereka muda dan berbakat. “Kita punya beberapa anak jenius, tapi klub Igo lain juga punya. Susah untuk memastikan apakah mereka bisa mencapai level pro, semua akan tergantung usaha mereka,” kata Ch’oe Kyu-pyeong, dan-9.

Sekolah ini dibuka dari pukul 8 pagi sampai 10 pagi. Yu Ch’ang-hyeok, dan-9 selalu mendampingi muridnya kecuali kalau ada jadwal turnamen.

Kami bertanya, “Bagaimana cara anda mengajar mereka?”. Dia menjawab, “Mereka bisa dengan mudah belajar opening, joseki, dan persoalan hidup mati dari buku. Jadi saya berusaha menciptakan atmosfir “self-learning” di sekolah ini. Hal utama yang saya lakukan adalah mengulang dan mengomentari permainan mereka. Banyak murid saya yang kemampuan membacanya sangat bagus, dan bahkan pemain pro tingkat tinggi tidak bisa membuat mereka lebih kuat dalam persoalan hidup mati. Tapi kita bisa mengajarkan mereka banyak hal lain.”

Beberapa berpendapat bahwa terlalu dini bagi Yu Ch’ang-hyeok, dan-9 untuk mengajar anak-anak, karena mereka percaya bahwa dia masih bisa berprestasi di panggung profesional. Yu Ch’ang-hyeok, dan-9 menjelaskan keputusannya: “Memang benar bahwa saya masih bermain serius, tapi saya tidak akan berada di puncak selamanya. Saya berpikir banyak tentang masa depan saya dan memutuskan bahwa saya akan menikmati mengajar Igo dibanding pekerjaan lain. Mimpi saya adalah menemukan murid yang bisa menjadi elit di dunia Igo Korea.”.

Yu, dan-9 juga mengatakan beberapa hal tentang murid-muridnya: “Seseorang mengatakan bahwa kami hanya mengambil insei dari Asosiasi Baduk Korea, tapi itu tidak benar. Kami lebih suka mengajar anak yang masih sangat muda, walaupun dia tidak sekuat insei. Menurut saya, tidaklah terlalu baik mengundang murid kuat dari klub dan guru lain, dan dalam kasus tersebut kami selalu meminta izin dari tempat belajar lamanya. Kami tidak mendirikan sekolah ini untuk menghasilkan uang, jadi moralitas selalu kami jaga. Kalau kami melihat bahwa seorang anak tidak mungkin menjadi pro, kami akan menghubungi orang tuanya dan meminta mereka mencari masa depan lain. Saya percaya, dalam beberapa kasus lebih baik mencari jalan lain, melanjutkan Igo hanya sebagai hobi.”

Terakhir, kami menanyakan Yu, dan-9 tentang situasi dunia Igo modern.

“Master Jepang jauh tertinggal di belakang. China berusaha mencapai level kami tapi itu tidaklah mudah. Negara mereka sangat besar dan susah untuk membuat sistem pembelajaran tingkat tinggi seperti di Korea. Beberapa kali mereka mengontak kami dan menyarankan kami untuk menerima murid dari China, tapi kami menolaknya terutama karena alasan bahasa,” kata Yu Ch’ang-hyeok, dan-9.

Yu Ch’ang-hyeok, dan-9 dan Ch’oe Kyu-pyeong, dan-9 adalah guru hebat dan kita akan melihat bagaimana mereka mengubah situasi dunia modern Igo.

Diterjemahkan ke bahasa Indonesia oleh Agro Rachmatullah.

“You are welcome to republish any text material from the IGN “Goama” without commercial purposes: please note the source and put the link to http://gogame.info/.”

Counting from 1 to 59 in Japanese

Tuesday, September 19th, 2006 by Agro Rachmatullah

Because some number kanji can be read in many ways, counting can be confusing to a beginner. The kanji for 44 is simply 四十四. However, how do we read it? よんじゅうし, よんじゅうよん, しじゅうよん, or しじゅうし? Only one correct reading, or more than 1 correct way to do it?

Tanaka Reina in Futarigoto

I found a real-life example that should shed a little light on this matter. In the TV show Futarigoto, Tanaka Reina of Morning Musume shows her ability to stand using her hands and head. While doing so, she times herself, counting from 1 onwards.

This example won’t invalidate other readings, however it does give us one way to correctly count. Here’s how she counts:

1: いち
2: に
3: さん
4: し
5: ご
6: ろく
7: しち
8: はち
9: く
10: じゅう
11: じゅういち
12: じゅうに
13: じゅうさん
14: じゅうし
15: じゅうご
16: じゅうろく
17: じゅうしち
18: じゅうはち
19: じゅうく
20: にじゅう
21: にじゅういち
… (same pattern)
30: さんじゅう
31: さんじゅういち
… (same pattern)
40: よんじゅう
41: よんじゅういち
… (same pattern)
50: ごじゅう
51: ごじゅういち
… (same pattern)
59: ごじゅうく

There are two things to note, probably specific to this kind of situation. First, the “じゅう” is spoken as only 1 mora, i.e. “じゅ”. Second, if the number consists of 2 or more mora and ends with a vowel, then the final vowel is oftenly omitted or almost unheard. Therefore it sounds like “ich”, “ni”, “san”, “shi”, “go”, “rok”, “shich”, “hach”, “ku”, “ju”, “juich”, “juni”, “jusan”, “jush”, “jugo”, “jurok”, “jushich”, “juhach”, “juk”, …

(This is like “tu, wa, ga, pat, …, dua satu, dua dua, …” instead of “satu, dua, tiga, empat, …, dua puluh satu, dua puluh dua, …” in Indonesian.)

I’ve prepared the audio file (396 KB) of Reina counting. The file is in the free Ogg/Vorbis format, and Windows user might need to download the codec. It is made using Audacity, a free digital audio editor.

PS: There are some interjections between the counting. First is between 19 and 20 (”It is getting tough”) and second is after 59 (”I passed 1 minute!”). After 59, she counts from 1 again. In the end she says “Let’s stop now.”.

私のfirst 1500 words (another edition)

Saturday, September 16th, 2006 by Agro Rachmatullah

The first printout of my first 1500 (or so) words is optimized to memorize the English meaning of a Japanese word. This is because the format is:

KANJI     KANA     ENGLISH_1, ENGLISH_2, ...

So, to drill the words, I cover the English meaning (and kana, if kanji exists) with a paper and then try to answer it.

For drilling the reverse, the ideal format is:

ENGLISH     KANJI_1 (KANA_1), KANJI_2 (KANA_2), ...

This time, it’s the kanji and kana that’s covered and I must translate from English to Japanese.

Of course, we can use the first format to drill English->Japanese by covering the kanji and kana. However there are two shortcomings:

  • The entries are sorted by kanji/kana. Therefore the sound of the answers will be similar if we drill from the top to bottom. This provides an unwanted clue.
  • Entries with the same English (for example 本日 and 今日 for “today”) is separated. Therefore there is ambiguity when trying to answer some items.

Thus the need for another format.

Preparing the first one isn’t hard because that’s exactly the format I use in my ods file. To prepare the second format, I write a filter for my text transformation program, LineFilter. The result is here.

Keeping a memorized pro game memorized

Saturday, September 16th, 2006 by Agro Rachmatullah

(Written on… Uhm… No more “written on” stuffs. Too much of a hassle.)

I’ve memorized a lot of Takemiya games. However, as time passed, I gradually forgot the moves. Only general impressions like “Takemiya likes san-ren-sei opening” and “Takemiya sometimes reply a keima-gakari with kosumi” remains.

That is undesirable. Ideally, I want to remember the games forever. Therefore, periodic review is a must. Mnemosyne, anyone?

Mnemosyne is a program that helps you memorize items. It will smartly schedule reviews for you. Items that you already know well will be asked rarely, while items that isn’t memorized well will be asked more frequently. I use Mnemosyne to memorize Japanese words, among others.

We can use simple HTML tags like <b> and <i> in Mnemosyne, so I thought applets could be supported. My first idea was to create a **cough** Java applet myself and embed it inside Mnemosyne. However, following the principle of “don’t reinvent the wheel” and considering that I had to dig a lot of documentation just to get a “Hello World” applet running (almost no past experience making applets), I tried finding other people’s applet first.

So, I dug through Hiroki Mori’s “Interactive Way To Go” because I remembered there was a game replayer there. This is what I found:

<applet codebase="./../java" code="mori/go/FreeBoardApplet.class"
   width=300 height=350 align=left border=10>
	<param name=demo value=true>
	<param name=size value=13>
	<param name=init value="B[cc]W[kk]B[dj]W[kd]">
	<param name=moves value="B[fk]W[ki]B[id]W[ic]B[hc]W[jc]B[gd]W[cf]B[ch]W[dc]">
</applet>

The parameters were easy enough to decode. Give it a board size, initial moves, and navigable moves. Coordinates are in SGF style, which is <column><row> and the top left is “aa” (the letter ‘i’ is used).

I usually memorize the first 50 moves of a game. My idea is to divide the moves into 10 moves chunks. So, a Mnemosyne item will test moves 1-10, another for moves 11-20, and so on.

However, if I want to test moves 11-20, it will help if move 10 was marked. Since the applet only marks the last move played (from the “moves” parameter), move 10 shouldn’t be in “init” but in “moves”. It will be a dummy move, just to provide the mark.

Sadly, the applet wouldn’t appear inside Mnemosyne. Therefore I changed the usage scenario into the following:

  • A Menosyne item will contain a kifu review code, for example: “Kifu review: ab” which means game ‘a’ part ‘b’ (part ‘a’ is moves 1-10, part ‘b’ moves 11-20, etc)
  • Upon seeing that code, I will go to Firefox and type “k ab” (’k’ stands for “Kifu review”).
  • Firefox will be configured such that ‘k’ corresponds to a bookmark, such as “http://localhost/kifureviewer/?code=cc.
  • A page will appear with the applet mentioned before. I will replay the kifu and report the result back to Mnemosyne.

The process is quite disintegrated, going back and forth between Mnemosyne and Firefox.

For the web application, I decided to use ASP.NET. This is because I planned to load the game data from the SGF file, and I’m already comfortable with .NET’s file I/O. I used Mono 1.1.7’s XSP as the web server.

My ASP.NET’s experience was almost none, so I need to peek the documentation even to get a Hello World running. Here’s a sample:

<%@ Page Language="C#" %>
<html>
	<head>
		<title><% Response.Write(DateTime.Now); %></title>
	</head>
	<body>
	<%
		for(int i = 0; i < 10; i++)
		{
			Response.Write("<p>Hello world!</p>");
		}
	%>
	</body>
</html>

Other than that, I searched on how to import namespaces (needed e.g. System.IO and I didn’t want to type it all over). The answer is to put something like…

<%@ Import Namespace="System.IO" %>

…below the “Page Language” thing.

Next is searching where to make classes and static functions. The answer is to put it inside…

<script runat="server">
</script>

…which is put before the <html> tag.

The last info I needed was how to fetch the HTTP GET variables. This example…

Request.QueryString["code"]

…will get the value of the HTTP GET variable named “code”.

From there it wasn’t that hard, just parsing the SGF file and giving the correct parameters to the applet. Normal C# coding in which I’m already comfortable with.

I didn’t read the SGF format specification, but guessing the tag meanings wasn’t that hard. I assumed the SGF to be nonbranching and probably a lot of other simplifying assumptions. Below is shown some first characters of an SGF file:

(;DT[2006-09-01]EV[3rd Toyota Cup]RO[semi-final]
PB[Lee Sedol]BR[9p]PW[Lee Changho]WR[9p]
KM[6.5]RE[B+R]SO[Moyo Go Studio]
;B[qd];W[pp];B[dc];W[cp];B[ep];W[ce];B[dn];W[oc];

The relation from game code to SGF file names is in the file “database.txt” (location and file name cofigurable in the aspx file) which contains for example:

a	20060901_Lee-Sedol_Lee-Changho.sgf
b	20060830_Lee-Sedol_Hane-Naoki.sgf

The path of the SGF file is also configurable in the aspx file.

However, testing quickly reveals a critical problem:

Illegal Go position

It is clear that in putting stones from the “init” parameter, the applet didn’t check for captures.

There were two alternatives if I still wanted to use that applet. First is to ask for the source code of the applet and modify it. Second to do the capture checking myself before giving the parameters to the applet.

I chose the latter, utilizing the class inside my (with Fuad, Awang) Go playing program, Sai. A little hack here, a little hack there, and the board was displayed properly:

Legal Go position

Of course the prisoner count was wrong :). I don’t think there is a way to tell the applet about the initial prisoner count.

Anyway, it supports handicap:

Handicap support in KifuReviewer

However, being a Frankenstein solution, there are many things to improve:

  • The applet should be inside Mnemosyne. (at least I informed the maintainer)
  • Dummy move should be eliminated. The board should start with the last move marked.
  • User should guess by clicking on the desired coordinate, not by clicking the next button.
  • Prisoner count should be correct.

At least now I have a non-completely-manual means to memorize a game infinitely long. 1 game is already in Mnemosyne, and a lot more will certainly come…