private int alphabeta(Coordinate field, int boardvalue, int alpha, int beta, int depthbound, int depth
#if PRETTY
                          , string parent
#endif
                          )
    {
#if STATS
        ++nodesvisited;
        depthnodes[depth]++;
        if (depth > maxdepth)
        {
            maxdepth = depth;
        }
#endif
        ++expirenodecnt;
        if (expirenodecnt >= 3000)
        {
            expirenodecnt = 0;
            //Console.WriteLine("Checking timeout: {0}", DateTime.Now);
            if (DateTime.Now > expiretime)
            {
                //Console.WriteLine("Timeout: {0}", DateTime.Now);
                throw new ABSearchTimeoutException();
            }
        }

        int attacker = (depth % 2 == 0) ? 1 : -1;

        InterestingFieldAgent fieldagentbackup = (InterestingFieldAgent)fieldagent.Clone();

        board[field.X, field.Y] = -1 * attacker;         // remember: field comes still from the upper level.
        fieldagent.UpdateInterestingFieldArray(board, field);
        fieldagent.UpdateThreatLists(board, field, -1 * attacker);

        boardvalue += field.Val;

#if PRETTY
        string thisnode = "" + nodesvisited;
        if (nodesvisited < 250)
        {
            string infostring = "";
            infostring += "<table>";
            infostring += "<tr><td>";
            infostring += "node: " + thisnode + "-" + depthnodes[depth] + ", boardval: " + boardvalue + ", moveval: " + eval.statVal(board, field, -1 * attacker);
            infostring += "</td></tr>";
            infostring += "<tr><td>compare val: " + field.Val + "</td></tr>";
            infostring += "<tr><td>last move from: " + attacker * -1 + "</td></tr>";
            infostring += "<tr><td>Own threats: " + fieldagent.ownthreatlist.Count + "</td></tr>";
            foreach (Threat t in fieldagent.ownthreatlist)
            {
                infostring += "<tr><td>cat : " + t.category + "</td></tr>";
                foreach (Coordinate c in t.fields)
                {
                    infostring += "<tr><td>coord : " + c + "</td></tr>";
                }
            }
            infostring += "<tr><td>Own threats added: " + fieldagent.ownaddedthreatlist.Count + "</td></tr>";
            foreach (Threat t in fieldagent.ownaddedthreatlist)
            {
                infostring += "<tr><td>cat : " + t.category + "</td></tr>";
                foreach (Coordinate c in t.fields)
                {
                    infostring += "<tr><td>coord : " + c + "</td></tr>";
                }
            }
            infostring += "<tr><td>Own threats removed: " + fieldagent.ownremovedthreatlist.Count + "</td></tr>";
            foreach (Threat t in fieldagent.ownremovedthreatlist)
            {
                infostring += "<tr><td>cat : " + t.category + "</td></tr>";
                foreach (Coordinate c in t.fields)
                {
                    infostring += "<tr><td>coord : " + c + "</td></tr>";
                }
            }
            infostring += "<tr><td>Opp threats: " + fieldagent.oppthreatlist.Count + "</td></tr>";
            foreach (Threat t in fieldagent.oppthreatlist)
            {
                infostring += "<tr><td>cat : " + t.category + "</td></tr>";
                foreach (Coordinate c in t.fields)
                {
                    infostring += "<tr><td>coord : " + c + "</td></tr>";
                }
            }
            infostring += "<tr><td>Opp threats added: " + fieldagent.oppaddedthreatlist.Count + "</td></tr>";
            foreach (Threat t in fieldagent.oppaddedthreatlist)
            {
                infostring += "<tr><td>cat : " + t.category + "</td></tr>";
                foreach (Coordinate c in t.fields)
                {
                    infostring += "<tr><td>coord : " + c + "</td></tr>";
                }
            }
            infostring += "<tr><td>Opp threats removed: " + fieldagent.oppremovedthreatlist.Count + "</td></tr>";
            foreach (Threat t in fieldagent.oppremovedthreatlist)
            {
                infostring += "<tr><td>cat : " + t.category + "</td></tr>";
                foreach (Coordinate c in t.fields)
                {
                    infostring += "<tr><td>coord : " + c + "</td></tr>";
                }
            }
            infostring += "</table>";
            PrettyPrint.PrintBoard(wr, thisnode, board, infostring);
            wr.WriteLine("{0} -> {1};", parent, nodesvisited);
        }
#endif

        if (boardvalue > StatValEvaluator.WINBORDER || boardvalue < -StatValEvaluator.WINBORDER)
        {
            board[field.X, field.Y] = 0;
            if (attacker == 1)
            {
                return(boardvalue - depth * 10000);
            }
            else
            {
                return(boardvalue + depth * 10000);
            }
        }

        if (depth == depthbound)
        {
            board[field.X, field.Y] = 0;
            return(boardvalue);
        }

        ArrayList fields = null;
        if (depth == 0)
        {
            fields = firstMoveFields;
        }
        else
        {
            fields = fieldagent.ReallyInterestingFields(board, attacker);
        }

        // Calculate the static value for all fields
        for (int i = 0; i < fields.Count; ++i)
        {
            Coordinate c = (Coordinate)fields[i];
            board[c.X, c.Y] = attacker;
            InterestingFieldAgent valifabackup = (InterestingFieldAgent)fieldagent.Clone();
            fieldagent.UpdateThreatLists(board, c, attacker);
            c.Val           = eval.statVal(board, c, attacker);
            fieldagent      = valifabackup;
            board[c.X, c.Y] = 0;
            fields[i]       = c;
        }

        fields.Sort();
        if (depth % 2 == 0)
        {
            //MAX node
            fields.Reverse();
            foreach (Coordinate ifield in fields)
            {
                int max = alpha;
                if ((max = alphabeta(ifield, boardvalue, alpha, beta, depthbound, depth + 1
#if PRETTY
                                     , thisnode
#endif
                                     )) > alpha)
                {
                    alpha = max;
                    if (depth == 0)
                    {
                        tmpbestfield = ifield;
                    }
                }
                if (depth == 0)
                {
                    Console.WriteLine("Got max from {0}: {1}", ifield, max);
                }
                if (alpha >= beta)
                {
                    fieldagent = fieldagentbackup;
                    if (depth == 0)
                    {
                        tmpbestfield = ifield;
                    }
                    board[field.X, field.Y] = 0;
                    return(beta);
                }
            }
            fieldagent = fieldagentbackup;
            board[field.X, field.Y] = 0;
            return(alpha);
        }
        else
        {
            //MIN node
            foreach (Coordinate ifield in fields)
            {
                if (depth == 0)
                {
                    tmpbestfield = ifield;
                }
                int min = beta;

                if ((min = alphabeta(ifield, boardvalue, alpha, beta, depthbound, depth + 1
#if PRETTY
                                     , thisnode
#endif
                                     )) < beta)
                {
                    beta = min;
                    if (depth == 0)
                    {
                        tmpbestfield = ifield;
                    }
                }
                if (alpha >= beta)
                {
                    fieldagent = fieldagentbackup;
                    if (depth == 0)
                    {
                        tmpbestfield = ifield;
                    }
                    board[field.X, field.Y] = 0;
                    return(alpha);
                }
            }
            fieldagent = fieldagentbackup;
            board[field.X, field.Y] = 0;
            return(beta);
        }
    }