Wednesday, April 14, 2010

The Tcl War

Weird thing came up twice on the web in the past two days. First was a search for "Tcl nntps", the second was on Reddit.

I've always been an admirer of Richard Stallman. Although I prefer vi to emacs, and GNU Hurd seems like total vaporware, you have to admire the impact Stallman has had, and his consistent application of his values.

But now, I'm afraid I will have to charge him with heinous war crimes against humanity!

His objections are pretty weak (no linked lists?, slow adds?). And to suggest Lisp as a replacement is just silly. Tcl syntax is weird, but Lisp (from Wikipedia)?

(let loop ((n 1))
(if (<= n 10)
(begin
(display n)(newline)
(loop (+ n 1)))))

I have no idea what that does. I think it prints the numbers one to ten...
In Tcl:
for {set i 0} {$i <= 10} {incr i} {
puts $i
}

A lot closer to C. Actually, Tcl has gotten a lot easier for me once I started thinking of it as a prefix type language (like Lisp). Just with [] and {} instead of ().

Saturday, April 10, 2010

Delight

(Continuing my experiences with the D programming language) Hmm, missing some back links before this.

I have been looking into what it will take to program my video card (Nvidia GeForce FX 5200). It's embarrassing how little information is out there. Nvidia used to maintain an open source driver - which only supported 2D. Given their refusal to support 3D, I have to wonder about the quality of the 2D support. There is a project to develop 3D support, but their focus is newer cards (and they are short-staffed).

I've been itching to write a cycle based processor model, and it seems now would be the best time. To mix things up a little, I've decided to write in D.

I've been working (on and off) about a week now, and I must say that programming in D is quite delightful.

Best parts:
  • No IDE needed - I use vi and make, and its no problem at all
  • Enums auto-namespace - all the enums are like RegBytes.BH, no need for crazy C++ kung-fu
  • Built-in array - being able to write:
    mem_[startAddr..startAddr+img.length] = img;

    with auto-bounds checking is a lot nicer than fighting with the dangers of memcopy
  • Writefln - writefln("Null in decoder for byte: ", "%x", op); (format as needed)
I haven't had any real negative experiences. I need to figure out how dependencies work. I'm not sure when I need to recompile a module based on what it imports. I've had to do some make cleans.
There are some gotchas for hardened C++ users, but they are related to improvements:
  • struct and class are different - this is a good thing, but it can be easy to forget. A struct is plain-old-data (like an int), so it is allocated automatically. A class is a pointer, so it defaults to null. You need "ptr = new Class" before you can use it. I ran into this once.
  • Circular import dependencies - you have to avoid them. Sometimes this means you need to break some stuff into a separate file. C++ solves this by using includes to toss everything into one big stewpot and doing multiple passes.

Friday, April 02, 2010

Hello, Graphics World

Of course, a screen shot can make it look like you are much further along than you really are...

I don't have interrupts (so no disk, or keyboard) and I can't create processes, but I can (almost) print "Hello world".

Except, I can't print capital letters, or spaces...

Monday, March 29, 2010

Bugs

With all these successful screenshots, you might think this stuff just turns out correctly on the first try... here is a good example of how tricky it is to get everything right:

I am trying to print the 'H' in "Hello world". It should line up in the upper right of the black box. Instead, there are sets of white pixels spread out in the middle of the screen (look closely, they come in pairs spread apart, with one solid line - the bar of the 'H').

This tells me two things:
  1. My starting point into the video memory is short by about one xterm height
  2. My next row code is off, by maybe 6 or so

Sunday, March 21, 2010

Console Coming Soon

This was a lot of fun!

I am supposed to be enabling interrupts (which will require turning off the PIC, configuring the IOPIC, and enabling the local APIC - a lot of boring and complicated stuff).

So instead, I thought about drawing console windows!

I got to think about fill_rect, and I have enough of the fixed width font ready to print Hello world.

Thursday, March 04, 2010

NewStars Status

Cool little bug managed to waste a week of John's time...

I had noticed a difference in surface minerals for player 1 in 2401. Examining the mining code indicated it was probably due to scrapping the JOAT remote miner.

The code which calculates ship cost and scrap value is pretty complicated, so it seemed natural the bug would be there.

After digging into it, it became apparent that the bug was due to the miner being on a destroyer hull!

This is due to a copy/paste bug in the code which gives players their initial fleets:
In function makeInitialJoatMiner (copied from the make destroyer code)
Ship *design = new Ship(*(pd->gd_->hullList[destroyer_hull]));

Oops.

Sunday, February 28, 2010

Tcl Alarm

Alright, I have laid the ground work for our helper program, now let's see what Tcl can do:

