-- CCL Breakout
-- jey@coral8.com

-- Set this variable to TRUE to enable "AI mode" by default.
-- AI mode may be toggled on and off by pressing the "A" key in the client.
-- For more information on "AI mode", see the bottom of this module.
CREATE VARIABLE BOOLEAN AutoPlayMode = FALSE;

CREATE WINDOW Brick SCHEMA (ID INTEGER, Type INTEGER, X INTEGER, Y INTEGER) KEEP ALL;
CREATE WINDOW Paddle SCHEMA (X INTEGER, Y INTEGER, V INTEGER) KEEP LAST;
CREATE WINDOW Ball SCHEMA (ID INTEGER, X INTEGER, Y INTEGER, XV INTEGER, YV INTEGER) KEEP LAST PER ID;
CREATE VARIABLE BOOLEAN Running = FALSE;
CREATE VARIABLE INTEGER BallsLost = 0;
CREATE VARIABLE INTEGER BottomBounce = 0;
CREATE VARIABLE TIMESTAMP BottomBounceEnd = NULL;
CREATE VARIABLE BOOLEAN RestartRequested = FALSE;
CREATE VARIABLE BOOLEAN RestartInProgress  = FALSE;
CREATE VARIABLE BOOLEAN ExpectingAIResponse = FALSE;

/* entry point */
INSERT INTO Initialize
SELECT 0
FROM MsgIn
WHERE Type = "CONNECT";

/** PutPixel(int x, int y) */
INSERT INTO MsgOut
SELECT
    "PIXEL",
    TO_STRING(X) || "," || TO_STRING(Y) || "," || COALESCE(Color, "255,255,255")
FROM PutPixel;

/** PlayMacro(string name) */
INSERT INTO MsgOut
SELECT "MACRO", Macro
FROM PlayMacro;

/** PlayMacroAtPos(string name, int Paddle_x, int orgin_y) */
INSERT INTO MsgOut
SELECT "OMACRO", Macro || "," || TO_STRING(X) || "," || TO_STRING(Y)
FROM PlayMacroAtPos;

/** DrawRectangle(int x1, int y1, int x2, int y2) */
-- Draw each pixel
INSERT INTO PutPixel
SELECT X, Y, Color
FROM DrawRectangle
WHERE X <= X2 AND Y <= Y2;

-- Initial case
INSERT INTO DrawRectangle
SELECT X1, Y1, X1, Y1, X2, Y2, Color
FROM DrawRectangle
WHERE X IS NULL AND Y IS NULL;

-- Iterating through row
INSERT INTO DrawRectangle
SELECT X+1, Y, X1, Y1, X2, Y2, Color
FROM DrawRectangle
WHERE X < X2 AND Y <= Y2;

-- End of row
INSERT INTO DrawRectangle
SELECT X1, Y+1, X1, Y1, X2, Y2, Color
FROM DrawRectangle
WHERE X = X2 AND Y <= Y2;

/** DrawFilledCircle(int mid_x, int mid_y, int r, string caller_data) */
-- Base case: begin iteration from upper left
INSERT INTO DrawFilledCircle
SELECT 0, 0, MidX, MidY, R, Color
FROM DrawFilledCircle
WHERE I IS NULL AND J IS NULL;

-- Draw each pixel (4 at a time)
-- No, this is not as expensive as it looks.
-- Primitive folding will combine the WHERE clauses into one filter.
INSERT INTO PutPixel
SELECT MidX+I, MidY+J, Color
FROM DrawFilledCircle
WHERE SQRT(I*I + J*J) <= R;

INSERT INTO PutPixel
SELECT MidX-I, MidY+J, Color
FROM DrawFilledCircle
WHERE SQRT(I*I + J*J) <= R;

INSERT INTO PutPixel
SELECT MidX+I, MidY-J, Color
FROM DrawFilledCircle
WHERE SQRT(I*I + J*J) <= R;

