Why you lose at bridge

I have recently taken-up studying bridge, and picked up Why you lose at bridge at a second-hand book sale for $1.

My first running joke was “I lose because I don’t play”, but jokes aside, it was a great read, even 63 years after it being published.

The book is aimed at experienced players, offering insight to common mistakes in bidding and game play.  It was interesting jumping ahead of myself, as  I have only read a beginners guide a couple of times, and the subtlety of the bidding signals seemed over the top, but after reading how the hand is played out, and how the inferences are used to guide play, I’ve become motivated to learn correct bidding.  Bridge feels very similar to Preference or 500, just with a mind boggling large set of signaling bids and plays.

Much learning ahead, but I’m excited…

Creating Palette based GIFs

A question was asked on the mailing list (ages ago) about creating 8-bit GIF files.  I proved this code for simple palette based GIFs, so here it is:

using System;  
using System.Drawing;  
using System.Drawing.Imaging;  
using System.Runtime.InteropServices;  
  
namespace Project  
{  
  class ProjectMain  
  {  
    public static void Main()  
    {  
      GenerateBackgroundImage(Color.AliceBlue, Color.Beige, Color.Cyan, 10, 10, 10, @"c:\\image.gif");  
    }  
      
    public static void GenerateBackgroundImage(Color leftColour, Color centerColour,  
    Color rightColour, int leftWidth, int centerWidth, int rightWidth, string path)  
    {  
      
      int width = leftWidth + centerWidth + rightWidth + 2;  
      int height = 10;  
  
      using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed))  
      {  
        Color backColour = Color.White;  
        byte idxBackground = 0;  
        byte idxLeft = 1;  
        byte idxCenter = 2;  
        byte idxRight = 3;  
          
        ColorPalette cp = bitmap.Palette;  
        cp.Entries[idxBackground] = backColour;  
        cp.Entries[idxLeft] = leftColour;  
        cp.Entries[idxCenter] = centerColour;  
        cp.Entries[idxRight] = rightColour;  
          
        bitmap.Palette = cp;  
          
        fillrect(idxBackground, bitmap, new Rectangle(0, 0, width, height));  
        fillrect(idxLeft, bitmap, new Rectangle(0, 0, leftWidth, height));  
        fillrect(idxCenter, bitmap, new Rectangle(leftWidth + 1, 0, centerWidth, height));  
        fillrect(idxRight, bitmap, new Rectangle(leftWidth + 2 + centerWidth, 0, rightWidth, height));  
  
        bitmap.Save(path, ImageFormat.Gif);  
      }  
    }  
  
    static void fillrect(byte colorIndex, Bitmap b, Rectangle r)  
    {  
      BitmapData bmpData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.WriteOnly, b.PixelFormat);  
        
      // Get the address of the first line.  
      IntPtr ptr = bmpData.Scan0;  
  
      // Declare an array to hold the bytes of the bitmap.  
      // This code is specific to a bitmap with 8 bits index per pixels.  
      int bytes = b.Width * b.Height;  
      byte[] Values = new byte[bytes];  
        
      // Copy the RGB values into the array.  
      Marshal.Copy(ptr, Values, 0, bytes);  
  
      for (int y = r.Top; y < r.Bottom; y++)  
      {  
        for (int x = r.Left; x < r.Right; x++)  
        {  
          Values[(y * b.Width) + x] = colorIndex;  
        }  
      }  
  
      // Copy the values back to the bitmap  
      Marshal.Copy(Values, 0, ptr, bytes);  
        
      // Unlock the bits.  
      b.UnlockBits(bmpData);  
    }   
  }  
}  

I would change fillrect, to seperate out the locking, and Marshal calls, to CreateTempBuffer, FillTempBuffer, and WriteTempBuffer functions, if you were to use fillrect more than a couple times.  But as it stands, the code is correct after each call.

End of year

And so we get to the end of the year.  It has been quite a good year personally,

Blog-wise: 92 posts, 133 comments, 18K visits from 141 countries.

