New Years Day and Infinity

Thursday, January 01, 2009

Well, I'm back.

Hope you've all had a happy, safe, not-too-exhausting holiday season. Happy New Year! I've been MIA for three months, here on Coding the Wheel, and for that I apologize. I haven't been abducted by PokerStars or clobbered by goons from the 2+2 forum, contrary to what you may have read in the comments. In fact, I briefly tried to go to work for PokerStars, on a lark; but for some reason, I never got a response—go figure. I'll tell that story, and say a few words about the recent harassment letter PokerStars sent to Coding the Wheel readers, in the next installment.

I don't want to start the year on a negative note.

Speaking of PokerStars: today marks the first day of the 2009 PokerStars Supernova Elite program.

To earn the rank of a Supernova Elite VIP you must accumulate 1,000,000 VIP Player Points during the calendar year (January 1st through December 31st). Once you have earned the required VPPs you're a Supernova Elite through at least the end of January of the following year.

Not many people have the time or motivation to "go Supernova"... 

"The Human Torch" by Tom B. Long

...and it's too bad, as this particular promotion can be (I've said it before) life-changing. If you can find between six and twelve months of empty time this year, without losing your job, defaulting on your mortgage, and/or getting divorced by your spouse—and if you can hold your own at the poker table—what are you waiting for?

Go for it.

If you do, make sure to check out the Official 2009 Supernova Elite Pursuit thread on 2+2. The signal-to-noise ratio is abysmal, as always on 2+2, but there's still an awful lot of signal. By the end of the year, this thread will have grown to monstrous proportions. To see what I mean, take a look at last year's Official 2008 Supernova Elite Pursuit thread which went 890 pages, with some 13,344 individual comments.

For some, Supernova Elite is a true obsession, and I support that.

What amazes me is that we live in a world where any of this is possible. Sit down at your computer. Click certain locations on the screen. Key certain letters on the keyboard. Congratulations, you've just achieved PokerStars Supernova Elite status, written a best-selling novel, gotten a cushy telecommuting job, or built the next killer app. It's crazy. Keystrokes and button-clicks have transformative power all out of proportion to their muscle cost, and as the world grows more connected, that power increases.

Of course, you have to pick the right permutation of keys and clicks.

If you had enough time, you could mash the keyboard randomly, like an angry child, and eventually, you'd get lucky and end up with one of Shakespeare's plays, or who knows, perhaps the authentic story of JFK's assassination. This, of course, is the million monkeys scenario. Another, more structured, way to go about it, would be to calculate the value of Pi to some arbitrarily huge number of digits and convert to binary, although in so doing you'd be guilty of child pornography, violations of national security, and death threats against every politician in the world.

Jorge Luis Borges gives the classic exposition of the idea in his famous short story, The Library of Babel (also available in this eye-straining online version):

He also alleged a fact which travelers have confirmed: In the vast Library there are no two identical books. From these two incontrovertible premises he deduced that the Library is total and that its shelves register all the possible combinations of the twenty-odd orthographical symbols (a number which, though extremely vast, is not infinite): Everything: the minutely detailed history of the future, the archangels' autobiographies, the faithful catalogues of the Library, thousands and thousands of false catalogues, the demonstration of the fallacy of those catalogues, the demonstration of the fallacy of the true catalogue, the Gnostic gospel of Basilides, the commentary on that gospel, the commentary on the commentary on that gospel, the true story of your death, the translation of every book in all languages, the interpolations of every book in all books.

The lesson I take from this, on New Year's Day, is that Borges's Library, the value of Pi, and the cubicle farm with a trillion monkeys all contain the exact, second-by-second account of the next year of your life, in all the languages that have been or will ever be spoken. That doesn't mean the next year is set in stone; contained within the value of Pi is the history of every possible  and every impossible permutation of events that could befall you in a minute, a year, or a century.

Choose one.

And that, ladies and gents, is the only New Year's Resolution that really matters.

Tags: infinity, Borges, PokerStars

32 comment(s)

Hurrah, welcome back!

Need....

Stealth....

Must talk...

Stealth...

Key certain letters on the keyboard. Congratulations, you've just achieved PokerStars Supernova Elite status, written a best-selling novel, gotten a cushy telecommuting job, or built the next killer app. It's crazy. Keystrokes and button-clicks have transformative power all out of proportion to their muscle cost, and as the world grows more connected, that power increases.

JD's back. Best news of the year thus far.

Welcome back. Looking forward to digest your future posts. Even with no interest in poker bots they contain a wealth of difficult to assemble technical information. Thank you for writing this up and making it available to us all.