INSERT INTO PutPixel
SELECT MidX-I, MidY-J, Color
FROM DrawFilledCircle
WHERE SQRT(I*I + J*J) <= R;

-- Iterating through row
INSERT INTO DrawFilledCircle
SELECT I+1, J, MidX, MidY, R, Color
FROM DrawFilledCircle
WHERE I < R AND J <= R;

-- End of row
INSERT INTO DrawFilledCircle
SELECT 0, J+1, MidX, MidY, R, Color
FROM DrawFilledCircle
WHERE I = R AND J < R;

/*** Initialization */
INSERT INTO Initialize
SELECT Step+1
FROM Initialize
WHERE NOT (Step IN (1, 2, 3)) AND Step < 13
OUTPUT AFTER 1 MICROSECOND;

-- 0
INSERT INTO MsgOut
SELECT "TITLE", "Loading..."
FROM Initialize
WHERE Step = 0;

INSERT INTO Paddle
SELECT 320 - $PaddleWidth/2, 450, 0
FROM Initialize
WHERE Step = 0;

INSERT INTO Ball
SELECT 0, 320, 240, TO_INTEGER(16 * RANDOM() - 8), $BallYVel
FROM Initialize
WHERE Step = 0;

ON Initialize
WHEN Step = 0
SET BallsLost = 0, BottomBounce = 0,
    BottomBounceEnd = NULL, ExpectingAIResponse = FALSE;

ON Initialize
WHEN Step = 0
DELETE FROM Ball;

ON Initialize
WHEN Step = 0
DELETE FROM Paddle;

ON Initialize
WHEN Step = 0
DELETE FROM Brick;

-- 1
INSERT INTO LoadBricks
SELECT 0
FROM Initialize
WHERE Step = 1 AND NOT RestartInProgress;

INSERT INTO Initialize
SELECT Step+1
FROM Initialize
WHERE Step = 1 AND RestartInProgress;

-- 2
INSERT INTO MakeBricks
SELECT 0, 0
FROM Initialize
WHERE Step = 2;

-- 3
INSERT INTO DrawBricks
SELECT 0
FROM Initialize
WHERE Step = 3;

-- 4
INSERT INTO MsgOut
SELECT "RECORD", "PAD"
FROM Initialize
WHERE Step = 4 AND NOT RestartInProgress;

-- 5
INSERT INTO DrawRectangle (X1, Y1, X2, Y2, Color)
SELECT 0, 0, $PaddleWidth, $PaddleHeight, "255,255,255"
FROM Initialize
WHERE Step = 5 AND NOT RestartInProgress;

-- 6
INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM Initialize
WHERE Step = 6 AND NOT RestartInProgress;

-- 7
INSERT INTO MsgOut
SELECT "RECORD", "BALL"
FROM Initialize
WHERE Step = 7 AND NOT RestartInProgress;

-- 8
INSERT INTO DrawFilledCircle (MidX, MidY, R, Color)
SELECT 0, 0, $BallRadius, "255,255,255"
FROM Initialize
WHERE Step = 8 AND NOT RestartInProgress;

-- 9
INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM Initialize
WHERE Step = 9 AND NOT RestartInProgress;

-- 10
INSERT INTO MsgOut
SELECT "RECORD", "FLOOR"
FROM Initialize
WHERE Step = 10 AND NOT RestartInProgress;

-- 11
INSERT INTO DrawRectangle (X1, Y1, X2, Y2, Color)
SELECT 0, 475, 640, 480, "200,0,0"
FROM Initialize
WHERE Step = 11 AND NOT RestartInProgress;

-- 12
INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM Initialize
WHERE Step = 12 AND NOT RestartInProgress;

-- 13
INSERT INTO AIInitialize
SELECT NULL
FROM Initialize
WHERE Step = 13;

INSERT INTO Initialize
SELECT 14
FROM AIInitializeDone
OUTPUT AFTER 1 MICROSECOND;

