Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Telling Gemini to be creative
#1
Gave gemini this training program:

Code:
' An AI training program in naalaa 7
' ----------------------------------
' Pass this program to Gemini to help it understand and use the language.

' Constants, visible in entire program but can't change values.
constant DIR_NONE = 0, DIR_LEFT = 1, DIR_RIGHT = 2, DIR_UP = 3, DIR_DOWN = 4

' Visible (global) variables, can be accessed in functions.
visible vObjects

' Use 'set window title, w, h, fullscreen, scale' to create a 320x240 pixels large window, visually
' upscaled by 2 for crispy pixels.
set window "Trainer", 320, 240, false, 2
' Turn off automatic redraw, meaning that we will have to call 'redraw' to manually copy the game's
' back buffer to the window.
set redraw off

' Create 100 moving objects and put them in vObjects.
vObjects = []
for i = 1 to 100
    if rnd(2) = 0
        obj = MovingRectangle(rnd(320), rnd(240), 16 + rnd(16), 16 + rnd(16))
    else
        obj = MovingEllipse(rnd(320), rnd(240), 16 + rnd(16), 16 + rnd(16))
    endif
    vObjects[sizeof(vObjects)] = obj
    obj.SetDir(rnd(1, 4))
    obj.SetSpeed(0.25 + rnd()*4.75)
next

' Control a crosshair.
crossHairX = 160
crossHairY = 120

' Define a polygon in the form [x0, y0, x1, y1 .. xn, yn], with its origin at (0, 0) that we can
' draw anywhere on the screen.
starPolygon = [0, -32, 8, -8, 32, 0, 8, 8, 0, 32, -8, 8, -32, 0, -8, -8]
starAngle = 0 ' The rotation angle of our star polygon.
starAngleSpeed = 4 ' The speed of rotation.

' Loop until user presses the escape key.
while not keydown(KEY_ESCAPE)
    ' Update objects.
    if sizeof(vObjects)
        for i = sizeof(vObjects) - 1 to 0
            if not vObjects[i].Update()
                free key vObjects, i
            endif
        next
    endif
   
    ' Move crosshair.
    if keydown(KEY_LEFT) crossHairX = max(crossHairX - 2, 0)
    if keydown(KEY_RIGHT) crossHairX = min(crossHairX + 2, 319)
    if keydown(KEY_UP)  crossHairY = max(crossHairY - 2, 0)
    if keydown(KEY_DOWN)  crossHairY = min(crossHairY + 2, 240)
   
    ' Change rotation direction of the star with left click. Setting the second parameter for
    ' 'mousebutton' to true means that the function won't return true until the the mouse button has
    ' been released and pressed again.
    if mousebutton(0, true) starAngleSpeed = -starAngleSpeed
   
    ' Update star angle. The modulo operator (%) performs mathematical modulo, meaning that it
    ' handles negative numbers correctly.
    starAngle = (starAngle + starAngleSpeed)%360
   
    ' Clear screen black.
    set color 0, 0, 0
    cls
   
    ' 'foreach' doesn't guarantee any specific order, so the objects will seem to change z order
    ' when the vObjects shrinks. I'm using 'foreach' just to show how it works :)
    foreach o in vObjects
        o.Draw()
    next
   
    ' Draw a transparent blue gradient at the top.
    for y = 0 to 63
        set color 32, 64, 255, 255*(63 - y)/64
        draw line 0, y, 319, y
    next
   
    ' Draw red crosshair.
    set color 255, 0, 0
    draw line crossHairX, crossHairY - 8, crossHairX, crossHairY + 8
    draw line crossHairX - 8, crossHairY, crossHairX + 8, crossHairY
   
    ' Draw transparent star polygon at mouse cursor position using 'draw poly xform points, x, y,
    ' scaleX, scaleY, angle, pivotX, pivotY, filled'.
    set color 255, 255, 255, 128
    mx = mousex();  my = mousey()
    draw poly xform starPolygon, mx, my, 1, 1, rad(starAngle), 0, 0, true
   
    ' 'draw poly points, filled' draws the polygon defined by 'points' without any
    ' transformations. So only the bottom left quarter of the star will be visible, at the top right
    ' corner of the window, when we use this command.
    draw poly starPolygon, true
   
    ' Write some info at the bottom left corner using the default fixed size font (all characters
    ' are 8x16 pixels large).
    set color 255, 255, 255
    set caret 0, 208
    ' 'wln txt' writes a text string and jumps to a new line.
    wln "Mouse position: " + mx + ", " + my
    ' 'write txt' writes a string without jumping to a new line. All numbers are floating points,
    ' use 'floor' or 'int' to remove the fractional part.
    write "Star angle: " + floor(starAngle)
    ' Copy backbuffer to window and use 'fwait' to cap fps at 60.
    redraw
    fwait 60
