Mintshot – Mint Tick Game

What are the chances of winning, and when should you stop.

Now that the mint tick game is back, I thought I’d have a play at lunch time. The two auctions I was playing on had a high score of 16 and 17.

After a few games I decided I wanted to know the odds/cost to ‘win’

Turn Ticks Left Crosses Left Chance of Selecting a Tick Chance to be here Every X Turns Cost to to be here
0 22 8 73.33% 100% 1 20
1 21 8 72.41% 73% 2 40
2 20 8 71.43% 53% 2 40
3 19 8 70.37% 37% 3 60
4 18 8 69.23% 26.6922% 4 80
5 17 8 68.00% 18.4792% 6 120
6 16 8 66.67% 12.5659% 8 160
7 15 8 65.22% 8.3772% 12 240
8 14 8 63.64% 5.4634% 19 380
9 13 8 61.90% 3.4767% 29 580
10 12 8 60.00% 2.1523% 47 940
11 11 8 57.89% 1.2914% 78 1,560
12 10 8 55.56% 0.7476% 134 2,680
13 9 8 52.94% 0.4153% 241 4,820
14 8 8 50.00% 0.2199% 455 9,100
15 7 8 46.67% 0.1099% 910 18,200
16 6 8 42.86% 0.0513% 1,950 39,000
17 5 8 38.46% 0.0220% 4,458 90,960
18 4 8 33.33% 0.0085% 11,825 236,500
19 3 8 27.27% 0.0028% 35,473 709,460
20 2 8 20.00% 0.0008% 130,065 2,601,300
21 1 8 11.11% 0.0002% 650,325 13,006,500
22 0 8 0.00% 0.0000% 5,852,925 117,058,500

So to get 16 ticks is a 1 in ~2000 event, and 17 is a 1 in ~4500.

So I then played 100 games, recording the outcomes and got the following histogram:

Tick Count Games Games with >= #Ticks Effective Game Percentage
0 26 100 100.00%
1 25 74 74.00%
2 15 49 49.00%
3 8 34 34.00%
4 13 26 26.00%
5 1 13 13.00%
6 4 12 12.00%
7 4 8 8.00%
8 1 4 4.00%
9 1 3 3.00%
10 1 2 2.00%
11 1 1 1.00%

Which is in-line with the expected chances from above.

So if you are hoping for a lucky brake, good luck….

Google Analytics - Updated

Google has updated Analytics, and the feature that made this most obvious was the date range picker.  Before you even open it you can see a new Comparing to: Site ? text.

Analytics date picker change 1
Analytics date picker change 1

On opening the data picker, they now let you choose today in New Zealand time.

Analytics date picker change 2
Analytics date picker change 2

No more editing the URL to see what is happening now! This is quite useful when I get comments to see how people found my site etc.

I will have to explore to see if I find more features, but for now, my #1 missing feature has been solved.

Installing Visual Studio 2008

I have finished now, but I have to say there was something creepy about the two male photos used. One looked too happy and the other too smooth.  What made it worse was that it kept changing and my attention would be pulled to smug guy or happy guy.

Visual Studio 2008 - Happy Guy
Visual Studio 2008 - Happy Guy
Visual Studio 2008 - Smooth Guy
Visual Studio 2008 - Smooth Guy

I’m not looking forward to having to do a repair, luckily I did a full install, so there are no extra features that I will have to install later……

Pascal 6-byte real to IEEE 8-byte double

A while ago I mentioned that System.BitConverter.Int64BitsToDouble would be useful for converting Pascal 6-byte real’s to IEEE 8-byte double’s.  Here is my C# .Net code to do just that.

My original code was based on Richard Biffl’s BPREAL.C.  My original code used System.Runtime.InteropServices.StructLayout( LayoutKind.Explicit ) attribute to make a C++ union data type.  The new code now uses a long (int64) and System.BitConverter.Int64BitsToDouble to do the dirty work.

I originally had my real’s loaded into registers CX, SI, and DI, so that is why the name/order of my functions parameters also.  I knew I had it correct when two of the original values turned out to be 2*PI and 100.0

Here’s the code, the old code is in class PascalReal and the newer version in class PascalRealNicer:

using System;
using System.Runtime.InteropServices;

namespace RealToDouble
{
    class MainProgram
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("{0}", PascalReal.ToDouble(new ushort[] { /*cx*/0xdc83, /*si*/0xcf80, /*di*/0x490F })); // 2 * PI
            Console.WriteLine("{0}", PascalReal.ToDouble(new ushort[] { /*cx*/0x0087, /*si*/0x0000, /*di*/0x4800 })); // 100.0
            Console.WriteLine("{0}", PascalReal.ToDouble(new ushort[] { /*cx*/0x0084, /*si*/0x0000, /*di*/0xa000 })); // -10.0
            Console.WriteLine("{0}", PascalReal.ToDouble(new ushort[] { /*cx*/0x0084, /*si*/0x0000, /*di*/0x0000 })); // 8.0
            Console.WriteLine("{0}", PascalReal.ToDouble(new ushort[] { /*cx*/0x0083, /*si*/0x0000, /*di*/0x0000 })); // 2.0
            Console.WriteLine("{0}", PascalReal.ToDouble(new ushort[] { /*cx*/0x0000, /*si*/0x0000, /*di*/0x0000 })); // 0.0