-- 14
INSERT INTO MsgOut
SELECT "TITLE", "CCL Breakout!"
FROM Initialize
WHERE Step = 14;

INSERT INTO MsgOut
SELECT "OK?", "InitDone"
FROM Initialize
WHERE Step = 14;

ON Initialize
WHEN Step = 14
SET RestartRequested = FALSE, RestartInProgress = FALSE;

-- await response for "OK?"
INSERT INTO MainLoop
SELECT 0
FROM MsgIn
WHERE Type = "OK" AND Data = "InitDone";

/** OK? handling */
INSERT INTO MsgOut
SELECT "OK", Data
FROM MsgIn
WHERE Type = "OK?";

/** Main Loop */
INSERT INTO MainLoop
SELECT Step+1
FROM MainLoop
WHERE Step <= 5 AND NOT (Step = 2 AND AutoPlayMode AND Running)
OUTPUT AFTER 1 MICROSECOND;

INSERT INTO PlayMacro
SELECT "BRICKS"
FROM MainLoop
WHERE MainLoop.Step = 0;

INSERT INTO PlayMacroAtPos
SELECT "PAD", Paddle.X, Paddle.Y
FROM MainLoop, Paddle
WHERE MainLoop.Step = 0;

INSERT INTO PlayMacroAtPos
SELECT "BALL", Ball.X, Ball.Y
FROM MainLoop, Ball
WHERE MainLoop.Step = 0;

INSERT INTO PlayMacro
SELECT "FLOOR"
FROM MainLoop
WHERE MainLoop.Step = 0 AND BottomBounce > 0;

INSERT INTO MsgOut
SELECT "FLIP", NULL
FROM MainLoop
WHERE MainLoop.Step = 1;

INSERT INTO MsgOut
SELECT "TITLE", "CCL Breakout! (Press space to unpause)"
FROM MainLoop
WHERE Step = 2 AND NOT Running;

INSERT INTO MsgOut
SELECT "TITLE", "CCL Breakout!    Balls Lost: " || TO_STRING(BallsLost)
FROM MainLoop
WHERE Step = 2 AND Running;

ON MainLoop
WHEN Step = 2 AND AutoPlayMode AND Running
SET ExpectingAIResponse = TRUE;

INSERT INTO AITrigger
SELECT NULL
FROM MainLoop
WHERE Step = 2 AND AutoPlayMode AND Running;

-- Here we "debounce" the input on AISetPaddleVelocity in case the AI
-- is buggy and sending us multiple rows per trigger row sent on AITrigger.
-- This query protects against the case where the rows all have the same timestamp.
-- The ExpectingAIResponse variable handles the case where the AI is sending
-- an input on AISetPaddleVelocity that does not have the same timestamp as
-- a row that is in response to a trigger row sent on AITrigger. If we didn't
-- do this filtering, a buggy AI could trigger multiple instances of MainLoop to
-- execute in parallel (since MainLoop is restarted from step 3 when the response
-- row arrives from the AI).
INSERT INTO SetPaddleVelocityDebounce
SELECT *
FROM AISetPaddleVelocity
WHERE ExpectingAIResponse
OUTPUT FIRST WITHIN 1 MICROSECOND;

ON SetPaddleVelocityDebounce
SET ExpectingAIResponse = FALSE;

INSERT INTO Paddle
SELECT P.X, P.Y, MIN($PaddleVel, MAX(-$PaddleVel, AI.PaddleVel))
FROM SetPaddleVelocityDebounce AS AI, Paddle AS P;

INSERT INTO MainLoop
SELECT 3
FROM SetPaddleVelocityDebounce;

INSERT INTO Paddle
SELECT MAX(0, MIN(640 - $PaddleWidth, P.X + P.V)), P.Y, P.V
FROM Paddle AS P, MainLoop
WHERE Step = 3 AND Running;

