Wednesday, May 25, 2011

git avert disaster

Let me start by saying I hate hg. I should like it, since it is fundamentally the same as git. I want to like it, but it just is unlikeable.
  1. It is too complicated. In git there are commits (patches, content) and heads (names). Mercurial has versions, patches (in mq), branches, tags, bookmarks. Maybe more.
  2. It is disjointed. In git, everything is integrated. In hg, everything is an extension. The extensions work fine, one at a time. But bringing multiple extensions together doesn't always work well. Also, the tab completion only supports some things.
  3. It keeps messing up. This is the really scary part. I haven't lost anything, but twice now all my subrepos have gone into a "disconnected head" state (once after a crash, but once all by itself). I also sometimes get weird "unknown version" errors. It generally just requires "hg onsub 'hg up'", but sometimes greater voodoo is required.
That said, I encountered my first git problem recently.
  1. Install Cygwin git on Windows
  2. Intall Linux dual boot, boot in Linux, install git
  3. Mount the NTFS under Linux (hmm, maybe not a good idea here!)
  4. Use Linux git to manipulate the Cygwin repo (playing with fire!)
  5. Rebase the repo
  6. Boom
Yea, maybe I was asking for this one. The problem is that under Cygwin all the files have 644 permission, while Linux mounts NTFS with 755. Git stores the permissions flag under version control, so it is seeing every file change all the time. Rebasing causes massive conflicts all the time (since the history is all 644, but the mount point won't allow anything but 755).

So, here I am in some disconnected head state, with all my patches gone from the rebase. What to do?

I forgot what I did, but I got most of my patches applied. Except one fell on the floor, and didn't show up in the history anymore (well, the commit was there with the log message, but the patch was empty).

Fortunately, there is a file in .git called "ORIG_HEAD" or something similar. Cat it, and "git checkout". Cp the bad files off to a separate space and "git checkout" back. Diff and patch, commit. All fixed!

Yea git!

Sunday, May 22, 2011

Stuff I've read lately

"The Oxford Book of Science Fiction" (ed. Tom Shippey) - This was really excellent. It covers about 100 years of SF, and most of the stories I hadn't read before. Really unusual.

Thursday, May 19, 2011

String Madness

I read earlier today that Denis Ritchie (or Brian Kernigan, I get them mixed up) hates C++.

Now, why would anyone hate C++?

Oh wait, I had to do some case insensitive string compares today in C++. Let's see how to do it:
  1. Solution 1, download hundreds of megabytes of Boost - meh
  2. Comment #2, Unicode is broken, yea Unicode!
  3. Solution three:
struct ci_char_traits : public char_traits<char> {
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); }
static int compare(const char* s1, const char* s2, size_t n) {
while( n-- != 0 ) {
if( toupper(*s1) < toupper(*s2) ) return -1;
if( toupper(*s1) > toupper(*s2) ) return 1;
++s1; ++s2;
}
return 0;
}
static const char* find(const char* s, int n, char a) {
while( n-- > 0 && toupper(*s) != toupper(a) ) {
++s;
}
return s;
}
};

typedef std::basic_string<char, ci_char_traits> ci_string;

Muahahahahahaa! That's evil (Note: I handled all the freaky <> using Tcl, yea Tcl!). In case you're wondering:
string map "< {&lt;} > {&gt;}" $code


Solution 4, fall back to C. Thanks, that's great. Also, note it is different on different platforms, yea C. It also doesn't work on Unicode.

In Tcl?
string compare -nocase $str1 $str2


Works on most Unicode, but, hey Unicode is broken what do you want?

Sunday, May 15, 2011

True Atlanteans

Lots of progress, haven't had time for updates. I am building a client for Atlantis, similar to Atlantis Little Helper (see screenshot).

Here is what I have so far:

Obviously, not as much functionality right now, but it is improving quickly. The main advantages will be that I can understand this code (currently less than 500 lines of Tcl).

Also, the code uses an internal database to store the turn information, so should be less vulnerable to disruptions (and more easily support multiple games).

This will be the main visualization tool for any changes we make to Atlantis (currently, I have already hacked in the new turn format).

Thursday, May 05, 2011

Tcl Object Notation

In the beginning, everything was a plain text file or a binary file. Binary files were easy for computers (just copy the bytes from disk into memory) and hard for people. Text files were easy for people and hard for computers.

On top of this, things were always changing. So the binary files from Word 1.0 didn't want to be read into Word 2.0 (well, 2.0 would upgrade them - but eventually, support could disappear). Text files have a way of expanding into their own Turing-complete language.

Then some mega-genius said, "Hey, let's make a text format that easy for computers and people, and backwards/forwards compatible! We'll call it XML."

And so we got this:
<?xml version="1.0"?>
<NSTARS_UNIV DIMENSIONS="2" X="400" Y="400">
<UNIV_HDR>
<STAR_COUNT>2</STAR_COUNT>
</UNIV_HDR>
<GAME_YEAR>2406</GAME_YEAR>
<TECH_COSTS>50 80 130 210 340 550 890 1440 2330 3770 6100 9870 13850 18040
22440 27050 31870 36900 42140 47590 53250 59120 65200 71490 77990 84700</TECH_C
OSTS>
<COMPONENTFILENAME>newStarsComponents.xml</COMPONENTFILENAME>
<HULLFILENAME>newStarsHulls.xml</HULLFILENAME>
<PLAYERFILEBASENAME>tiny_sparse</PLAYERFILEBASENAME>
<MASTER_COPY>1</MASTER_COPY>
<NUMBER_OF_PLAYERS>2</NUMBER_OF_PLAYERS>
<PLAYERDATA>
<RACELIST>
<RACE>
<SINGULARNAME>Ugly Duckling</SINGULARNAME>
<PLURALNAME>Baby Swans</PLURALNAME>


That's the first 771 bytes of the NewStars master file (which is 3530 bytes in full). That's turn 6 for a tiny universe. I generated a huge turn once, it was many megabytes... Every AJAX request is generating and shipping around stuff like this. If you wonder why servers can't handle many clients, why the Internet is so slow (even though we have a lot more bandwidth than the old 56k modems), and clients are so slow - XML is a big part of it.

Then another (smarter) genius said, "All these angle brackets and matching tags are just a pain. Why can't we have a simpler format?" That gave us JSON (JavaScript Object Notation, and AJAJ). Here is the JSON file from my Space Battle project:
{
"force1" : {
"name" : "Imperials",
"ships" : [
"idest"
]
},

"force2" : {
"name" : "Bugs",
"ships" : [
"bship"
]
}
}


A lot more concise. But, why do I need all the quotes and colons? Why are some things in square brackets, while others are in curlies? We can do better:
Name {Tester (3)}
FactionType { (War 1, Trade 1, Magic 1)}
Month March
Year 1
VerString {4.1.0}
Rulesetname {Ceran}
Rulesetversion {2.0.4 (beta)}
Newssheet 1
Password {none}
TurnCountdown -1
Quit 0
TaxRegion 0
MaxTax 10
TradeRegion 0
MaxTrade 10
NumMage 1
MaxMage 2


This is "Tcl Object Notation" (TON). Just as JSON yields a JavaScript dictionary, this is a Tcl dictionary. Since everything is a string, no quotes needed. No colons (dictionaries are lists with "key" "value" pairs). You just need {} for things which might have spaces (or sub-dictionaries).

This will be the turn file format for the True Atlanteans, Atlantis PBEM GUI Client.