jamin on October 31st, 2003

Finished up getting the remaining bits of my costume together last night. So now I have an orange jump suit that says “Death Row” on the front, professional grade leg irons with 15″ chain, bandana, dangly cross earing, fake tattoos.

I also hacked on WoodPusher a bit last night. I’ve now got it to the point where I can actually play a whole game of chess on an ICS server. Beautiful. And my app is now multithreaded. Read on to see the source code.

// WoodPusher.cs

//
// Author: Jamin P. Gray
//
// (c) 2003 Jamin P. Gray

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using System.Threading;

using Gtk;
using Gdk;
using Glade;
using Gnome;
using GtkSharp;

public class WoodPusher : Gnome.Program
{
  // Members
  [Glade.Widget("canvas")]
  private Gnome.Canvas myCanvas;

  [Glade.Widget("window")]
  private Gnome.App myWindow;

  private int board_size = 400;
  private int square_size;
  private double offset_x = 0.0, offset_y = 0.0;
  private double original_x = 0.0, original_y = 0.0;
  private bool moving = false;
  private const string VERSION = "0.01";
  private Pixbuf darkSquarePixbuf;
  private Pixbuf whitePawnPixbuf;
  private Pixbuf whiteKnightPixbuf;
  private Pixbuf whiteBishopPixbuf;
  private Pixbuf whiteRookPixbuf;
  private Pixbuf whiteQueenPixbuf;
  private Pixbuf whiteKingPixbuf;
  private Pixbuf blackPawnPixbuf;
  private Pixbuf blackKnightPixbuf;
  private Pixbuf blackBishopPixbuf;
  private Pixbuf blackRookPixbuf;
  private Pixbuf blackQueenPixbuf;
  private Pixbuf blackKingPixbuf;
  private Pixbuf lightSquarePixbuf;
  private int counter;
  private Piece[,] board = new Piece[8,8];

  public struct Coordinate
  {
    public int x;
    public int y;
  }

  public enum PieceType
  {
    Empty,
    WhitePawn,
    WhiteKnight,
    WhiteBishop,
    WhiteRook,
    WhiteQueen,
    WhiteKing,
    BlackPawn,
    BlackKnight,
    BlackBishop,
    BlackRook,
    BlackQueen,
    BlackKing
  }

  public struct Piece
  {
    public PieceType type;
    public CanvasPixbuf cpb;
  }

  // Style 12 string (see docs/style12.txt)
  public string initialBoardSetup = "<12> " +
            "rnbqkbnr " +
            "pppppppp " +
            "-------- " +
            "-------- " +
            "-------- " +
            "-------- " +
            "PPPPPPPP " +
            "RNBQKBNR " +
            "W -1 1 1 1 1 0 0 White Black " +
            "1 0 0 39 39 0 0 none (0:00) none 0";

  private Regex style12Regex;

  private Thread readThread, writeThread;
  private TcpClient client;
  private NetworkStream stream;
  private StreamReader streamReader;
  private StreamWriter streamWriter;

  public static void Main ( string[] args )
  {
    WoodPusher app = new WoodPusher( args );
    app.Run ( );
  }

  public WoodPusher(string[] args)
    : base ("WoodPusher " + VERSION, VERSION, Modules.UI, args)
  {
    Glade.XML appGxml = new Glade.XML (null, "woodpusher.glade", "window", null);
    appGxml.Autoconnect (this);

    square_size = board_size / 8;

    darkSquarePixbuf = Scale ( new Pixbuf ( "pixmaps/square.dark.png" ), square_size );
    lightSquarePixbuf = Scale ( new Pixbuf ( "pixmaps/square.light.png" ), square_size );
    whitePawnPixbuf = Scale ( new Pixbuf ( "pixmaps/white.pawn.png" ), square_size );
    whiteKnightPixbuf = Scale ( new Pixbuf ( "pixmaps/white.knight.png" ), square_size );
    whiteBishopPixbuf = Scale ( new Pixbuf ( "pixmaps/white.bishop.png" ), square_size );
    whiteRookPixbuf = Scale ( new Pixbuf ( "pixmaps/white.rook.png" ), square_size );
    whiteQueenPixbuf = Scale ( new Pixbuf ( "pixmaps/white.queen.png" ), square_size );
    whiteKingPixbuf = Scale ( new Pixbuf ( "pixmaps/white.king.png" ), square_size );
    blackPawnPixbuf = Scale ( new Pixbuf ( "pixmaps/black.pawn.png" ), square_size );
    blackKnightPixbuf = Scale ( new Pixbuf ( "pixmaps/black.knight.png" ), square_size );
    blackBishopPixbuf = Scale ( new Pixbuf ( "pixmaps/black.bishop.png" ), square_size );
    blackRookPixbuf = Scale ( new Pixbuf ( "pixmaps/black.rook.png" ), square_size );
    blackQueenPixbuf = Scale ( new Pixbuf ( "pixmaps/black.queen.png" ), square_size );
    blackKingPixbuf = Scale ( new Pixbuf ( "pixmaps/black.king.png" ), square_size );

    style12Regex = new Regex ( @"(\<12\>.*)" , RegexOptions.Compiled | RegexOptions.Multiline);

    DrawBoard ( );
    SetUpBoard ( initialBoardSetup );
    ConnectToICS ( );
    readThread = new Thread ( new ThreadStart ( ICSRead ) );
    writeThread = new Thread ( new ThreadStart ( ICSWrite ) );
    readThread.Start ( );
    writeThread.Start ( );
  }