I was making my daily rounds and decided to swing by CTW to see if you'd come out of hibernation for the new year. Looks like I guessed right.

Anybody know what the original source of the link (DONT CALCULATE THE VALUE OF PI) is? Is the version you linked to (from alt.whatever on Google) the original?

So cool!! Welcome back!

Awesome quote:

"Keystrokes and button-clicks have transformative power all out of proportion to their muscle cost, and as the world grows more connected, that power increases."

Great artcile mate. This is a great way to look at the power of the internet and computers.

I got to Gold Star after 9 tabling NL50 on PokerStars for a month and almost hit Platinum. I was playing about 7 hours a day on average... It's insane! I do wish to be super nova elite at some point! The rakeback is immense. Thanks for another great article

Hooray you are back!

Wellcome back James!!!

Nice to read you again.

Lol, James, you have to setup registration for your forums. The guy trolling with God above isn't me. Let's see if he at least did it from anonymous IP :)

Yay ! I missed your postings !

Great, so you'll be back to bad-mouth and hurt the online poker cause with your straw-man arguments. Yippee. Like we don't have enough problems to deal with.

Huzaa; Welcome back and I look forward to more awesome posts this year!

At last...

Cool. I was a little worried the poker mafia got you :)

For the guy who asked for stealth a class to stealth.... Use it like this for hiding the window of your bot from prying eyes..

private void button1_Click(object sender, EventArgs e) { Stealth window = new Stealth(this.Text, this.Handle, ""); window.Visible = false; } Create a hotkey to bring the window / process back to the windows life And don't forget that .NET makes every static thread safe (almost ;) )

class Stealth { /// <summary> /// Win32 API Imports /// </summary> [DllImport("user32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool IsIconic(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool IsZoomed(IntPtr hWnd); [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport("user32.dll")] private static extern IntPtr AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, int fAttach);