wend

' Create and return a rectangle that can move.
function MovingRectangle(centerX, centerY, w, h)
    ' Create object and set properties.
    mr = [dir: DIR_NONE,
            x: centerX - w/2, y: centerY - h/2,
            w: w, h: h,
            dx: 0, dy: 0,
            speed: 1, bouncesLeft: 5,
            r: rnd(256), g: rnd(256), b: rnd(255)]
           
    ' Add some functions to object.
   
    mr.SetDir = function(dir)
        this.dir = dir
        select dir
            case DIR_LEFT
                this.dx = -1;  this.dy = 0
            case DIR_RIGHT
                this.dx = 1;  this.dy = 0
            case DIR_UP
                this.dx = 0;  this.dy = -1
            case DIR_DOWN
                this.dx = 0;  this.dy = 1
            default
                this.dx = 0;  this.dy = 0
        endsel
    endfunc
   
    mr.Stop = function()
        this.SetDir(DIR_NONE)
    endfunc
   
    mr.GetDir = function()
        return this.dir
    endfunc
   
    mr.SetSpeed = function(spd)
        this.spd = spd
    endfunc
   
    mr.GetSpeed = function()
        return this.spd
    endfunc

    mr.Update = function()
        ' Move.
        this.x = this.x + this.dx
        this.y = this.y + this.dy
        ' Turn on screen edges.
        if this.dir = DIR_LEFT and this.x < 0
            this.SetDir(DIR_RIGHT)
            this.bouncesLeft = this.bouncesLeft - 1
        elseif this.dir = DIR_RIGHT and this.x > 320
            this.SetDir(DIR_LEFT)
            this.bouncesLeft = this.bouncesLeft - 1
        endif
        if this.dir = DIR_UP and this.y < 0
            this.SetDir(DIR_DOWN)
            this.bouncesLeft = this.bouncesLeft - 1
        elseif this.dir = DIR_DOWN and this.y > 240
            this.SetDir(DIR_UP)
            this.bouncesLeft = this.bouncesLeft - 1
        endif
        return this.bouncesLeft > 0
    endfunc
   
    mr.Draw = function()
        set color this.r, this.g, this.b
        ' Use 'draw rect x, y, w, h, filled' to draw a filled rectangle.
        draw rect this.x, this.y, this.w, this.h, true
    endfunc
   
    return mr
endfunc

' Create and return a moving ellipse.
function MovingEllipse(x, y, w, h)
    ' Base on moving rectangle.
    me = MovingRectangle(x, y, w, h)
   
    ' Replace the Draw function.
    me.Draw = function()
        set color this.r, this.g, this.b
        ' Use 'draw ellipse centerX, centerY, radiusX, radiusY, filled' to draw a filled ellipse.
        draw ellipse this.x + this.w/2, this.y + this.h/2, this.w/2, this.h/2, true
    endfunc
   
    return me
endfunc

' Return true if the bounding rectangle of objects a and b overlaps. Tables/arrays are always passed
' by reference.
function Overlaps(a, b)
    return a.x + a.w > b.x and a.x < b.x + b.w and a.y + a.h > b.y and a.y < b.y + b.h
endfunc

Then I told it to be "creative" and create two games. Here's the first one, where it re-used very much from the training program, still quite fun:

Code:
' Neon Star Eater - Commented Educational Version
' --------------------------------------------------

' 'constant' defines values that cannot change while the program runs.
' These are visible everywhere automatically.
constant DIR_NONE = 0, DIR_LEFT = 1, DIR_RIGHT = 2, DIR_UP = 3, DIR_DOWN = 4
constant STATE_PLAYING = 0, STATE_GAMEOVER = 1

' 'visible' declares global variables. Without this, variables created in
' the main loop or functions are local to that specific scope.
' Using a 'v' prefix is a great convention to easily identify them!
visible vEnemies
visible vFood
visible vScore
visible vGameState
visible vStarPoly
visible vStarAngle
visible vStarAngleSpeed