            Console.WriteLine();

            Console.WriteLine("{0}", PascalRealNicer.ToDouble( /*cx*/0xdc83, /*si*/0xcf80, /*di*/0x490F)); // 2 * PI
            Console.WriteLine("{0}", PascalRealNicer.ToDouble( /*cx*/0x0087, /*si*/0x0000, /*di*/0x4800)); // 100.0
            Console.WriteLine("{0}", PascalRealNicer.ToDouble( /*cx*/0x0084, /*si*/0x0000, /*di*/0xa000)); // -10.0
            Console.WriteLine("{0}", PascalRealNicer.ToDouble( /*cx*/0x0084, /*si*/0x0000, /*di*/0x0000)); // 8.0
            Console.WriteLine("{0}", PascalRealNicer.ToDouble( /*cx*/0x0083, /*si*/0x0000, /*di*/0x0000)); // 2.0
            Console.WriteLine("{0}", PascalRealNicer.ToDouble( /*cx*/0x0000, /*si*/0x0000, /*di*/0x0000)); // 0.0

            Console.ReadKey();
        }
    }

    class PascalReal
    {
        [ StructLayout( LayoutKind.Explicit )]
        public struct doublearray
        {
            [ FieldOffset( 0 )]
            public ushort a0;
            [ FieldOffset( 2 )]
            public ushort a1;
            [ FieldOffset( 4 )]
            public ushort a2;
            [ FieldOffset( 6 )]
            public ushort a3;

            [ FieldOffset( 0 )]
            public double d;
        }

        public static double ToDouble( ushort[] r )
        {
            doublearray da;

            da.d = 0.0;
            da.a0 = 0;
            da.a1 = 0;
            da.a2 = 0;
            da.a3 = 0;

            ushort x = (ushort)(r[0] & 0x00FF);  /* Real biased exponent in x */
            /* when exponent is 0, value is 0.0 */
            if (x == 0)
                da.d = 0.0;
            else
            {
                da.a3 = (ushort)(((x + 894) << 4) |  /* adjust exponent bias */
                    (r[2] & 0x8000) |  /* sign bit */
                    ((r[2] & 0x7800) >> 11));  /* begin significand */
                da.a2 |= (ushort)((r[2] << 5) |  /* continue shifting significand */
                    (r[1] >> 11));
                da.a1 |= (ushort)((r[1] << 5) |
                    (r[0] >> 11));
                da.a0 |= (ushort)((r[0] & 0xFF00) << 5); /* mask real's exponent */

            }
            return da.d;

        }
    }

    class PascalRealNicer
    {
        public static double ToDouble(ushort cx, ushort si, ushort di)
        {
            long double64 = 0;
            int exp = cx & 0x00ff;

            if (exp != 0)
            {
                // sign
                double64 = (long)(di & 0x8000) << 48;
                // biased exponent
                double64 |= (long)(exp + 894) << 52;
                // mantissa
                double64 |= (long)(di & 0x7FFF) << 37;
                double64 |= (long)si << 21;
                double64 |= (long)(cx & 0xFF00) << 5;
            }

            return System.BitConverter.Int64BitsToDouble(double64);
        }
    }
}

Compiling and Running code at runtime

I have wanted to know how to compile and run code at runtime for a long time. I have now got a working solution, so it’s time to share.  I might even learn a better way.

So here is the C# 2.0 code, no extra references are required.

using System;
using System.Collections.Generic;
using System.Text;

using System.CodeDom.Compiler;
using System.IO;
using Microsoft.CSharp;
using System.Reflection;

namespace DynaCode
{
    class Program
    {
        static string[] code = {
            "using System;"+
            "namespace DynaCore"+
            "{"+
            "   public class DynaCore"+
            "   {"+
            "       static public int Main(string str)"+
            "       {"+
            "           return str.Length;"+
            "       }"+
            "   }"+
            "}"};

        static void Main(string[] args)
        {
            CompileAndRun(code);

            Console.ReadKey();
        }

        static void CompileAndRun(string[] code)
        {
            CompilerParameters CompilerParams = new CompilerParameters();
            string outputDirectory = Directory.GetCurrentDirectory();

            CompilerParams.GenerateInMemory = true;
            CompilerParams.TreatWarningsAsErrors = false;
            CompilerParams.GenerateExecutable = false;
            CompilerParams.CompilerOptions = "/optimize";

            string[] references = { "System.dll" };
            CompilerParams.ReferencedAssemblies.AddRange(references);

            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerResults compile = provider.CompileAssemblyFromSource(CompilerParams, code);

            if (compile.Errors.HasErrors)
            {
                string text = "Compile error: ";
                foreach (CompilerError ce in compile.Errors)
                {
                    text += "rn" + ce.ToString();
                }
                throw new Exception(text);
            }

            //ExpoloreAssembly(compile.CompiledAssembly);

            Module module = compile.CompiledAssembly.GetModules()[0];
            Type mt = null;
            MethodInfo methInfo = null;

            if (module != null)
            {
                mt = module.GetType("DynaCore.DynaCore");
            }

            if (mt != null)
            {
                methInfo = mt.GetMethod("Main");
            }

            if (methInfo != null)
            {
                Console.WriteLine(methInfo.Invoke(null, new object[] { "here in dyna code" }));
            }
        }

