Monday, April 30, 2007

Getting Started with NHibernate

I just found a good video introduction to NHibernate over at dnrTV created by Oren Eini (aka Ayende), who is an active NHibernate contributer. If you're an NHibernate pro, you probably won't find anything you didn't already know. I usually use Castle ActiveRecord instead of just using NHibernate directly in order to get a sizable productivity boost, provided the project is small enough. When a project is sufficiently large or complex (multiple client applications, large model, difficult mapping, etc), I believe that skipping AR and going directly to NHibernate is the way to go. It helps keep your laying cleaner by reducing coupling of your application services and the persistence mechanism.

Saturday, April 28, 2007

Rendering Binary Data with MonoRail

Sometimes you want to make your MonoRail controller render binary data for a download. MonoRail by default is setup to render HTML via the view engine, but you can change that behavior. I usually put a method like this in my base controller:

        protected void SetupDownload(string filename, string contentType)

        {

            CancelLayout();

            CancelView();

            Response.Clear();

            Response.ContentType = contentType;

            Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

        }



By calling this method inside one of your controllers, you will change the default behavior of the controller to not perform the layout (CancelLayout()) and to not try to render a view via the view engine (CancelView()). The contentType should be something like "application/zip". It's the MIME type that is reported to the browser. This method also tells the browser that the data is not inline, and that the user should be prompted to download the file with a default filename provided by the filename argument.

So you have changed the default behavior of MonoRail to render something other than a plain vanilla view. All that's left is to write the binary data into the response's output stream. If you already have a stream, then you would do something like this:

        private void CopyStream(Stream from, Stream to)

        {

            byte[] buffer = new byte[_bufferSize];

            int bytes = 0;

            while ((bytes = from.Read(buffer, 0, buffer.Length)) > 0)

                to.Write(buffer, 0, bytes);

        }



            CopyStream(System.IO.File.OpenRead(path), Response.OutputStream);



Or, if you have a byte array (buffer in this example) or something similar, you can do something like this.

            Response.OutputStream.Write(buffer, 0, buffer.Length);



Notice that if you want to have the brower render something inline (e.g. an image), than you can just remove line that adds the Content-Disposition header that is in my example SetupDownload function.

Friday, April 27, 2007

Remove All Tables and Constraints from a Database Using T-SQL

You've had this problem before: You don't want to drop a database completely, but you do want to drop all the tables. Try to drop your tables in the wrong order and you're slapped with an error regarding referential constraints. I've created this script to ease the burden. It first drops all the constraints, and then it drops all the tables. Let me know if this doesn't work on your SQL Server database. Here's a warning for those who didn't bother to read this paragraph:

WARNING: The following script will delete all the tables in your database.

On to the script:


DECLARE @TableName NVARCHAR(MAX)

DECLARE @ConstraintName NVARCHAR(MAX)

DECLARE Constraints CURSOR FOR

 SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE

 

OPEN Constraints

FETCH NEXT FROM Constraints INTO @TableName, @ConstraintName

 

WHILE @@FETCH_STATUS = 0

BEGIN

 EXEC('ALTER TABLE [' + @TableName + '] DROP CONSTRAINT [' + @ConstraintName + ']')

 FETCH NEXT FROM Constraints INTO @TableName, @ConstraintName

END

 

CLOSE Constraints

DEALLOCATE Constraints

 

DECLARE Tables CURSOR FOR

 SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES

 

OPEN Tables

FETCH NEXT FROM Tables INTO @TableName

 

WHILE @@FETCH_STATUS = 0

BEGIN

 EXEC('DROP TABLE [' + @TableName + ']')

 FETCH NEXT FROM Tables INTO @TableName

END

 

CLOSE Tables

DEALLOCATE Tables



Enjoy. Let me know if this doesn't work for you.

Thursday, May 12, 2005

Adapting the Elo Rating System for Poker

Chess players know what the Elo rating system is. Every player gets a rating a from 0 to 3000. The higher your rating, the better you are. I recently was tasked with coming up with a rating system for poker players that play tournaments. I have previously played around with rolling my own system of statistics to determine the ability of a poker player, but I'm no math genius so I looked for something prebuilt.

I decided I'd modify the Elo rating system used in chess for poker. It has to be modified because it was originally designed for games where there are only two players. Ratings for players are calculated based on who won the game and what the respective ratings of the players were before the game completed. The problem is that poker tournaments have many players, not just two, so it had to be modifed.

The Elo rating system tries to predict the probability that a given player will beat another player based on their ratings. It then uses the new data, i.e. the result of the game, to adjust its predictions for the next game. If a player wins, he gets a score of 1. If he loses, he gets a score of 0. And if both players draw, they both get a score of 0.5.

In poker tournaments, you want capture not only who won the game, but who did well in the tournament. Obviously, second place, third place, etc. deserve some recognition. You can't just recognize first place as the only "winner." So, instead of a score of 1 for the winner, and 0 for all the losers, a player attains a score equal to that player's place scaled by the size of the tournament he played in. The equation looks something like:

S = Score
P = Place of a specific player
N = Number of players

S = (P-1)/(N-1)

Using this formula, first place gets a 1, last place gets a 0, and all the players in between get something between 0 and 1.

The Elo system also uses an expression to predict the score of a given player based on his opponent. The original system only takes into account one other player. The new system has to include the ratings of all of the other players in the tournament. Traditionally, the Elo system uses an expression to predict the score that looks something like:

Ea = Estimated score for Player A
Eb = Estimated score for Player B
Ra = Rating of Player A
Rb = Rating of Player B

Ea = 1 / (1 + 10^((Rb-Ra)/400))
Eb = 1 / (1 + 10^((Ra-Rb)/400))
We have more than one opposing player, so I average the ratings of all opposing players. This is the second modification I made. By the way, the 400 is used to fit the ratings along a normal distribution curve desired for chess ratings.

I've tested this model with good results. I plan on implementing it for a large group of poker players and hope that others might test it and try it out on their own.

Update: I've revised my ideas on the modification to the system here.