@name iterrecurse2
@inputs 
@outputs Maxs:array Best:vector2
@persist Maxs:array Levels:array Todo:array Undo:array Game:table DepthLeft Turn RGame:table
@trigger none


if (first()) {
    Game = table(
        array(0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0)
    )
    
    RGame = Game:clone()
        
    Eval = table(
        array(3, 4,  5, 7,   5, 4, 3),
        array(4, 6,  8, 10,  8, 6, 4),
        array(5, 8, 11, 13, 11, 8, 5),
        array(5, 8, 11, 13, 11, 8, 5),
        array(4, 6,  8, 10,  8, 6, 4),
        array(3, 4,  5,  7,  5, 4, 3)
    )
    
    function number eval( G:table ) {
            local Sum = 128
            for (Row = 1, 6) {
                for (Col = 1, 7) {
                    if (G[Row, array][Col, number] != 0) {
                        Sum += Eval[Row, array][Col, number]    
                    }
                }
            }
            
            return Sum 
    }
        
    function number do_move( Table:table, Row, Col, Val ) {
        Table[Row, array][Col, number] = Val    
    }
    
    function number undo_move( Table:table, Row, Col ) {
        Table[Row, array][Col, number] = 0
    }
    
    
#[        function number table:can_insert( Col ) {
        for (R = 1, 6) {
            if (This[R, array][Col, number] != 0) {
                return R - 1
            }
        }
        return 6
    }]#
    
    function array get_moves( Table:table ) {
        local Moves = array()
        for (Column = 1, 7) {
            local MoveRow = 6
            for (Row = 1, 6) {
                if (Table[Row, array][Column, number] != 0) {
                    MoveRow = Row - 1
                    break    
                }
            }
            if (MoveRow > 0) { Moves:pushVector2( vec2(MoveRow, Column) ) }
        }
        return Moves    
    }
    
    DepthLeft = 5
    
 #   print( get_moves( Game ) )
    
#[    Maxs:pushNumber(-10000)
    
    local Legals = get_moves(Game)
    
    while (Legals:count()) {
        Todo:pushVector2(Legals:popVector2())   
        Levels:pushNumber(1) 
    }
    ]#
}

interval(1000)

    Maxs:pushNumber(-10000)
    
    Game = RGame:clone()

    print("\n\n\n\n----------")
    for (Row = 1, 6) {
        print(Game[Row, array])
    }
        
    local Legals = get_moves(Game)
    
    while (Legals:count()) {
        Todo:pushVector2(Legals:popVector2())   
        Levels:pushNumber(1) 
    }
    
    while (perf() & Todo:count()) {
        local Move = Todo:popVector2()
        local Level = Levels:popNumber()
        
        Undo:pushVector2(Move)    
        
        if (Level != DepthLeft) {
            Maxs:pushNumber(-10000)   
        }
        
        do_move(Game, Move[1], Move[2], Level % 2 == 0 ? -1 : 1)
        
        if (Level == DepthLeft) {
            local Score = -eval(Game) * (Level % 2 == 0 ? -1 : 1)
            if (Score > Maxs[Maxs:count(), number]) {
                Maxs:popNumber()
                Maxs:pushNumber(Score)    
                
                Best = Move
            }
            
            local UndoMove = Undo:popVector2()
            undo_move(Game, UndoMove[1], UndoMove[2])
            
            local Diff = Level - Levels[Levels:count(), number]
            if (Diff != 0) {
                while (Diff > 0) {
                    Diff--
                    
                    Score = -Maxs:popNumber()
                    if (Score > Maxs[Maxs:count(), number]) {
                        Maxs:popNumber()
                        Maxs:pushNumber(Score)
                        
                        Best = Move
                    }
                    
                    local UndoMove = Undo:popVector2()
                    undo_move(Game, UndoMove[1], UndoMove[2])
                }
            }
        }
        else {
            local Legals = get_moves(RGame)
            while (Legals:count()) {
                Todo:pushVector2(Legals:popVector2())   
                Levels:pushNumber(Level + 1) 
            }
        }
        
        #undo_move(Game, Move[1], Move[2])
    }
    
    
    #print(Best)
    
    if (Best:length()) { Turn++, do_move(RGame, Best[1], Best[2], Turn % 2 == 0 ? -1 : 1) }
    


#[
Random r = new Random();
Stack<int> maxs = new Stack<int>();
Stack<int> levels = new Stack<int>();
Stack<string> todo = new Stack<string>();
Stack<string> undo = new Stack<string>();
maxs.Push(int.MinValue);

var le = legals(bd);
while (le.Any())
{
    var mv = le[r.Next(le.Count)];
    le.Remove(mv);
    todo.Push(mv);
    levels.Push(1);
}

while (todo.Any())
{
    //init
    string mv = todo.Pop();
    int level = levels.Pop();
    undo.Push(mv);
    if (level != depthleft) maxs.Push(int.MinValue);
    move(mv, level % 2 == 0 ? "b" : "w");

    //expand children/do operations,cleanup
    if (level == depthleft)
    {
         int score = -eval(bd, level % 2 == 0);
         if (score > maxs.Last())
         {
              maxs.Pop();
              maxs.Push(score);
         }
         unmove(undo.Pop());

         int diff = level - levels.Last();
         if (diff != 0)
         {
              for (; diff > 0; diff--)
              {
                   score = -maxs.Pop();
                   if (score > maxs.Last())
                   {
                        maxs.Pop();
                        maxs.Push(score);
                   }
                   unmove(undo.Pop());
              }
         }
     }
     else
     {
          var ls = legals(bd);
          while (ls.Any())
          {
              var child = ls[r.Next(ls.Count)];
              ls.Remove(child);
              todo.Push(child);
              levels.Push(level + 1);
          }
     }
}     
]#