First, we might have multiple things to wait for, and we want to see how much time is left, not just rely on a single sound to notify us:
set $var $tm
lappend ::dl $var
lappend ::al $var

pack [frame .tMain.f$var] -side top -expand 1 -fill x
pack [label .tMain.lT$var -text $tx] -in .tMain.f$var -side left
pack [label .tMain.l$var] -in .tMain.f$var -side right

This is actually a function (proc addLine {var tm tx}), so I can add lines programmatically.

The "lines" are placed in the window, each one representing a timer counting down.
You have parameters:
  • var - the variable which will hold the time, this is displayed elsewhere, so it can be descriptive, and is used inside functions, so it needs the global namespace like "::zombies" or "::arena"
  • tm - the time (in seconds) until the event
  • tx - the text description for the window
al and dl are global lists. dl is used for decrementing the timers, al is all the timers available (for listing the timers to reset)

Now, when we want to decrement all the timers:
proc decList {il} {
upvar $il l

# foreach variable in the list
foreach iu $l {
upvar $iu i

# decrement it
incr i -1

# update the GUI
.tMain.l$iu configure -text [tformat $i]

# check for timer expire
if {$i == 0} {
# remove the timer from the list
set idx [lsearch $l $iu]
set l [lreplace $l $idx $idx]

# flash the text
after 1000 ".tMain.lT$iu configure -fg #008800"
after 5000 ".tMain.lT$iu configure -fg #000000"

playSound
}
}
}

The upvar may not be needed, I was trying to work around not using globals...

tformat is my "time format". It converts a number of seconds into a nice "35 m 0 s" or "1 h 0 m 50 s" string for pretty display. It is left as an exercise for the reader.

Saturday, February 27, 2010

Better Games

(Continuing my treatment of Facebook games)

Given the number of * Wars games there are, there is sadly little content of interest. There is some adventure in exploring new content, but no staying power. They eventually devolve into a treadmill of grinding through new content, and waiting for new content. More jobs with different names dropping equipment with higher numbers and different names.

However, there is one group developing interesting games, and another with one good game (Nitrous Racing, and several boring games: Monster Defense and Fish Life, among others).

The first single-handedly developed five games that I was willing to try. Three of those were pretty good.

The games are Mad Scientist, Robot Builder, Robotico, Star Conquest, and War Machine.

The first three are good enough, that I will break them out separately. Star Conquest was a good try, and worth discussing. War Machine is actually one of the best * Wars games, but, ultimately, is not enough better.

I wanted to give a peak today of a tool I developed to help with the timers (in Tcl of course!).

Let's say you have some zombies cooking in 14 minutes for Mad Scientist, or you need to wait 45 minutes for more energy. You're in the middle of New Stars or NedOS programming, so you might get distracted and forget to look at a clock for an hour or two...

Enter Snack. Snack is a Tcl package for generating sound. It is really easy in wish:

$ package require snack

Now you need to load an alarm sound to notify you that it is time.

$ snack::sound s -load $path_to_file

Then set the alarm:
$ after [expr ($hour*3600 + $min*60 + $sec)*1000] {s play}

That's it. Just set the variables {hour,min,sec} and up-arrow to the after, and hit enter.

Friday, February 26, 2010

PvP

(Continuing my treatment on Facebook games)

I've mentioned PvP a couple times now, and for those who don't know (and haven't googled it yet), it is "Player vs. Player".

Now, some might think the purpose of a game (especially a game on a social network) would be for players to compete. The alternative is PvE (environment), sometimes called AI (which is too generous), or simply computer players. This is how Civilization and a lot of other games work, and work well.

All Facebook games are competitive, in that you can see what your friends and other players have accomplished, and use that to drive you to do more.

In the * Wars games, the PvP aspect is an in-game effect where you improve and the other player is set back (some games lack this PvP aspect, while being similar in most other ways. e.g. Metropolis)

This might seem to be the main focus of the game (it is for some), but in most cases, it is a simply a small annoyance.

In most games, your PvP power is proportional to the number of people in your network (which is usually capped at 500).

Now, no one has 500 friends, much less 500 friends all interested in playing the same game.

This leads to huge "Add Me" threads on the forums, and giant email chains.

If you're not interested in that (and I'm not), there is a simple precaution to avoid serious setback - bank (or spend) your money at the end of a session (and ignore the "defeated" statistic in your profile).

Thursday, February 25, 2010

* Wars

(Continuing from last time)

The biggest part of Facebook games is resource management. Usually, the biggest resource is your own time (micro-management). This is because Facebook is looking for ad impressions, so every time you load a new page, they get revenue.

Still, most games place some limit on your activity. This is usually referred to as "Energy" or "Fuel" or some other stat. It recharges at a flat rate (often 1 point per four minutes). Usually there is a recharge benefit which you can send to your friends.