Top five viewed pages in 2008:

  1. wpf making a expander look like a groupbox
  2. remote connection to oracle 10g express via odbc
  3. blog
  4. category: curse of the azure bonds
  5. curse of the azure bonds code wheel copy protection

All of which were 2007 posts, so here are the top five viewed pages from 2008:

  1. casio ctk-800 and macbook
  2. slow dns on macbook
  3. how to build a wireshark plug-in
  4. reverse-and-add 110502 in erlang
  5. oracles lag in ms sql server 2005

Only a few minutes left of today, this month and year, so I’ll post now, and go to bed.  See you next year!

New swim record

After over eating on Christmas day, and then feeling very bloated on Boxing day, I went for a swim at the local pool and set a new personal record of 3km (in two sets of 1.5km).  I was shocked by how much energy I had, but my tendons were starting to feel pulled at the end.

On the underwater front, I also swam 50m underwater, the week before.  I have done this a few times this year.  I feel kind of bad that I’ve not played underwater hockey this year at all.  I revisited Tony’s underwater hockey blog today and felt the need to pay some respect.

Star Wars: The Clone Wars

Summary: Boring

I sat down with Jacob to have a geek fest and watch Clone Wars today, but I’ve had to walk away near the end.

I was getting bored to tears with all the talking.  I had such high expectations…

It’s finished now, and Jacob has just declared it disapointing also.

Curse of the Azure Bonds - build 1.0.15

Build 1.0.15 is now available for your gaming pleasure.

  • The game now plays sampled sounds, so you can have that authentic gaming experience!  I even use a blend of PC Speaker sounds and Tandy 1000 sounds.  I’m moving towards the latter, as they sound way better
  • Also this Installer is actually playable, as build 1.0.14 was missing a .dll, and I wonder why nobody mentioned this….
  • Enhanced the ‘Dump Monsters’ debugging, it now dumps all monsters plus details shown in my monsters blog post, to a monsters.html file in the current working directory
  • Started working on decoding the affects and their meaning, to clean-up above monsters.html

Also a warning that the game-play may have been affected by the level of code-refactoring I have currently been undertaking, so watch-out, but feel free to report any issues.

Loving the Visual Studio 2008 compiler

I have been finding lambda and extension methods really helpful in my game port.

Blobs of C styled single linked list code, when changed to generic lists boil down to one line.

like this:

Item item = player.itemsPtr;
while (item != null)
{
  Item next_item = item.next;

  if (item_type == item.type)
  {
    lose_item(item, player); // just removes from linked list.
  }
  item = next_item;
}

to this:

player.items.RemoveAll(item => item.type == item_type);

much nicer.

A new puzzle

The folks across the road Telogis are hiring, and they have a puzzle/quiz on their web site.

I’ve my solutions don’t seem correct… and I’m not sure of the language the code is written in.

Some assumptions that may effect the result:

  • the number precession and overflow behaviour
  • the empty array set indexing behaviour
  • how non-consecutive array elements are printed

That is if how I’ve simplified the code down is correct.

Interesting C# aside: the C# compiler does not parse octal formatted numbers, so 12345 and 0x3039 do not equal 030071, quite a strange diversion from C and C++.

Curse of the Azure Bonds monster information

Stu posted a dump of Curse of the Azure Bonds monster data from the Apple IIe disk set.

Not to be out done, I have dumped the same data but with more details… because I can.

Update: Oh god this table looks bad on my site