INSERT INTO Ball
SELECT B.ID, B.X + B.XV, B.Y + B.YV, B.XV, B.YV
FROM Ball AS B, MainLoop
WHERE Step = 3 AND Running;

INSERT INTO DoCollisions
SELECT BottomBounce
FROM MainLoop
WHERE MainLoop.Step = 4;

INSERT INTO Ball
SELECT
    0,
    P.X + $PaddleWidth/2,
    240,
    TO_INTEGER(16 * RANDOM() - 8),
    $BallYVel
FROM MainLoop FULL OUTER JOIN Ball, Paddle AS P
WHERE MainLoop.Step = 5 AND Ball.ID IS NULL;

INSERT INTO MainLoop
SELECT 0
FROM MainLoop, Paddle
WHERE MainLoop.Step = 5 AND NOT RestartRequested
OUTPUT AFTER 30 MILLISECONDS;

-- restart if requested
ON MainLoop
WHEN Step = 5 AND RestartRequested
SET RestartInProgress = TRUE;

INSERT INTO Initialize
SELECT 0
FROM MainLoop
WHERE Step = 5 AND RestartRequested
OUTPUT AFTER 1 MICROSECOND;

/** Pause */
ON MsgIn
WHEN Type = "KEYDN" AND Data = "SPACE"
SET Running = NOT Running;

/** Paddle Movement */
INSERT INTO Paddle
SELECT P.X, P.Y, P.V + $PaddleVel
FROM MsgIn AS M, Paddle AS P
WHERE NOT AutoPlayMode
    AND ((M.Type = "KEYDN" AND M.Data = "RIGHT")
        OR (M.Type = "KEYUP" AND M.Data = "LEFT"));

INSERT INTO Paddle
SELECT P.X, P.Y, P.V - $PaddleVel
FROM MsgIn AS M, Paddle AS P
WHERE NOT AutoPlayMode
    AND ((M.Type = "KEYDN" AND M.Data = "LEFT")
        OR (M.Type = "KEYUP" AND M.Data = "RIGHT"));

/** Toggle AI mode */
ON MsgIn
WHEN Type = "KEYDN" AND Data = "a"
SET AutoPlayMode = NOT AutoPlayMode;

INSERT INTO Paddle
SELECT P.X, P.Y, 0
FROM MsgIn, Paddle AS P
WHERE Type = "KEYDN" AND Data = "a";

/** Restart game */
ON MsgIn
WHEN Type = "KEYDN" AND Data = "r"
SET RestartRequested = TRUE;

/** load each brick graphic */
INSERT INTO LoadBricks
SELECT Step+1
FROM LoadBricks
WHERE Step < 12
OUTPUT AFTER 1 MICROSECOND;

INSERT INTO MsgOut
SELECT "RECORD", "B0"
FROM LoadBricks
WHERE Step = 0;

INSERT INTO DrawRectangle (X1, Y1, X2, Y2, Color)
SELECT 0, 0, $BrickWidth, $BrickHeight, "175,175,175"
FROM LoadBricks
WHERE Step = 1;

INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM LoadBricks
WHERE Step = 2;

INSERT INTO MsgOut
SELECT "RECORD", "B1"
FROM LoadBricks
WHERE Step = 3;

INSERT INTO DrawRectangle (X1, Y1, X2, Y2, Color)
SELECT 0, 0, $BrickWidth, $BrickHeight, "200,0,0"
FROM LoadBricks
WHERE Step = 4;

INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM LoadBricks
WHERE Step = 5;

INSERT INTO MsgOut
SELECT "RECORD", "B2"
FROM LoadBricks
WHERE Step = 6;

INSERT INTO DrawRectangle (X1, Y1, X2, Y2, Color)
SELECT 0, 0, $BrickWidth, $BrickHeight, "0,200,0"
FROM LoadBricks
WHERE Step = 7;

INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM LoadBricks
WHERE Step = 8;

INSERT INTO MsgOut
SELECT "RECORD", "B3"
FROM LoadBricks
WHERE Step = 9;