' Create a window: title, width, height, fullscreen (false), scale (2x)
set window "Neon Star Eater", 320, 240, false, 2
' Turn off automatic redraw so we can draw everything in the background
' and flip it to the screen all at once (double buffering) to prevent flickering.
set redraw off

' Initialize the player's shape as a list of x, y coordinates forming a polygon.
vStarPoly = [0, -12, 4, -4, 12, 0, 4, 4, 0, 12, -4, 4, -12, 0, -4, -4]
vStarAngle = 0
vStarAngleSpeed = 4

' Call our setup function to set the initial game state
ResetGame()

' --- MAIN GAME LOOP ---
' This loop runs continuously until the user presses the Escape key.
while not keydown(KEY_ESCAPE)
    ' Clear the screen to black at the start of every frame
    set color 0, 0, 0
    cls
   
    ' Handle logic and drawing based on the current game state
    if vGameState = STATE_PLAYING
        UpdatePlaying()
        DrawPlaying()
    elseif vGameState = STATE_GAMEOVER
        UpdateGameOver()
        DrawGameOver()
    endif
   
    ' Copy our background drawings to the actual window
    redraw
    ' Cap the frame rate at 60 Frames Per Second
    fwait 60
wend


' --- GAME STATE FUNCTIONS ---

function ResetGame()
    vScore = 0
    vGameState = STATE_PLAYING
    ' Empty tables (arrays) to hold our game objects
    vEnemies = []
    vFood = []
   
    ' Spawn initial food using a 'for' loop
    for i = 1 to 3
        SpawnFood()
    next
endfunc

function SpawnEnemy()
    ' Get current mouse position to know where the player is
    mx = mousex(); my = mousey()
    safe = false
    ex = 0
    ey = 0
   
    ' Keep picking random coordinates until we find one far enough from the player
    while not safe
        ex = rnd(320)
        ey = rnd(240)
       
        ' Calculate the squared distance (a^2 + b^2 = c^2).
        ' We skip the square root to save processing power!
        distSq = (ex - mx)*(ex - mx) + (ey - my)*(ey - my)
        ' 10000 means the enemy must spawn at least 100 pixels away (100^2 = 10000)
        if distSq > 10000
            safe = true
        endif
    wend

    ' Create a new enemy object and set its properties
    obj = MovingRectangle(ex, ey, 12 + rnd(12), 12 + rnd(12))
    obj.SetDir(rnd(1, 4))
    obj.SetSpeed(1.0 + rnd()*2.0)
    obj.r = 255; obj.g = 32; obj.b = 32 ' RGB color: Bright Red
   
    ' Add the new object to the end of the vEnemies array.
    ' sizeof() gets the current number of items in the array.
    vEnemies[sizeof(vEnemies)] = obj
endfunc

function SpawnFood()
    obj = MovingEllipse(rnd(320), rnd(240), 10, 10)
    obj.SetDir(rnd(1, 4))
    obj.SetSpeed(0.5 + rnd()*1.5)
    obj.r = 32; obj.g = 255; obj.b = 32 ' RGB color: Bright Green
    vFood[sizeof(vFood)] = obj
endfunc

function UpdatePlaying()
    mx = mousex(); my = mousey()
    ' Rotate the star. The modulo (%) operator keeps the angle between 0 and 359
    vStarAngle = (vStarAngle + vStarAngleSpeed)%360
   
    ' Create a temporary table representing the player's bounding box for collisions
    playerBox = [x: mx - 8, y: my - 8, w: 16, h: 16]
   
    ' --- ENEMY UPDATE ---
    if sizeof(vEnemies)
        ' Loop backwards! When removing items from an array inside a loop,
        ' looping backwards prevents index shifting errors.
        for i = sizeof(vEnemies) - 1 to 0
            vEnemies[i].Update()
            if Overlaps(playerBox, vEnemies[i])
                vGameState = STATE_GAMEOVER
            endif
        next
    endif
   
    ' --- FOOD UPDATE ---
    if sizeof(vFood)
        for i = sizeof(vFood) - 1 to 0
            vFood[i].Update()
            if Overlaps(playerBox, vFood[i])
                vScore = vScore + 10
                ' 'free key' removes an item from an array at the specified index
                free key vFood, i
                SpawnFood()
               
                ' The modulo (%) operator checks if the score is perfectly divisible by 50
                if vScore % 50 = 0
                    SpawnEnemy()
                endif
            endif
        next
    endif
endfunc