        static void ExpoloreAssembly(Assembly assembly)
        {
            Console.WriteLine("Modules in the assembly:");
            foreach (Module m in assembly.GetModules())
            {
                Console.WriteLine("{0}", m);

                foreach (Type t in m.GetTypes())
                {
                    Console.WriteLine("t{0}", t.Name);

                    foreach (MethodInfo mi in t.GetMethods())
                    {
                        Console.WriteLine("tt{0}", mi.Name);
                    }
                }
            }
        }
    }
}

The foundation of this code was a Dynamically Compiling C# blog post for IronPython.

It took me ages to realise that the string[] that CompileAssemblyFromSource consumes is a single string for each block (file) worth of C# code, not for each line.  New lines and space do not affect the compiler.

I then wasted ages finding my method to call via Invoke.  I have not come up with a good solution yet.  Currently my code is calling a static method, as this is what I need.

The last pain was that Invoke takes an array of objects, but it then maps the array to the method being called, so the method needs to have the signature of the items in the object array. I thought I could just handle object[] as the method input.  This makes sense in hind sight, but at the time it was very painful.

Now that I have working code, and know what to Google for, I have found other posts that go into great detail, like Rick Strahl’s 2002 Dynamically executing code in .Net. I feel like I’ve been under a rock.

SELECT * FROM USER_ERRORS

The most important Oracle pl/sql right now is:

SELECT * FROM USER_ERRORS

I’ve been “developing” some new functions, and I was getting sick and tired of being told:

Warning: execution completed with warning
 function MissingProd Compiled.

Now I can know what’s wrong, and fix it, before reloading my complete scheme.   Yay!

Curse of the Azure Bonds update

Last development update was in May ‘07, so I will quickly describe progress that has been made since then:

  • I have renamed lots of methods, global data structures, and generally worked stuff out
  • Got the combat graphics working
  • Fixed the crash when the “screen” is updated by the game engine while Windows is drawing it
  • Re-fix the 3D view (works perfectly now)
  • Damage in Combat
  • Keyboard input now correctly delays the game, when that is wanted
  • Worked out what code was responsible for sounds and named them, but still no sound
  • Items can now be purchased from shops
  • Added a cache to try remove the disk thrashing that happens due to how graphics were drawn/handled
  • Resting now works, spell assisted resting not tested
  • Improved Auto (quick) combat for my test party
  • Pooling of money now works after combat, and I assume in shops
  • Improvements to character generation, not tested all classes/race combo’s yet

The game is starting to be playable, the other night I started a new group, fought in the bar, sleep in the inn, visited the sage, attacked the king, fought the king’s guards.

Issues currently in active progress:

  • combat not giving any exp, I know kind of a big one!
  • combat starting positions of the party is the same square

Raro (Sugar) Man

My sister saw this T-shirt and thought of me:

RaroT-shirt
RaroT-shirt

I must admit, I have loved my Raro all my life, but I’m a little concerned that my work mates will claim that this is the final evidence needed, that I only eat sugar.

The T-shirt is from productville.co.nz

Mintshot Auctions

Yesterday after spending time trying to win a $25 dollar cheese voucher and failing, I decided to investigate how the auctions work a little.

The first thing I noticed was that I was getting snipped by people in the last few seconds, yet it was hard to know when the last few seconds were.

So for the next cheese auction (item_id 145 unit_id 395) the URL of the closing time is:
http://www.mintshot.co.nz/components/com_cat/getBidTime.php?item_id[]=145&unit_id[]=395
this currently displays:
145x395-closes in 4 mins and 49 secs*
this can be hit every second, giving you quite good time count down.

the bidding history can be found at:
http://www.mintshot.co.nz/components/com_cat/getBidStatus.php?adv_id=145&unit_id=395
which returns this as html

Mintshot auction history
Mintshot auction history

I’ve shown a picture here due to the actual result is 9kB (1.7kB html 7.3kB inline styles).

Also of interest is that the winners time is shown 30 minutes before the previous bid. WTF!

I had planned to pull the past cheese auctions and show the history of the winning prices. But my own Internet went funny last night, and Mintshot is down this morning, sighting heavy traffic.

Mintshot down… again
Mintshot down… again

Other issues:

  • When watching an auction, only the time left refreshes. This means you have to reload the whole page to see if the current leader or auction history has changed.
  • There is a large amount of debugging code left in the live site, but commented out. You can almost see the developers figuring out how to get it working by what is left in there.
  • Explicit styles set on every element. Not only does it bloat the page, and makes more work for the servers, but horror if they decide to re-theme the site.