The * Wars games all have the following character attributes: attack, defense, energy, stamina, health. Stamina is energy for PvP.

Advancement is experience point based, with experience given for jobs (which consume energy). Each level you gain 5 points which can be spent into your attributes. Also, when you level up, your ablative attributes (health, energy, stamina) are recharged

There is a virtuous cycle here.

Energy -> jobs -> experience -> level up (energy refilled) -> spend on energy attribute

In Mafia Wars, there were several times I was able to level up multiple times in a row (especially when coupled with the daily free energy recharge). The experience cost per level grows linearly, and there is a bonus for the first time you "complete" a job (do the job a lot).

So where do the spreadsheets come in?
Not all jobs are created equal. Your spreadsheet should include Xp/Energy and $/energy (money is needed for equipment, which is used in PvP and in enabling new jobs, usually it is not a limiting factor). Some jobs also drop special equipment. You will need a spreadsheet to track what equipment you have and need, and which drops are best (some games have wikis, but it is good to have a local copy).

Most games also have a notion of "investment" (current cash goes into giving cash per time). You can make a spreadsheet detailing the various return rates, but I haven't seen a game where it wasn't easier to just get money through jobs (which you are doing for the xp anyway - that is, high xp/energy and $/energy usually go together).

Wednesday, February 24, 2010

Add Me

A while back, I promised to tell all about Facebook games.

It has been a hard road, full of sacrifice.

I can say there is something new about Facebook games - the "add me" effect.

This is largely by design. Facebook encourages developers to incorporate some social aspect into games.

It's also apparent that this is often done with little or no thought or effort.

The net effect is that "Add Me" games can vary from annoying to unplayable - based on your willingness to add yourself to huge chain lists of email addresses on the forums.

Most games are built on a single dynamic - building. The other distinguishing feature is PvP.