function DrawPlaying()
    ' 'foreach' is a clean way to loop through an array when you don't need the index
    foreach e in vEnemies
        e.Draw()
    next
   
    foreach f in vFood
        f.Draw()
    next
   
    ' Set color to Yellow with 200 alpha (slight transparency)
    set color 255, 255, 0, 200
    mx = mousex(); my = mousey()
   
    ' Draw the player polygon.
    ' xform allows scaling (1, 1) and rotation. 'rad()' converts degrees to radians.
    ' The last parameter (true) means the polygon will be filled.
    draw poly xform vStarPoly, mx, my, 1, 1, rad(vStarAngle), 0, 0, true
   
    ' Draw UI Score text at coordinates x:4, y:4
    set color 255, 255, 255
    set caret 4, 4
    write "SCORE: " + vScore
endfunc

function UpdateGameOver()
    ' Wait for the player to press SPACE to restart
    if keydown(KEY_SPACE)
        ResetGame()
    endif
endfunc

function DrawGameOver()
    DrawPlaying() ' Keep the game visible in the background
   
    ' Draw a dark, translucent rectangle over the whole screen (0,0 to 320,240)
    set color 0, 0, 0, 180
    draw rect 0, 0, 320, 240, true
   
    ' Draw Game Over text
    set color 255, 50, 50
    set caret 120, 100
    write "GAME OVER"
   
    set color 255, 255, 255
    set caret 95, 130
    write "Final Score: " + vScore
   
    set color 200, 200, 200
    set caret 70, 160
    write "Press SPACE to Restart"
endfunc


' --- CORE OBJECT CLASSES ---

' This function acts like a "Class Constructor" in other languages.
' It creates a table with properties and attaches functions to it.
function MovingRectangle(centerX, centerY, w, h)
    ' Create the base table (object) with its properties
    mr = [dir: DIR_NONE,
          x: centerX - w/2, y: centerY - h/2,
          w: w, h: h, dx: 0, dy: 0,
          speed: 1,
          r: 255, g: 255, b: 255]
         
    ' Attach a method to the object.
    ' 'this' refers to the specific table that owns the function.
    mr.SetDir = function(dir)
        this.dir = dir
        ' 'select/case' is a cleaner way to write multiple 'if/elseif' statements
        select dir
            case DIR_LEFT
                this.dx = -this.speed; this.dy = 0
            case DIR_RIGHT
                this.dx = this.speed; this.dy = 0
            case DIR_UP
                this.dx = 0; this.dy = -this.speed
            case DIR_DOWN
                this.dx = 0; this.dy = this.speed
            default
                this.dx = 0; this.dy = 0
        endsel
    endfunc
   
    mr.SetSpeed = function(spd)
        this.speed = spd
        this.SetDir(this.dir) ' Update dx/dy based on the new speed
    endfunc

    mr.Update = function()
        ' Move the object
        this.x = this.x + this.dx
        this.y = this.y + this.dy
       
        ' Bounce off the screen edges
        if this.dir = DIR_LEFT and this.x < 0
            this.SetDir(DIR_RIGHT)
        elseif this.dir = DIR_RIGHT and this.x > 320 - this.w
            this.SetDir(DIR_LEFT)
        endif
        if this.dir = DIR_UP and this.y < 0
            this.SetDir(DIR_DOWN)
        elseif this.dir = DIR_DOWN and this.y > 240 - this.h
            this.SetDir(DIR_UP)
        endif
        return true
    endfunc
   
    mr.Draw = function()
        set color this.r, this.g, this.b
        draw rect this.x, this.y, this.w, this.h, true
    endfunc
   
    ' Return the fully constructed object
    return mr
endfunc

' Inheritance! This creates a MovingEllipse by first creating a MovingRectangle,
' and then overriding its Draw function.
function MovingEllipse(x, y, w, h)
    me = MovingRectangle(x, y, w, h)
   
    ' Override the default rectangle drawing method
    me.Draw = function()
        set color this.r, this.g, this.b
        ' Ellipses are drawn from their center point, so we add half the width/height
        draw ellipse this.x + this.w/2, this.y + this.h/2, this.w/2, this.h/2, true
    endfunc
   
    return me
endfunc

' Axis-Aligned Bounding Box (AABB) collision detection.
' Checks if the right side of A is past the left side of B, etc.
function Overlaps(a, b)
    return a.x + a.w > b.x and a.x < b.x + b.w and a.y + a.h > b.y and a.y < b.y + b.h
endfunc

, and here's the second one, after I told gemini it needn't re-use that much of the code:

Code:
' Neon Herder - An Anomaly Containment Game
' ----------------------------------------------------
' Goal: Herd all the yellow wandering anomalies into the center blue core using the mouse.
' Mechanics: The mouse emits a repulsion field. Anomalies flee when the mouse gets close.

set window "Neon Herder", 320, 240, false, 2
set redraw off

' Global variables
visible vAnomalies
visible anomaliesLeft

vAnomalies = []
anomaliesLeft = 50

' Generate 50 wandering anomalies
for i = 1 to 50
    ' Create anomaly object
    anomaly = [x: rnd(320), y: rnd(240), dx: 0.0, dy: 0.0, captured: false]
   
    ' Object method to handle physics and AI
    anomaly.Update = function(mx, my)
        if this.captured
            ' Gently settle into the core once captured
            this.x = this.x + (160 - this.x) * 0.05
            this.y = this.y + (120 - this.y) * 0.05
            return
        endif

        ' Brownian motion (random wandering)
        this.dx = this.dx + (rnd() * 2 - 1) * 0.5
        this.dy = this.dy + (rnd() * 2 - 1) * 0.5

        ' Apply friction to prevent infinite speed
        this.dx = this.dx * 0.9
        this.dy = this.dy * 0.9

        ' Repulsion from the mouse cursor
        ' We use distance squared to avoid needing a heavy square root calculation
        distSq = (this.x - mx)*(this.x - mx) + (this.y - my)*(this.y - my)
       
        if distSq < 2500 ' 50 pixel radius
            ' Flee from the mouse!
            this.dx = this.dx + (this.x - mx) * 0.03
            this.dy = this.dy + (this.y - my) * 0.03
        endif

        ' Apply velocity
        this.x = this.x + this.dx
        this.y = this.y + this.dy

        ' Wall collisions (bounce)
        if this.x < 0
            this.x = 0; this.dx = -this.dx
        elseif this.x > 319
            this.x = 319; this.dx = -this.dx
        endif
       
        if this.y < 0
            this.y = 0; this.dy = -this.dy
        elseif this.y > 239
            this.y = 239; this.dy = -this.dy
        endif

        ' Check if anomaly has been corralled into the core (radius 20)
        distToCore = (this.x - 160)*(this.x - 160) + (this.y - 120)*(this.y - 120)
        if distToCore < 400
            this.captured = true
            anomaliesLeft = anomaliesLeft - 1
        endif
    endfunc
   
    ' Object method to draw the anomaly
    anomaly.Draw = function()
        if this.captured
            set color 0, 255, 255 ' Cyan when captured
        else
            set color 255, 255, 0 ' Yellow when wild
        endif
        ' Draw as a crisp 3x3 pixel
        draw rect this.x - 1, this.y - 1, 3, 3, true
    endfunc

    ' Append to our global array
    vAnomalies[sizeof(vAnomalies)] = anomaly
next

' Main Game Loop
while not keydown(KEY_ESCAPE)
    mx = mousex()
    my = mousey()

    ' Clear screen to a dark, moody blue-black
    set color 10, 10, 20
    cls

    ' Draw the containment core in the center
    set color 0, 100, 255, 100
    draw ellipse 160, 120, 20, 20, true
    set color 0, 200, 255
    draw ellipse 160, 120, 20, 20, false

    ' Draw the player's repulsion field aura
    set color 255, 50, 50, 30
    draw ellipse mx, my, 50, 50, true
    set color 255, 50, 50, 128
    draw ellipse mx, my, 50, 50, false

    ' Update and draw all anomalies
    foreach a in vAnomalies
        a.Update(mx, my)
        a.Draw()
    next

    ' UI / HUD
    set color 255, 255, 255
    set caret 4, 4
    if anomaliesLeft > 0
        write "Uncontained: " + anomaliesLeft
    else
        set color 0, 255, 0
        write "CONTAINMENT COMPLETE!"
    endif

    ' Render and cap at 60 FPS
    redraw
    fwait 60
wend
Reply
#2
Welcome to the second most primitive IDE thinkable!
Compiled with n7 version 22.07.08b
Saved "D:\ARCHIVE\N7_220708\N7\gemini.n7"
Saved "D:\ARCHIVE\N7_220708\N7\gemini.n7"
Compiling "D:\ARCHIVE\N7_220708\N7\gemini.n7"
n7: gemini.n7:92: error: Undeclared identifier 'xform'

ok i wll try with latest release

Yikes ...now work and not Bad..not bad
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)