Game Area Id Name NPC Exp Hit Points AC Thac0 Str Dex Con Int Wis Cha Cleric Level Druid Level Fighter Level Paladin Level Ranger Level Magic-User Level Thief Level Monk Level Weapon Armor Damage Spells Affects
1 1 FIRE KNIFE 0 26 1 19 10 18 10 10 10 10 0 0 5 0 0 0 6 0 Long Sword Leather Armor 1d8
1 8 CROCODILE 0 16 5 16 10 10 10 3 10 10 0 0 4 0 0 0 0 0 1d8
1 16 RED PLUME 0 35 3 16 16 10 10 10 10 10 0 0 5 0 0 0 0 0 Broad Sword Splint Mail 2d4+1
1 17 CULTIST 0 18 3 20 10 10 10 10 16 10 3 0 0 0 0 0 0 0 Flail Ring Mail 1d6+1 Spiritual Hammer, Curse, Hold Person
1 32 ZHENTIL FIGHTER 0 35 4 16 16 10 10 10 10 10 0 0 5 0 0 0 0 0 Broad Sword Chain Mail 2d4+1
1 53 BLACK DRAGON 0 48 3 12 10 10 10 10 10 10 0 0 12 0 0 12 0 0 1d4 detect_invisibility, breath_acid
1 60 DRACOLICH 0 66 -6 7 25 18 10 10 10 10 0 0 17 0 0 0 0 0 3d8 affect_6e, affect_77, affect_7a, affect_7b, affect_87, affect_85, affect_80, affect_7e, affect_7d
1 80 DISPLACER BEAST 0 35 2 13 10 10 10 10 10 10 0 0 0 0 0 0 0 0 2d4
1 81 HIPPOGRIFF 0 25 5 16 10 10 10 10 10 10 0 0 0 0 0 0 0 0 1d6
1 82 ETTIN 0 70 3 10 10 10 10 10 10 10 0 0 0 0 0 0 0 0 2d8
1 83 LIZARD MAN 0 15 4 16 10 10 10 10 10 10 0 0 0 0 0 0 0 0 Short Sword 1d6
1 84 CENTAUR 0 28 4 15 10 10 10 10 10 10 0 0 0 0 0 0 0 0 Long Bow 1d6
1 85 RUSTLE 53184 98 0 -3 18(100) 10 10 10 10 10 0 0 9 0 0 0 0 0 Two-Handed Sword +1 1d10+7
1 86 BUGBEAR 0 24 5 16 10 10 10 10 10 10 0 0 0 0 0 0 0 0 Spear 1d6
1 87 WORG 0 44 6 15 10 10 10 10 10 10 0 0 0 0 0 0 0 0 2d8
1 88 CYNTHIA 53184 40 2 -2 18(100) 10 10 18 10 10 0 0 0 0 0 9 0 0 1d2+6 Magic Missile (3), Stinking Cloud, Fireball, Lightning Bolt
1 89 FIGHTER 0 35 4 16 16 10 10 10 10 10 0 0 5 0 0 0 0 0 Broad Sword Chain Mail 2d4+1
1 90 GRENDEL 53184 60 0 0 18(100) 10 10 18 18 10 9 0 0 0 0 0 0 0 Staff Sling +1 1d4+2
2 0 ROYAL GUARD 0 21 3 18 10 10 10 10 10 10 0 0 3 0 0 0 0 0 Long Sword Chain Mail 1d8
2 1 FIRE KNIFE 0 26 1 19 10 18 10 10 10 10 0 0 5 0 0 0 6 0 Long Sword Leather Armor 1d8
2 2 THIEF 0 24 4 19 10 17 10 10 10 10 0 0 0 0 0 0 6 0 Dagger Leather Armor 1d4
2 3 MAGE 0 12 8 20 10 10 10 10 10 10 0 0 0 0 0 4 0 0 Quarter Staff 1d6 Magic Missile (3), Stinking Cloud (2)
2 4 BAR PATRON 0 16 8 19 12 14 10 10 10 10 0 0 0 0 0 0 0 0 Short Sword Leather Armor 1d6
2 5 FIGHTING DOG 0 12 6 16 10 10 10 3 10 10 0 0 3 0 0 0 0 0 2d4
2 6 MONKEY 0 6 7 18 10 10 10 3 10 10 0 0 2 0 0 0 0 0 Sling 1d4+1
2 7 TROLL 0 36 4 13 10 10 10 10 10 10 0 0 7 0 0 0 0 0 1d4+4 affect_64, affect_65
2 8 CROCODILE 0 16 5 16 10 10 10 3 10 10 0 0 4 0 0 0 0 0 1d8
2 9 OTYUGH 0 40 3 12 10 10 10 10 10 10 0 0 8 0 0 0 0 0 1d4+1
2 10 NEO-OTYUGH 0 72 0 9 10 10 10 10 10 10 0 0 12 0 0 0 0 0 2d6
2 11 KNIGHT 0 54 1 15 18(0) 15 18 14 10 18 0 0 6 0 0 0 0 0 Long Sword Plate 1d8+2
3 16 RED PLUME 0 40 3 13 17 10 10 10 10 10 0 0 7 0 0 0 0 0 Broad Sword Splint Mail 2d4+1
3 17 CULTIST 0 24 3 19 10 10 10 10 16 10 5 0 0 0 0 0 0 0 Flail Ring Mail +1 1d6+1 Spiritual Hammer, Curse, Hold Person
3 18 LOOTER 0 20 4 19 10 17 10 10 10 10 0 0 0 0 0 0 5 0 Short Sword Leather Armor 1d6
3 19 ZHENTRIM CLERIC 0 48 1 17 10 10 10 10 17 10 9 0 0 0 0 0 0 0 Mace +1 Splint Mail +2 1d6+2 Sticks to Snakes, Hold Person (4), Prayer, Cause Disease (2) detect_invisibility, resist_fire
3 20 ZHENTRIM FGHTR 0 58 2 9 18(76) 10 10 10 10 10 0 0 9 0 0 0 0 0 Broad Sword +1 Banded Mail +1 2d4+5
3 21 ZHENTRIM MAGE 0 25 4 19 10 10 10 10 10 10 0 0 0 0 0 9 0 0 Dagger 1d4 Magic Missile (4), Stinking Cloud (2), Lightning Bolt, Blink, Lightning Bolt, Fear, Fire Shield minor_globe_of_invulnerability, detect_invisibility, prot_from_normal_missiles
3 22 ALIAS 51797 48 -1 15 17 17 17 17 17 17 0 0 6 0 0 0 0 0 Long Sword Plate Mail 1d8+1 affect_51, affect_7d, affect_8a
3 23 DRAGONBAIT 925 50 3 16 15 13 17 14 16 4 0 0 0 7 0 0 0 0 Two-Handed Sword Plate Mail 1d10 affect_51, affect_7d, affect_8a, prot_from_evil_10_radius
3 24 MOGION 0 60 -5 11 10 10 10 10 18 10 10 0 0 0 0 0 0 0 Mace +2 Plate Mail +3 1d6+4 Hold Person (4), Slay Living (2), Poison (2), Bestow Curse resist_cold
3 25 SHAMBLING MOUND 0 65 0 10 10 10 10 3 10 10 0 0 11 0 0 0 0 0 2d8 affect_70, affect_54, affect_52, affect_51, affect_39
3 26 BIT O’ MOANDER 0 140 0 7 10 10 10 3 10 10 0 0 20 0 0 0 0 0 2d8 affect_70, affect_54, affect_52, affect_51, affect_39
3 27 SM VEGEPYGMY 0 15 4 16 10 10 10 10 10 10 0 0 3 0 0 0 0 0 1d6 affect_87, affect_55, affect_6d, affect_6c
3 28 LG VEGEPYGMY 0 30 4 14 10 10 10 10 10 10 0 0 6 0 0 0 0 0 1d6 affect_87, affect_55, affect_6d, affect_6c
3 30 GIANT SLUG 0 60 8 9 10 10 10 3 10 10 0 0 12 0 0 0 0 0 1d12 spit_acid
4 9 OTYUGH 0 40 3 12 10 10 10 10 10 10 0 0 8 0 0 0 0 0 1d4+1
4 32 ZHENTIL FIGHTER 0 40 3 12 18(1) 10 10 10 10 10 0 0 7 0 0 0 0 0 Broad Sword +1 Chain Mail +1 2d4+4
4 33 ZHENTIL MAGE 0 19 4 18 10 10 10 10 10 10 0 0 0 0 0 7 0 0 Dagger +1 1d4+1 Fire Shield, Magic Missile (3), Stinking Cloud (2), Blink, Haste, Charm Person
4 34 ZHENTIL CLERIC 0 40 1 17 10 10 10 10 17 10 6 0 0 0 0 0 0 0 Mace +1 Chain Mail +1 1d6+2 Curse, Spiritual Hammer, Hold Person, Prayer, Dispel Magic, Bestow Curse
4 35 OGRE 0 21 5 15 18(0) 10 10 6 10 10 0 0 5 0 0 0 0 0 1d10
4 37 GRIFFON 0 42 3 13 10 10 10 10 10 10 0 0 7 0 0 0 0 0 1d4
4 38 MANTICORE 0 33 4 14 10 10 10 10 10 10 0 0 7 0 0 0 0 0 Spines 1d6
4 39 HOODED MEDUSA 0 42 0 13 10 10 10 10 10 10 0 0 6 0 0 0 0 0 1d10 affect_40, affect_7f, affect_53
4 40 BEHOLDER 0 75 0 7 10 10 10 10 10 10 0 0 0 0 0 0 0 0 2d4 affect_81, affect_57
4 41 MINOTAUR 0 33 1 10 18(91) 10 10 10 10 10 0 0 7 0 0 0 0 0 Battle Axe +1 Plate Mail +1 1d8+6
4 43 DARK ELF LORD 0 108 -7 5 16 19 18 10 10 10 0 0 12 0 0 0 0 0 Drow Long Sword +5 Drow Chain Mail 1d8+6 detect_invisibility, haste, affect_69, affect_6b
4 67 RAKSHASA 0 35 -4 13 10 10 10 10 10 10 7 0 7 0 0 7 0 0 1d3 Lightning Bolt (3), Stinking Cloud (2), Charm Person (2) detect_invisibility, affect_82, affect_81, affect_3c
4 72 HIGH PRIEST 0 60 0 13 10 10 10 10 18 10 10 0 0 0 0 0 0 0 Flail +1 Plate Mail +2 1d6+2 Slay Living (2), Sticks to Snakes, Poison, Bestow Curse, Prayer, Poison, Cause Disease, Cause Blindness, Hold Person (3) protection_from_good, resist_cold
5 48 DARK ELF LORD 0 108 -7 2 20 19 18 10 10 10 0 0 12 0 0 0 0 0 Drow Long Sword +5 Plate Mail +3 1d8+13 detect_invisibility, haste, affect_69, affect_6b
5 49 DK ELF FIGHTER 0 38 0 13 16 15 10 10 10 10 0 0 5 0 0 0 0 0 Drow Long Sword +3 Drow Chain Mail 1d8+4 affect_69, affect_6b
5 50 DARK ELF MAGE 0 20 1 13 16 15 15 10 10 10 0 0 5 0 0 6 0 0 Drow Long Sword +3 Drow Chain Mail 1d8+3 Magic Missile, Stinking Cloud (2), Lightning Bolt (2) affect_69, affect_6b
5 51 DARK ELF CLERIC 0 42 0 12 17 15 15 10 17 10 6 0 5 0 0 0 0 0 Drow Mace +3 Drow Chain Mail 1d6+5 Resist Fire, Hold Person, Bestow Curse, Cause Blindness affect_69, affect_6b
5 52 EFREETI 0 55 2 10 10 10 10 10 10 10 0 0 10 0 0 0 0 0 3d8 affect_71
5 53 BLACK DRAGON 0 48 3 12 10 10 10 10 10 10 0 0 12 0 0 12 0 0 1d4 detect_invisibility, breath_acid
5 54 WYVERN 0 42 3 12 10 10 10 10 10 10 0 0 9 0 0 0 0 0 2d8 affect_40
5 55 OWL BEAR 0 27 5 15 10 10 10 3 10 10 0 0 6 0 0 0 0 0 1d6 affect_60
5 56 ANHKHEG 0 40 2 12 10 10 10 3 10 10 0 0 8 0 0 0 0 0 3d6 affect_50, affect_79
5 57 SALAMANDER 0 42 3 15 10 10 10 10 10 10 0 0 8 0 0 0 0 0 2d6 affect_67, affect_77, affect_70, affect_6d, affect_6c
5 58 DRACANDROS 0 32 -1 14 10 10 10 10 10 10 0 0 0 0 0 11 0 0 Quarter Staff +2 1d6+2 Feeblemind, Cone of Cold (2), Ice Storm, Fire Shield, Fumble, Lightning Bolt (4), Magic Missile (3), Stinking Cloud (2) prot_from_normal_missiles, affect_8a, detect_invisibility, minor_globe_of_invulnerability
5 59 AKABAR BEL AKAS 21915 15 10 20 11 12 13 15 13 14 0 0 0 0 0 5 0 0 Quarter Staff 1d6 Magic Missile (4), Stinking Cloud (2), Fireball
5 60 DRACOLICH 0 66 -6 7 25 18 10 10 10 10 0 0 17 0 0 0 0 0 3d8 affect_6e, affect_77, affect_7a, affect_7b, affect_87, affect_85, affect_80, affect_7e, affect_7d
6 64 THRI-KREEN 0 33 5 13 10 10 10 10 10 10 0 0 7 0 0 0 0 0 1d4 affect_68, affect_43
6 65 PHASE SPIDER 0 35 7 13 10 10 10 3 10 10 255 0 255 255 255 255 255 0 0d0 affect_46, blink
6 66 GIANT SPIDER 0 24 4 15 10 10 10 10 10 10 0 0 5 0 0 0 0 0 0d0 affect_40
6 67 RAKSHASA 0 35 -4 13 10 10 10 10 10 10 7 0 7 0 0 7 0 0 1d3 Lightning Bolt (3), Stinking Cloud (2), Charm Person (2) detect_invisibility, affect_82, affect_81, affect_3c
6 68 HELL HOUND 0 35 4 13 10 10 10 10 10 10 0 0 7 0 0 0 0 0 2d4 detect_invisibility, cast_breath_fire
6 69 MARGOYLE 0 30 2 13 10 10 10 10 10 10 0 0 6 0 0 0 0 0 1d6 affect_77
6 70 PRIEST OF BANE 0 48 3 16 10 10 10 10 18 10 8 0 0 0 0 0 0 0 Mace Splint Mail 1d6+1 Sticks to Snakes, Poison, Bestow Curse, Cause Disease, Cause Blindness, Hold Person (3)
6 71 TYRANTHRAXUS 0 100 -5 1 10 21 10 10 10 10 0 0 15 0 0 0 0 0 7d6 detect_invisibility, affect_70, affect_4f, affect_6a, cast_throw_lightening, affect_87
6 72 HIGH PRIEST 0 60 0 13 10 10 10 10 18 10 10 0 0 0 0 0 0 0 Flail +1 Plate Mail +2 1d6+2 Slay Living (2), Sticks to Snakes, Poison, Bestow Curse, Prayer, Poison, Cause Disease, Cause Blindness, Hold Person (3) protection_from_good, resist_cold
6 73 RAKSHASA 0 35 -4 7 10 10 10 10 10 10 7 0 7 0 0 7 0 0 Long Bow +3 1d6+6 Lightning Bolt (3), Haste, Stinking Cloud (2), Charm Person (2) detect_invisibility, affect_82, affect_81, affect_3c
6 89 FIGHTER 0 35 4 16 16 10 10 10 10 10 0 0 5 0 0 0 0 0 Broad Sword Chain Mail 2d4+1

Now I just need to alter my port, so I can start having a round robin Vs. battle between all the monsters to rank them. This will help with improving the AI (if you can call it that), which currently does some silly things.