#@name tetris2
@inputs EGP:wirelink
@outputs 
@persist [Tetris Tetromino Colors]:table [CurRow CurCol] [NextRow NextCol]
@persist [Game Piece]:table Color GameOver HOLO StepTime [HOLO_Base HOLO_ID]
@trigger none

if (first()) {
    
    
    #------------------------
    #-- GAME: Default
    Tetris = table(
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
        array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    )


    #------------------------
    #-- PIECE: Shapes 
    Tetromino = table(
        1 = table( #-- i
            array(0, 0, 0, 0),
            array(1, 1, 1, 1),
            array(0, 0, 0, 0),
            array(0, 0, 0, 0)
        ),
        2 = table( #-- j
            array(1, 0, 0),
            array(1, 1, 1),
            array(0, 0, 0)    
        ),
        3 = table( #-- l
            array(0, 0, 1),
            array(1, 1, 1),
            array(0, 0, 0)
        ),
        4 = table( #-- o
            array(1, 1),
            array(1, 1)
        ),
        5 = table( #-- s
            array(0, 1, 1),
            array(1, 1, 0),
            array(0, 0, 0)
        ),
        6 = table( #-- t
            array(0, 1, 0),
            array(1, 1, 1),
            array(0, 0, 0)
        ),
        7 = table( #-- z
            array(1, 1, 0),
            array(0, 1, 1),
            array(0, 0, 0)
        )
    )
    
        
    #------------------------
    #-- PIECE: Colors
    Colors = table(
        0 = hsv2rgb(  0, 0, 1), #-- white
        1 = hsv2rgb(180, 1, 1), #-- i, cyan
        2 = hsv2rgb(240, 1, 1), #-- j, blue
        3 = hsv2rgb( 30, 1, 1), #-- l, orange
        4 = hsv2rgb( 60, 1, 1), #-- o, yellow
        5 = hsv2rgb(120, 1, 1), #-- s, green
        6 = hsv2rgb(300, 1, 1), #-- t, magenta
        7 = hsv2rgb(360, 1, 1)  #-- z, red
    )


    #------------------------
    #-- PIECE: Rotate    
    function rotatePiece( Left ) {
        local Len = Piece:count()
        local New = table()

        for (I = 1, Len) {
            for (J = 1, Len) {
                New[J, array] = New[J, array] ?: array()
    
                if (Left > 0) {
                    New[J, array][I, number] = Piece[I, array][Len - J + 1, number]
                }
                else {
                    New[J, array][I, number] = Piece[Len - I + 1, array][J, number]                
                }
            }
        }
        
        Piece = New
    }


    #------------------------
    #-- PIECE: Spawn
    function spawnPiece() {
        local RColor = randint(1, 7)
        local RPiece = Tetromino[RColor, table]:clone()
        
        local Len = RPiece:count()
        for (I = 1, Len) {
            for (J = 1, Len) {
                RPiece[I, array][J, number] = RPiece[I, array][J, number] * RColor
            }
        }
        
        Piece = RPiece
        Color = RColor
        
        CurRow = 0
        CurCol = 0
    }



    #------------------------
    #-- GAME: Place piece
    function placePiece() {
        local Len = Piece:count()
        for (PY = 1, Len) {
            for (PX = 1, Len) {
                if (Piece[PY, array][PX, number]) {
                    Game[CurRow + PY, array][CurCol + PX, number] = Piece[PY, array][PX, number]    
                }        
            }
        }

        #-- remove lines and update score  
    }

    #------------------------
    #-- GAME: Reset
    function resetGame() {
        Game = Tetris:clone()
    }    
    

    #-- GAME: Print 
    function printGame( G:table ) {

        printColor(vec(255, 255, 255), "      Tetris")
        for (R = 1, 20) {
            local A = G[R, array]
            printColor(
                Colors[A[1, number], vector],  A[1, number]  + " ",
                Colors[A[2, number], vector],  A[2, number]  + " ",
                Colors[A[3, number], vector],  A[3, number]  + " ",
                Colors[A[4, number], vector],  A[4, number]  + " ",
                Colors[A[5, number], vector],  A[5, number]  + " ",
                Colors[A[6, number], vector],  A[6, number]  + " ",
                Colors[A[7, number], vector],  A[7, number]  + " ",
                Colors[A[8, number], vector],  A[8, number]  + " ",
                Colors[A[9, number], vector],  A[9, number]  + " ",
                Colors[A[10, number], vector], A[10, number] + " "
            ) 
        }
    }   


    function number pieceCollision() {
        local Len = Piece:count()
        for (R = 1, Len) {
            for (C = 1, Len) {
                if (Piece[R, array][C, number]) {
                    if (Game[R + NextRow, array][C + NextCol, number]) {
                        return 1
                    }
                    
                    if (C + NextCol <  1)  { return 3 }
                    if (C + NextCol >= 10) { return 4 }
                    if (R + NextRow > 20)  { return 2 }
                }
            }
        }
        return 0
    }

    
    resetGame()
    spawnPiece()
    
    HOLO_ID++
    HOLO_Base = HOLO_ID
    holoCreate(HOLO_Base)
    holoAlpha(HOLO_Base, 50)

    function spawnPieceHolo() {
        local Dim = Piece:count()

        for (I = HOLO_ID, HOLO_ID - 4, -1) {
            holoUnparent(I)    
        }
                
        holoPos(HOLO_Base, entity():toWorld(vec(0, CurCol, CurRow)))
        holoAng(HOLO_Base, entity():toWorld(ang()))
        

    
        for (PieceRow = 1, Dim) {
            for (PieceCol = 1, Dim) {
                if (Piece[PieceRow, array][PieceCol, number]) {
                    HOLO_ID++
                    holoCreate(HOLO_ID)
                    holoParent(HOLO_ID, HOLO_Base)
                    holoPos(HOLO_ID, holoEntity(HOLO_Base):toWorld(vec(0, 12*PieceCol - 6*Dim - 6, -12*PieceRow + 6*Dim + 6)))
                    holoScaleUnits(HOLO_ID, vec(sqrt(11), 11, 11))
                    holoColor(HOLO_ID, Colors[Color, vector])    
                    holoDisableShading(HOLO_ID, 1)
                    holoMaterial(HOLO_ID, "models/shiny")
                    holoModel(HOLO_ID, "rcube")
                }
            }
        }
        
        
    }
    
    spawnPieceHolo()
    
#[    local Len = Piece:count()
    for (R = 1, Len) {
        for (C = 1, Len) {
            if (Piece[R, array][C, number]) {
                HOLO++
                
                holoCreate(HOLO, entity():toWorld(vec(0, (C - 1)*12, -(R - 1)*12)), vec(11/12))
                holoColor(HOLO, Colors[Color, vector])
            }
        }
    }]#
    
   # GameOver = 1
    StepTime = curtime()
}