INSERT INTO DrawRectangle (X1, Y1, X2, Y2, Color)
SELECT 0, 0, $BrickWidth, $BrickHeight, "0,0,200"
FROM LoadBricks
WHERE Step = 10;

INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM LoadBricks
WHERE Step = 11;

INSERT INTO Initialize
SELECT 2
FROM LoadBricks
WHERE Step = 12;

/** MakeBricks() */
INSERT INTO MakeBricks
SELECT BrickID, Step+1
FROM MakeBricks
WHERE BrickID < 12 * $BrickRows AND Step < 4
OUTPUT AFTER 1 MICROSECOND;

INSERT INTO MakeBricks
SELECT BrickID+1, 0
FROM MakeBricks
WHERE BrickID < 12 * $BrickRows - 1
    AND Step = 4;

INSERT INTO Initialize
SELECT 3
FROM MakeBricks
WHERE BrickID = 12 * $BrickRows - 1 AND Step = 4;

INSERT INTO MsgOut
SELECT "RECORD", "_" || TO_STRING(BrickID)
FROM MakeBricks
WHERE BrickID < 12 * $BrickRows AND Step = 0;

INSERT INTO Brick
SELECT
    BrickID,
    CASE
        WHEN RANDOM() < $RedBrickProb THEN 1
        WHEN RANDOM() < $GreenBrickProb THEN 2
        WHEN RANDOM() < $BlueBrickProb THEN 3
        ELSE 0
    END,
    20 + (BrickID MOD 12) * 50,
    20 + (BrickID / 12) * 20
FROM MakeBricks
WHERE Step = 1 AND RANDOM() > .1;

INSERT INTO PlayMacroAtPos
SELECT "B" || TO_STRING(B.Type), B.X, B.Y
FROM Brick AS B, MakeBricks
WHERE Step = 2 AND B.ID = MakeBricks.BrickID;

INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM MakeBricks
WHERE Step = 3;

/** DrawBricks() */
INSERT INTO DrawBricks
SELECT Step+1
FROM DrawBricks
WHERE Step < 3
OUTPUT AFTER 1 MICROSECOND;

INSERT INTO MsgOut
SELECT "RECORD", "BRICKS"
FROM DrawBricks
WHERE Step = 0;

INSERT INTO PlayMacro
SELECT "_" || TO_STRING(ID)
FROM DrawBricks, Brick
WHERE Step = 1;

INSERT INTO MsgOut
SELECT "STOPREC", NULL
FROM DrawBricks
WHERE Step = 2;

INSERT INTO Initialize
SELECT 4
FROM DrawBricks
WHERE Step = 3;

/** DestroyBrick(int brick_id) */
ON DestroyBrick
DELETE FROM Brick
WHERE Brick.ID = DestroyBrick.BrickID;

INSERT INTO MsgOut
SELECT "DELMACRO", "_" || TO_STRING(BrickID)
FROM DestroyBrick;

/** Collisions */
INSERT INTO Ball
SELECT
    B.ID,
    B.X,
    IF B.Y > P.Y + $PaddleHeight/2
        THEN P.Y + $PaddleHeight
        ELSE P.Y - $PaddleHeight
        END,
    B.XV + P.V/3,
    -B.YV
FROM Paddle AS P, Ball AS B, DoCollisions
WHERE B.X + $BallRadius >= P.X
    AND B.X - $BallRadius <= P.X + $PaddleWidth
    AND (ABS(B.Y - (P.Y + $PaddleHeight)) <= $BallRadius
        OR ABS(B.Y - P.Y) <= $BallRadius);

INSERT INTO Ball
SELECT B.ID, B.X, B.Y, B.XV, -B.YV
FROM Paddle AS P, Ball AS B, DoCollisions
WHERE B.Y - $BallRadius <= 0;