When I say "building", it is basically grinding on your character/empire/whatever. There is little or no danger of loss. It is just a matter of you putting in the time. It can still be fun, especially when there is a wide variety of things to optimize for, and you can build spreadsheets to determine the optimal path (because a good game leads to building spreadsheets! I'm serious!)

The most popular games fall into what I call * Wars (pronounced Star Wars). That is the glob *, meaning "match everything". You have Mafia Wars, Mob Wars, Dragon Wars, Vampire Wars, Fashion Wars. I have played a handful of them, and they all play the same. A lot of other games use the same dynamic, but don't have Wars in the name - Street Racing, War Machine (now called War Metal), Star Conquest, even the RPG Hammerfall is really the same.

More later...

Tuesday, February 23, 2010

OS Info

I must say that Bochs is really a wonderful tool for OS development. The debugger is great: with breakpoints, single step, and full state inspection. It supports command history, and editing the command line.

That said, some stuff just needs to be printed at run time for inspection (particularly anything with loops).

With that in mind, I have forked the CD boot code into a program to dump the relevant structures for inspection. It keeps the screen in text mode, and is printing from 64 bit mode.

Monday, February 22, 2010

NewStars Status

Turn 2!

Here we can see some problems, although nothing earth shattering.

There is some difference in mining or scrapping (the JOAT miner was scapped on turn 1). But the pop growth looks good, as well as resource calculation, and production. I've also checked the resources going into research, and they match.

The x resources out of y is a known Tcl bug. I just put "x of x", and don't bother to include the research tax...

There should be a WM scout visible, but I need to create the P2 orders to make that happen...

Monday, February 15, 2010

Aqua Screen of Life

Oooh, aahh.

No, I didn't just change the pixel color.

The red screen is now part of the kernel panic function (which is now well tested - remind me to tell the story about the difference between step and next in the debugger, and how I spent an hour trying to figure out why call stopped working in 64 bit mode). If everything goes well, you get the aqua screen, else BOOM! red screen.

Under the covers, the code is now searching memory for the ACPI tables. Find them, you get aqua (actually alternating blue and green pixels, I write two pixels at a time 0x0000FF00_000000FF).

Sunday, February 14, 2010

Red Screen of Death

Check it out!

That beautiful red screen is brought to you by the NedOS boot loader, and the NedOS kernel (which is currently just a rep stosq and an infinite loop).

I was able to fit all the boot loader functionality into one 512 B sector.

It has to:
  1. Retrieve the memory map from the BIOS
  2. Enable A20
  3. Get a list of video modes, pick one, and set it
  4. Transition the system into 64 bit paged mode
The memory map code is kind of a hog. Together with the logic for picking a video mode, the boot loader is nearly 500 B. That is after a lot of effort to minimize code size.

That is too big for a harddrive boot sector (which has 64 B of partition tables and a 2 B signature). I have a version where I strip out all the error checking, that brings the size of the memory map code down significantly. Still, it is currently 433 B - leaving about 10 B to actually load something. Not enough to walk the partition table and figure out on its own what to load. I will have to load something from a hard coded location.

I'd like to be able to draw a text window, and put some text in it...

Saturday, February 13, 2010

New Stars Status

Another day, another bug!

This time, it looks like a bug (or bizarre algorithm) in Stars!

John was kind enough to fix the previous bug.

Now, our Long Range Scout has picked up a ly in the X direction.

The relevant X,Y pairs are:
Finale 78, 80
New Stars 101, 108
Stars 100, 108

The distances are 36.24 ly for New Stars, and 35.61 for Stars. It's really not clear why Stars didn't give up that last ly...

I'm tempted to call "Will Not Fix".

How can our lock step hope to succeed with bizarre bugs like this :(

Friday, January 29, 2010

HTML Canvas

Interesting development. The guys behind FreeCiv have developed a client using the HTML 5 canvas.

I remember looking at a proposal for canvas a while back. It was sorely lacking from the Tcl canvas (if only Tcl had made it as a web standard!).

But, if you can implement FreeCiv in it, maybe it has gotten better (or maybe FreeCiv doesn't use circles...).

Probably worth looking into. A NewStars web client would be nice.

Tuesday, January 26, 2010

NedOS on CD

Booting from a floppy is a good start. But there's just not much you can do with 1.44MB.

I looked into bootable CDs, and they are really nice!
  • You get >600 MB of storage for your OS and app code + read-only data.
  • Writable CDs are cheap and portable, potentially allowing you to run on any machine
  • You don't risk messing up your hard drive (particularly the boot sector)
Best of all, the boot CD spec (El Torito) allows you to load multiple sectors immediately. That means no messing with BIOS read disk routines in the boot loader.

Of course, switching my boot floppy code to CD ran into multiple problems (all stupid ones).
  • The boot code can load into any address. 0 will get you the default (7c00), but just to make sure I could write whatever I want when I need to, I set it to 7c00.
  • Of course, it is a segment address, so I got 7c000, which is near 512K, not 32K, so I was executing uninitialized RAM.
  • Then, when I fixed the segment, I forgot that my makecd program only writes those sectors for new disks, so I still had the old values.
  • The boot floppy code is org 7c3e (to skip the Bios Param Block), but the CD code needs org 7c00.
It took longer than it should of, but I can now boot from CD!

Monday, January 25, 2010

New Stars Status

Hopefully things will pick up...

Here we have our first turn gen, and our first bug!
Our move code has place the destroyer and the probe in the same location, while Stars has them one light year apart. Bizarro. Must be a rounding problem...

I also had to fix the recent file LRU yet again. Hopefully it is correct now.

Tuesday, January 19, 2010

New Stars Status

Not exactly a blitz, but moving along...

Here is player 2. Note, I have fixed the title bar. I did the Stars turn by hand, but the New Stars turn was generated from Tcl!

$ cat orders_P2_2400.tcl
set owd [pwd]
cd ../../../gui/tcl
load ./nstclgui.so
source nsCli.tcl

set nsGui::playerNum [newStars $::ns_open $owd/tiny_sparse_P2_Y2400.xml]
buildMyPlanetMap
set hwPID $nsGui::myPlanetMap(0)

set fid [findFleetByName "Armed Probe #2443026239740"]
sendFleetToPlanet "Armed Probe #2443026239740" [findPlanetByName Pervo]
sendFleetToPlanet "Armed Probe #2443026239740"
sendFleetToPlanet "Armed Probe #2443026239740"

# get a useful scout
newStars $::ns_design $::ns_loadPre scout "Smaugarian Peeping Tom"
newStars $::ns_design $::ns_save

# build it
newStars $::ns_planet $hwPID $::ns_addAtIndex 0 0 1 $::designMap(3)

# set orders for max growth
for {set i 0} {$i < 100} {incr i} {
newStars $::ns_planet $hwPID $::ns_addAtIndex 1 1 3
newStars $::ns_planet $hwPID $::ns_addAtIndex 2 1 4
}

newStars $::ns_save $owd/tiny_sparse_P2_Y2400.xml


Pasting Tcl code is so much easier than C++, a lot fewer < and >!

I had to override the logic for "sendFleetToPlanet" auto-pick. It picks the closest planet, but I wanted to send the Armed Probe on a one-way trip to cover a specific set of planets. The Smaug will cover closer planets.

I had to adjust the speed of the probe in Stars, but the New Stars auto-pick got the speed I wanted, very nice!

New Stars does not show what will finish, that is a very hard problem. I will have to address it at some point, though...