    /// <summary>
    /// Win32 API Constants for ShowWindowAsync()
    /// </summary>
    private const int SW_HIDE = 0;
    private const int SW_SHOWNORMAL = 1;
    private const int SW_SHOWMINIMIZED = 2;
    private const int SW_SHOWMAXIMIZED = 3;
    private const int SW_SHOWNOACTIVATE = 4;
    private const int SW_RESTORE = 9;
    private const int SW_SHOWDEFAULT = 10;
    /// <summary>
    /// Private Fields
    /// </summary>
    private IntPtr m_hWnd;
    private string m_Title;
    private bool m_Visible = true;
    private string m_Process;
    private bool m_WasMax = false;
    /// <summary>
    /// Window Object's Public Properties
    /// </summary>
    public IntPtr hWnd
    {
        get{return m_hWnd;}
    }
    public string Title
    {
        get{return m_Title;}
    }
    public string Process
    {
        get{return m_Process;}
    }
    /// <summary>
    /// Sets this Window Object's visibility
    /// </summary>
    public bool Visible
    {
        get{return m_Visible;}
        set
        {
            //show the window
            if(value == true)
            {
                if(m_WasMax)
                {
                    if(ShowWindowAsync(m_hWnd,SW_SHOWMAXIMIZED))
                        m_Visible = true;
                }
                else
                {
                    if(ShowWindowAsync(m_hWnd,SW_SHOWNORMAL))
                        m_Visible = true;
                }
            }
            //hide the window
            if(value == false)
            {
                m_WasMax = IsZoomed(m_hWnd);
                if(ShowWindowAsync(m_hWnd,SW_HIDE))
                    m_Visible = false;
            }
        }
    }
    /// <summary>
    /// Constructs a Window Object
    /// </summary>
    /// <param name="Title">Title Caption</param>
    /// <param name="hWnd">Handle</param>
    /// <param name="Process">Owning Process</param>
    public Stealth(string Title, IntPtr hWnd, string Process)
    {
        m_Title = Title;
        m_hWnd = hWnd;
        m_Process = Process;
    }
    //Override ToString() 
    public override string ToString()
    {
        //return the title if it has one, if not return the process name
        if (m_Title.Length > 0)
        {
            return m_Title;
        }
        else
        {
            return m_Process;
        }
    }
    /// <summary>
    /// Sets focus to this Window Object
    /// </summary>
    public void Activate()
    {
        if(m_hWnd == GetForegroundWindow())
            return;
        IntPtr ThreadID1 = GetWindowThreadProcessId(GetForegroundWindow(),IntPtr.Zero);
        IntPtr ThreadID2 = GetWindowThreadProcessId(m_hWnd,IntPtr.Zero);
        if (ThreadID1 != ThreadID2)
        {
            AttachThreadInput(ThreadID1,ThreadID2,1);
            SetForegroundWindow(m_hWnd);
            AttachThreadInput(ThreadID1,ThreadID2,0);
        }
        else
        {
            SetForegroundWindow(m_hWnd);
        }
        if (IsIconic(m_hWnd))
        {
            ShowWindowAsync(m_hWnd,SW_RESTORE);
        }
        else
        {
            ShowWindowAsync(m_hWnd,SW_SHOWNORMAL);
        }
    }
}
/// <summary>
/// Collection used to enumerate Window Objects
/// </summary>
public class Windows : IEnumerable, IEnumerator
{
    /// <summary>
    /// Win32 API Imports
    /// </summary>
    [DllImport("user32.dll")] private static extern int GetWindowText(int hWnd, StringBuilder title, int size);
    [DllImport("user32.dll")] private static extern int GetWindowModuleFileName(int hWnd, StringBuilder title, int size);
    [DllImport("user32.dll")] private static extern int EnumWindows(EnumWindowsProc ewp, int lParam); 
    [DllImport("user32.dll")] private static extern bool IsWindowVisible(int hWnd);
    //delegate used for EnumWindows() callback function
    public delegate bool EnumWindowsProc(int hWnd, int lParam);
    private int m_Position = -1; //holds current index of wndArray, necessary for IEnumerable
    ArrayList wndArray = new ArrayList(); //array of windows
    //Object's private fields
    private bool m_invisible = false;
    private bool m_notitle = false;
    /// <summary>
    /// Collection Constructor with additional options
    /// </summary>
    /// <param name="Invisible">Include invisible Windows</param>
    /// <param name="Untitled">Include untitled Windows</param>
    public Windows(bool Invisible, bool Untitled)
    {
        m_invisible = Invisible;
        m_notitle = Untitled;
        //Declare a callback delegate for EnumWindows() API call
        EnumWindowsProc ewp = new EnumWindowsProc(EvalWindow);
        //Enumerate all Windows
        EnumWindows(ewp, 0);
    }
    /// <summary>
    /// Collection Constructor
    /// </summary>
    public Windows()
    {
        //Declare a callback delegate for EnumWindows() API call
        EnumWindowsProc ewp = new EnumWindowsProc(EvalWindow);
        //Enumerate all Windows
        EnumWindows(ewp, 0);
    }
    //EnumWindows CALLBACK function
    private bool EvalWindow(int hWnd, int lParam)
    {
        if (m_invisible == false && !IsWindowVisible(hWnd))
            return(true);
        StringBuilder title = new StringBuilder(256);
        StringBuilder module = new StringBuilder(256);
        GetWindowModuleFileName(hWnd, module, 256);
        GetWindowText(hWnd, title, 256);
        if (m_notitle == false && title.Length == 0)
            return(true);
        wndArray.Add(new Stealth(title.ToString(), (IntPtr)hWnd, module.ToString()));
        return(true);
    }
    //implement IEnumerable
    public IEnumerator GetEnumerator()
    {
        return (IEnumerator)this;
    }
    //implement IEnumerator
    public bool MoveNext()
    {
        m_Position++;
        if (m_Position < wndArray.Count)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    public void Reset()
    {
        m_Position = -1;
    }
    public object Current
    {
        get
        {
            return wndArray[m_Position];
        }
    }
}

thank you CodingInCSharp!! i'm working too in c# and I'm using EasyHook to inject my dll into pokerstars account. Do you know how to get text from the chat window? the old method (ovveriding the DrawText winAPI) is not working anymore cause they have created a new window to draw the text in the chatbox.

Right now i'm usin WinaApiOvveride ( http://jacquelin.potier.free.fr/winapioverride32/ ) to see which WinApi calls are used but with no real success... does anybody can point me to the right direction? thank you in advance.

C# the wave of the future.....

Download the sourcecode to SNGEGT it's a working botlike program written in c#. It has screenscraping and ocr for pokerstars and fulltilt. Works like a charm and i used it in conjunction with the stealth class to write a new (real)bot. Don't use dll hooking if you want your bot to do stealth. To inject and use a hook is something we used to do in the old days when writing a virus... It's easy to detect for the pokerclient. Screenscraping however is not easy to detect. Because pokerroomsoftware is not allowed to take a picture or look at your system (privacy laws etc.. http://www.privacylaws.com) However they may look and test their own software. So if you wanna stay undetected scrape the screen, hide and don't stack 12 pokerrooms on each other. (Yes people, that's where the most of the bots get caught. No human interface can handle 12 turbo rooms at a time. Stay with 3 per bot per account and you'll almost never get caught. at least i didn't)

The url for source SNGEGT http://www.sngegt.com/index.php?action=Downloads

By the way, you don't need to drive a stick to code a working bot. c# and .NET are fast enough. So write as much as you can in managed code because memory leaks, buffer and stack errors are more prone when you code in c++. And if you realy want speed. Use ASM :)

good

thank you very much CodingInCSharp... i have downloaded sngegt and tomorrow i'll give it a try....

you said: "To inject and use a hook is something we used to do in the old days when writing a virus... It's easy to detect for the pokerclient."

can you please explain me how it can be detected? how a program can see if a dll is injected into a program's process?

thanks in advance!

Anyone using Wine to run the PS client under Linux?

1 st: It's easy to detect, because you can send an extra indentifier with the text, not visible for de hook dll. At the other side, you test if that indentifier has arrived. If not, there must be a hook reroute. (this is when changing text) second : You can test who is accessing the dll, hooks need a point of entry. (works allways)

Allmost every virus scanner checks on hooks / injection, so how do you think they get those virussus? If it was impossible to check on injection or hooks, then you could write a virus that was undetectable. We know that is not true. So injection / hooking is not save...

Screenscraping however is undetectable, you make a copy of the screen and scrape it in memory. Just look at SNGEGT, it makes a copy of the screen (and saves it for debugging, but i cut that out) in own memory. It's done in OwnImage.cs. Just take a look and see how it's done. Then it uses ocr to trace the pixels in an small stack / bet window. it's fast and save to do.

Glad to see you're back JD.

You never explained about the 'going to work for PokerStars'.

Would it even be legal?

What we need is something like Murata Boy ( http://www.murataboy.com/en ). Place one of these wonders in front of the computer and have it to operate the keyboard and mouse, and let's see PokerStars detect this baby!

thx codingInCSharp for your reply! I have been already caught by pokerstars developing my bot. it uses to work by injecting a dll into pokerstars process. Looks like those guys watches if your Visual Studio IDE is opened too ;) Thx to your suggestions, i'm now developing an ocr based bot and let's see what happens... OpenHoldem ( http://pokerai.org/openholdem.html ) is also doing a great job in screenscraping thw pokerstars window, but as you told, let's see where i can get just with c# and with SNGEGT even if it doesn't give me all i need... like the cards on the table...

oleeeee, congrats all!!!

Myro i'm rewriting sngegt at this moment and i only focus on fulltilt, but i get everything that's visible. From stacks, bets and cards. The ocr is very fast and i made some adjustments by not saving the image so there is only a copy in memory. It's very fast and i get enough images per second (i have to slow it down manualy, otherwise it will hijack the processor).

The hand ev odds etc... calculation in sngegt is only done pre flop, but i've changed it to do it with every card. But i use a separate thread for the calculations. Only if the cards have changed from the new image compared to the old image i start that thread for that table again to do the calc. So low overhead on the heavy calculations.

If you focus on just one pokerroom (pokerstars in your case) in sngegt and follow the sourcecode flow with breakpoints then everything should become obvious.

hi CodingInCSharp! could u please contact me at nemesisattax@hushmail.com?

Good new year for everybody!

4日の参院予算委員会では、小沢グループの奥村展三文部科学副大臣と中塚一宏内閣府副大臣が消費税法案に賛成する意向を表明した。奥村、中塚両氏は小沢元代表の意向に反し辞表を提出していない。

 首相は辞任した4人の後任について、消費税法案への賛否を確認した上で起用する方針だ。

Use the form below to leave a comment.






Coding the Wheel has appeared on the New York Time's Freakonomics blog, Jeff Atwood's Coding Horror, and the front page of Reddit, Slashdot, Digg.

On Twitter

Thanks for reading!

If you enjoyed this post, consider subscribing to Coding the Wheel by RSS or email. You can also follow us on Twitter and Facebook. And even if you didn't enjoy this post, better subscribe anyway. Keep an eye on us.

Question? Ask us.

About

Poker

Coding the Wheel =
Code, poker, technology, games, design, geekery.


Hire

You've read our technical articles, you've tolerated our rants and raves. Now you can hire us anytime, day or night, for any project large or small.

Learn more

We Like

Speculation, by Edmund Jorgensen.