INSERT INTO Ball
SELECT B.ID, B.X, B.Y, B.XV, -B.YV
FROM Paddle AS P, Ball AS B, DoCollisions
WHERE DoCollisions.BottomBounce > 0 AND B.Y + $BallRadius >= 480;

INSERT INTO Ball
SELECT B.ID, B.X, B.Y, -B.XV, B.YV
FROM Ball AS B, DoCollisions
WHERE (B.X - $BallRadius <= 0) OR (B.X + $BallRadius >= 640);

-- brick collision
INSERT INTO BrickCollision
SELECT R.ID, R.Type, B.ID, B.X, B.Y, B.XV, -B.YV
FROM Brick AS R, Ball AS B, DoCollisions
WHERE B.X + $BallRadius >= R.X
    AND B.X - $BallRadius <= R.X + $BrickWidth
    AND (ABS(B.Y - (R.Y + $BrickHeight)) <= $BallRadius
        OR ABS(B.Y - R.Y) <= $BallRadius);

INSERT INTO DestroyBrick
SELECT BrickID
FROM BrickCollision;

INSERT INTO Ball
SELECT BallID, BallX, BallY, BallXV, BallYV
FROM BrickCollision;

INSERT INTO Ball
SELECT
    MaxID.ID+1,
    TO_INTEGER(RANDOM() * 400 + 120),
    $BallRadius,
    TO_INTEGER(16 * RANDOM() - 8), $BallYVel
FROM BrickCollision,
    (SELECT MAX(ID) AS ID FROM Ball) AS MaxID KEEP LAST
WHERE BrickType = 3;

INSERT INTO Ball
SELECT
    MaxID.ID+1,
    BallX,
    BallY,
    TO_INTEGER(16 * RANDOM() - 8),
    $BallYVel * SIGN(RANDOM() - 0.5)
FROM BrickCollision,
    (SELECT MAX(ID) AS ID FROM Ball) AS MaxID KEEP LAST
WHERE BrickType = 2;

ON BrickCollision
WHEN BrickType = 1
SET BottomBounce = BottomBounce + 1,
    BottomBounceEnd = NOW() + 5 SECONDS;

INSERT INTO BottomBounceDec
SELECT 0
FROM BrickCollision
WHERE BrickCollision.BrickType = 1
OUTPUT AFTER 5 SECONDS;

ON BottomBounceDec
SET BottomBounce = BottomBounce - 1,
    BottomBounceEnd =
        IF BottomBounce > 0 THEN BottomBounceEnd ELSE NULL END;

INSERT INTO LostBall
SELECT Ball.*
FROM Ball, DoCollisions
WHERE Ball.Y > 480 AND DoCollisions.BottomBounce = 0;

INSERT INTO LostBall
SELECT B.*
FROM Ball AS B, DoCollisions
WHERE B.X < -$BallRadius OR B.X > 640 + $BallRadius
    OR B.Y < -$BallRadius OR B.Y > 480 + $BallRadius;

ON LostBall
DELETE FROM Ball
WHERE Ball.ID = LostBall.ID;

ON LostBall
SET BallsLost = BallsLost + 1;