  // Draw the dark and light squares that make up the board
  public void DrawBoard ( )
  {
    bool light = true;
    for ( int x = 0; x < board_size; x += square_size )
    {
      light = !light;
      for ( int y = 0; y < board_size; y += square_size )
      {
        light = !light;
        CanvasPixbuf boardCanvasPixbuf = new CanvasPixbuf ( myCanvas.Root ( ) );
        if ( light )
        {
          boardCanvasPixbuf.Pixbuf = lightSquarePixbuf;
        }
        else
        {
          boardCanvasPixbuf.Pixbuf = darkSquarePixbuf;
        }
        boardCanvasPixbuf.X = x;
        boardCanvasPixbuf.Y = y;
      }
    }
  }

  // Takes a style 12 string and places the pieces on the board
  public void SetUpBoard ( string s )
  {
    string [] fields = s.Split ( new Char [] {' '} );
    for ( int y = 0; y < 8; y++ )
    {
      char [] characters = fields[y + 1].ToCharArray ( );
      for ( int x = 0; x < 8; x++ )
      {
        Pixbuf piece;
        switch ( characters[x] )
        {
          case 'p':
            piece = blackPawnPixbuf;
            break;
          case 'n':
            piece = blackKnightPixbuf;
            break;
          case 'b':
            piece = blackBishopPixbuf;
            break;
          case 'r':
            piece = blackRookPixbuf;
            break;
          case 'q':
            piece = blackQueenPixbuf;
            break;
          case 'k':
            piece = blackKingPixbuf;
            break;
          case 'P':
            piece = whitePawnPixbuf;
            break;
          case 'N':
            piece = whiteKnightPixbuf;
            break;
          case 'B':
            piece = whiteBishopPixbuf;
            break;
          case 'R':
            piece = whiteRookPixbuf;
            break;
          case 'Q':
            piece = whiteQueenPixbuf;
            break;
          case 'K':
            piece = whiteKingPixbuf;
            break;
          default:
            piece = null;
            break;
        }
        if (piece != null)
        {
          board[x,y].cpb = new CanvasPixbuf ( myCanvas.Root ( ) );
          board[x,y].cpb.Pixbuf = piece;
          board[x,y].cpb.X = x * square_size;
          board[x,y].cpb.Y = y * square_size;
          board[x,y].cpb.CanvasEvent += new GnomeSharp.CanvasEventHandler (Piece_Event);
        }
      }
    }

  }

  // Clears all the pieces from the board
  public void ClearBoard ( )
  {
    for ( int y = 0; y < 8; y++ )
    {
      for ( int x = 0; x < 8; x++ )
      {
        if ( board[x,y].cpb != null )
        {
          board[x,y].cpb.Destroy ( );
          board[x,y].type = PieceType.Empty;
        }
      }
    }
  }

  public Pixbuf Scale ( Pixbuf image, int size )
  {
    return image.ScaleSimple ( size, size, Gdk.InterpType.Bilinear );
  }

  // Returns the coordinates (8x8 grid) of a chess square 
  // given the coordinates of a point on the canvas.