interval(15)

if (!GameOver) {
    Dir = owner():keyPressed("right") - owner():keyPressed("left")
    if (changed(Dir) & Dir) {
        NextCol = CurCol + Dir
        if (!pieceCollision()) {
            CurCol = NextCol
            
            holoPos(HOLO_Base, entity():toWorld(vec(0, (CurCol - 1)*12, -(CurRow - 1)*12)))
            
#[            local Len = Piece:count()
            local IDX = HOLO - 4
            for (R = 1, Len) {
                for (C = 1, Len) {
                    if (Piece[R, array][C, number]) {
                        IDX++
                        holoPos(IDX, entity():toWorld(vec(0, (C + CurCol - 1)*12, -(R + CurRow - 1)*12)))
                    }
                }
            }]#
        }
    }
    
    Rot = owner():keyPressed("up") - owner():keyPressed("down")
    if (changed(Rot) & Rot) {
        rotatePiece(Rot)
        if (pieceCollision()) {
            rotatePiece(-Rot)
        }
        else {
#[            local Len = Piece:count()
            local IDX = HOLO - 4
            for (R = 1, Len) {
                for (C = 1, Len) {
                    if (Piece[R, array][C, number]) {
                        IDX++
                        holoPos(IDX, entity():toWorld(vec(0, (C + CurCol - 1)*12, -(R + CurRow - 1)*12)))
                    }
                }
            }            ]#
        }
    }
    
    if (curtime() - StepTime > 0.25) {
        StepTime = curtime()
    
        NextRow = CurRow + 1
        NextCol = CurCol + 0
        
        if (!pieceCollision()) {
            CurRow = NextRow
            CurCol = NextCol   
            
            holoPos(HOLO_Base, entity():toWorld(vec(0, (CurCol - 1)*12, -(CurRow - 1)*12)))
            
#[            local Len = Piece:count()
            local IDX = HOLO - 4
            for (R = 1, Len) {
                for (C = 1, Len) {
                    if (Piece[R, array][C, number]) {
                        IDX++
                        holoPos(IDX, entity():toWorld(vec(0, (C + CurCol - 1)*12, -(R + CurRow - 1)*12)))
                    }
                }
            }]#
        }
        else {
            placePiece()
            printGame(Game)
            
            spawnPiece()
            
            NextRow = CurRow + 1
            NextCol = CurCol + 0  
            
            spawnPieceHolo()
            
#[            local Len = Piece:count()
            for (R = 1, Len) {
                for (C = 1, Len) {
                    if (Piece[R, array][C, number]) {
                        HOLO++
                        
                        holoCreate(HOLO, entity():toWorld(vec(0, (C - 1)*12, -(R - 1)*12)), vec(11/12))
                        holoColor(HOLO, Colors[Color, vector])
                    }
                }
            }
            ]#
            if (pieceCollision()) { GameOver = 1, print("GAME OVER") }  
        }
    }
}


#[

wall kick

I'll let you figure out the details, but essentially you need to check 
whether rotating the tetromino would move it out of bounds and, if so, 
move it left or right one or two spaces as necessary. However, you 
must remember to check for potential collisions with other blocks after 
applying both the rotation and the movement!

]#