/******* AI Mode *******
 * In AI mode, the paddle is controlled automatically by CCL code. Once per frame, Breakout
 * will send the AI a row on the stream AITrigger. This stream contains no useful data, but
 * is used to request the AI to set the paddle's horizontal velocity. The AI responds by sending
 * an integer in the range [-$PaddleVel, $PaddleVel] on the AISetPaddleVelocity stream. This integer
 * is clamped to be in range then set as the paddle's horizontal velocity in pixels per frame.
 *
 * AI mode can be toggled on and off with the "a" key.
 *
 * Rules:
 *  - The AI may take more than one timeslice (microsecond) to make its decision. After the game
 *    sends a row on the AITrigger stream, the rest of the game will NOT run until it receives
 *    a paddle velocity setting for this frame on the AISetPaddleVelocity stream.
 *
 * - The AI is permitted to read but not modify the following windows:
 *      Brick (ID INTEGER, Type INTEGER, X INTEGER, Y INTEGER)
 *          Contains one row per brick on the screen. ID is a unique identifier per brick.
 *          The brick is a rectangle with coordinates (X, Y) to (X + $BrickWidth, Y + $BrickHeight).
 *
 *          The brick types are:
 *              0. Gray     Regular brick
 *              1. Red      Makes the bottom of the arena solid for 5 seconds.
 *              2. Green    Releases a ball contained within the brick.
 *              3. Blue     Releases a ball from above the arena.
 *
 *      Paddle (X INTEGER, Y INTEGER, V INTEGER)
 *          Contains a single row with the Paddle's upper-left coordinates and horizontal velocity.
 *          The paddle is a rectangle with coordinates (X, Y) to (X + $PaddleWidth, Y + $PaddleHeight).
 *          The velocity is an integer in the range [-$PaddleVel, $PaddleVel] and is given in
 *          pixels per frame.
 *
 *      Ball (ID INTEGER, X INTEGER, Y INTEGER, XV INTEGER, YV INTEGER)
 *          Contains one row per ball currently in play. ID is a unique identifier per ball.
 *          The ball has its midpoint at (X, Y) and has a radius of $BallRadius pixels. The
 *          ball's velocity, (XV, YV), is given in pixels per frame.
 *
 * - The AI is permitted to read but not modify the following variables:
 *      BottomBounceEnd: TIMESTAMP
 *          If NULL, the bottom of the arena is not solid. Otherwise, the time at which the
 *          bottom of the arena will no longer be solid.
 *
 *      BottomBounce: INTEGER
 *          If this variable is greater than 0, the bottom of the arena is currently solid.
 *
 *      BallsLost: INTEGER
 *          The number of balls that have fallen out of the arena.
 *
 *      Running: BOOLEAN
 *          TRUE if the game is running, FALSE if paused.
 *
 *      RestartInProgress: BOOLEAN
 *          TRUE iff AIInitialize is being invoked in response to a restart request,
 *          FALSE othewise.
 *
 * - The AI is permitted to use all module parameters.
 *      $PaddleWidth, $PaddleHeight, $BallRadius, $BrickRows, $PaddleVel, $BallYVel, $BrickWidth,
 *      $BrickHeight, $GreenBrickProb, $RedBrickProb, $BlueBrickProb
 *
 * - The following streams may be helpful for development and debugging:
 *      PutPixel
 *      DrawRectangle
 *      DrawFilledCircle
 *
 * - You may create any streams, windows, variables, submodules, etc as needed.
 *
 * A simple AI implementation is given below. Note that the AI is permitted to use multiple
 * queries, and the AI is not required to respond immediately; the response may be delayed
 * slightly (usually a few microseconds) if needed.
 */

-- Do not modify this query if you do not need any initialization.
INSERT INTO AIInitializeDone
SELECT *
FROM AIInitialize;

-- Sample AI
INSERT INTO AISetPaddleVelocity
SELECT
    IF ABS((B.X + (B.Y - P.Y) * (TO_FLOAT(B.XV) / B.YV)) - P.X) <= $PaddleWidth/2.0
    THEN 0
    -- As a first step, you might want to try improving the behavior of the following line of code.
    ELSE $PaddleVel * SIGN(B.X - P.X - $PaddleWidth/2)
    END
FROM AITrigger,
    Paddle AS P, Ball AS B,
    (SELECT B.ID AS ID
        FROM Paddle AS P, Ball AS B
        WHERE DISTANCE(P.X + $PaddleWidth/2, P.Y, B.X, B.Y) =
            (SELECT MIN(DISTANCE(P.X + $PaddleWidth/2, P.Y, B.X, B.Y))
                FROM Paddle AS P, Ball AS B)) AS BallToChase KEEP LAST
WHERE B.ID = BallToChase.ID;