  public Coordinate GetCoordinates ( double x, double y )
  {
    Coordinate c;
    c.x = (int) ( x / square_size + 1 );
    c.y = (int) ( y / square_size + 1 );
    if (c.x > 8 || c.y > 8 || c.x < 1 || c.y < 1) {
      c.x = -1;
      c.y = -1;
    }
    return c;
  }

  public void MakeMove ( Coordinate start, Coordinate end )
  {
    string move = "" + CoordToLetter ( start.x ) +
                  (9 - start.y).ToString ( ) +
            CoordToLetter ( end.x ) +
            (9 - end.y).ToString ( );
    streamWriter.WriteLine ( move );
    streamWriter.Flush ( );
  }

  public string CoordToLetter ( int i )
  {
    Console.WriteLine ( "x: {0}", i );
    switch ( i )
    {
      case 1:
        return "a";
        break;
      case 2:
        return "b";
        break;
      case 3:
        return "c";
        break;
      case 4:
        return "d";
        break;
      case 5:
        return "e";
        break;
      case 6:
        return "f";
        break;
      case 7:
        return "g";
        break;
      case 8:
        return "h";
        break;
      default:
        return "z";
        break;
    }
    return "z";
  }

  public void OnWindowDeleteEvent (object o, DeleteEventArgs args)
  {
    Quit ( );
    args.RetVal = true;
    readThread.Join ( 0 );
    writeThread.Join ( 0 );
    Environment.Exit ( 0 );
  }

  void Piece_Event (object obj, GnomeSharp.CanvasEventArgs args) {
    EventButton ev = EventButton.New (args.Event.Handle);
    CanvasPixbuf item = (CanvasPixbuf) obj;

    switch (ev.type) {
    case EventType.ButtonPress:
      if (ev.button == 1) {
        offset_x = ev.x % square_size;
        offset_y = ev.y % square_size;
        original_x = ev.x;
        original_y = ev.y;
        args.RetVal = true;
        return;
      }
      if (ev.button == 2) {
        ClearBoard ( );
        args.RetVal = true;
        return;
      }
      break;
    case EventType.ButtonRelease:
      if (moving) {
        Coordinate c = GetCoordinates ( ev.x, ev.y );
        if (c.x != -1) {
          double new_x = c.x * square_size - square_size;
          double new_y = c.y * square_size - square_size;
          item.X = new_x;
          item.Y = new_y;
          MakeMove ( GetCoordinates ( original_x, original_y ), c );
        }
        args.RetVal = true;
        moving = false;
        return;
      }
      break;
    case EventType.MotionNotify:
      Gdk.ModifierType state = (Gdk.ModifierType) ev.state;
      if ((state & Gdk.ModifierType.Button1Mask) != 0) {
        moving = true;
        item.X = ev.x - offset_x;
        item.Y = ev.y - offset_y;
        args.RetVal = true;
        return;
      }
      break;
    }

    args.RetVal = false;
    return;
  }

  public void ConnectToICS ( )
  {
    try
    {
      Console.WriteLine ( "Connecting..." );
      client = new TcpClient ( "freechess.org", 23 );
      Console.WriteLine ( "Connected." );

      stream = client.GetStream ( );
    }
    catch (Exception e)
    {
      Console.WriteLine( "Error: " + e.StackTrace );
    }
  }

  private void ICSRead ( )
  {
    while ( true )
    {
      streamReader = new StreamReader ( stream );
      string s = "";
      char [] c = null;
      while ( streamReader.Peek ( ) >= 0 )
      {
        c = new char[1];
        streamReader.Read(c, 0, c.Length);
        s += new String ( c );
      }
      Match m = style12Regex.Match ( s );
      if ( m.Success )
      {
        Console.WriteLine ( "STYLE 12 MATCH!" );
        ClearBoard ( );
        string style12 = m.ToString ( );
        Console.WriteLine ( "####" + s + "####" );
        SetUpBoard ( style12 );
      }
      else
        Console.Write ( s );
    }
  }

  private void ICSWrite ( )
  {
    string input;
    while ( true )
    {
      streamWriter = new StreamWriter ( stream );
      input = Console.ReadLine ( );
      streamWriter.WriteLine ( input );
      streamWriter.Flush ( );
    }
  }
}

Tags:

One Response to “Accomplishments”

  1. I was able to play a full game of chess, however, there are some serious bugs I’ve noticed since then…working on fixing…Also lots of features need to be added…