My Frankenstein Monster

wonder

Expert
Licensed User
Longtime User
Once upon a night of insomnia last week, I went a little bit too far on the weird part of YouTube, got inspired and decided to create "artificial life" in B4J.

(See attached jar file)

After a few hours of coding, a set of artificial creatures had been created.
They hunt, mate and sleep, usually in this order.
They're kinda on a cannibalistic diet, because I didn't bother to add any other species.

I'm happy to provide the source code, but bear in mind that I didn't bother to comment much, so the logic I used isn't explained at all. Besides, there's a bunch of hard-coded random numbers thrown in. This keeps the population stable, at least for a few generations, until they all eat each-other. :D

Here's the code, provided as is, written by a madman who couldn't sleep:
B4X:
#Region  Project Attributes
    #MainFormWidth: 800
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form

    'Custom Types
        Type Position(x As Double, y As Double)
        Type Velocity(x As Double, y As Double, angle As Double, magnitude As Double)
        Type Physical(radius As Double, mass As Double, color As Paint, mouth As Double, mouthDir As Double)
        Type Biology(energy As Double, food As Double, sleep As Double, health As Double, male As Int, children As Int)
        Type Psychology(food As Double, exploration As Double)
        Type Entity(Position As Position, Target As Position, Velocity As Velocity, Biology As Biology, Physical As Physical, Psychology As Psychology, Status As String, ID As Int)

    'Constants and not so constants
        Dim MAX_NUMBER_OF_CREATURES = 1024          As Int
        Dim MAX_NUMBER_OF_CHILDREN  = Rnd(16, 32)   As Int
        Dim STARTING_POPULATION     = Rnd(32, 128)  As Int

    'Canvas
        Dim cvs As Canvas

    'Biological Entities      
        Dim Creatures(MAX_NUMBER_OF_CREATURES) As Entity
          
    'Timers
        Dim MainCycle As Timer
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.SetFormStyle("UNIFIED")
    MainForm.BackColor = fx.Colors.RGB(0, 64, 128)
    MainForm.Show

    cvs.Initialize("cvs")
    MainForm.RootPane.AddNode(cvs, 0, 0, MainForm.Width, MainForm.Height)

    GenerateCreatures

    MainCycle.Initialize("MainCycle", 16)
    MainCycle.Enabled = True
End Sub

Sub GenerateCreatures
    Dim id = 0 As Int
    For Each Creature As Entity In Creatures
        Dim biology    As Biology  
        Dim position   As Position
        Dim target     As Position
        Dim velocity   As Velocity
        Dim physical   As Physical
        Dim psychology As Psychology
        Dim color      As Paint
          
        color = fx.Colors.RGB(255, 255, 255)

        biology.health     = 1
        biology.energy     = 1
        biology.food       = Rnd(50, 80) / 100
        biology.sleep      = 0
        biology.male       = Rnd(0, 2)
        biology.children   = 0
  
        physical.mouth     = 0
        physical.mouthDir  = 0.04
        physical.radius    = 5
        physical.mass      = Rnd(10, 10 + physical.radius)  
        physical.color     = color

        position.x         = Rnd(0 + physical.radius, MainForm.Width  - physical.radius)
        position.y         = Rnd(0 + physical.radius, MainForm.Height - physical.radius)
  
        target.x           = position. x
        target.y           = position. y
  
        velocity.x         = 0
        velocity.y         = 0  
        velocity.angle     = Rnd(0, 360) - 180
        velocity.magnitude = 0
  
        'let's roll with this for now
        psychology.exploration = biology.food
        'actually, let's not even using it...
          
        Creature.Biology  = biology
        Creature.Position = position
        Creature.Target   = target
        Creature.Velocity = velocity
        Creature.Physical = physical
        Creature.Status   = "NORMAL"
        Creature.ID       = id
  
        If id >= STARTING_POPULATION Then biology.health = 0

        id = id + 1
    Next
End Sub

Sub GenerateCreature(newCreature As Entity, x As Double, y As Double) As Entity
        Dim biology    As Biology  
        Dim position   As Position
        Dim target     As Position
        Dim velocity   As Velocity
        Dim physical   As Physical
        Dim psychology As Psychology
        Dim color      As Paint
          
        color = fx.Colors.RGB(255, 255, 255)

        biology.health     = 1
        biology.energy     = 1
        biology.food       = 0.10
        biology.sleep      = 0
        biology.male       = Rnd(0, 2)
        biology.children   = 0
  
        physical.mouth     = 0
        physical.mouthDir  = 0.04
        physical.radius    = 3
        physical.mass      = Rnd(10, 10 + physical.radius)  
        physical.color     = color

        position.x         = x
        position.y         = y
  
        target.x           = position. x
        target.y           = position. y
  
        velocity.x         = 0
        velocity.y         = 0  
        velocity.angle     = Rnd(0, 360) - 180
        velocity.magnitude = 0
  
        'let's roll with this for now
        psychology.exploration = biology.food
          
        newCreature.Biology  = biology
        newCreature.Position = position
        newCreature.Target   = target
        newCreature.Velocity = velocity
        newCreature.Physical = physical
        newCreature.Status   = "NORMAL"
  
        Return newCreature
End Sub

Sub MainCycle_Tick
    cvs.ClearRect(0, 0, cvs.Width, cvs.Height)
    For Each Creature As Entity In Creatures

        If Creature.Biology.health > 0 Then

            'Initialization
            '-------------------------------------------------------------------------------------------
                Dim biology   = Creature.Biology  As Biology          
                Dim position  = Creature.Position As Position
                Dim target    = Creature.Target   As Position
                Dim velocity  = Creature.Velocity As Velocity
                Dim physical  = Creature.Physical As Physical
                          
                Dim healthIndicator As Paint
                Dim beingAlive = Rnd(1, 100) / 100000 As Double      
                Dim awereness = 50 As Double
            '-------------------------------------------------------------------------------------------


            'Biological Calculations
            '-------------------------------------------------------------------------------------------
                'Sleep
                    Dim sleepFactor As Double              
              
                    If (biology.energy < 0.25 Or biology.sleep > 0.9) And _
                    biology.food > 0.50 Then Creature.Status = "SLEEP"              
              
                    If (biology.sleep = 0 Or biology.food < 0.25) And _
                    biology.energy > 0.75 Then Creature.Status = "NORMAL"              
              
                    If Creature.Status = "SLEEP" Then
                        biology.sleep  = Max(0, biology.sleep  - beingAlive * 2)
                        biology.energy = Min(1, biology.energy + beingAlive * (biology.food * 0.5))
                        sleepFactor = 0.33
                    Else
                        biology.sleep = Min(1, biology.sleep + beingAlive * 0.5)
                        sleepFactor = 1
                    End If
          
                'Digestion
                    Dim foodFactor = 0.15 As Double
                    biology.food = Max(0, biology.food - beingAlive * foodFactor * sleepFactor)              
              
                'Energy
                    Dim energyFactor = 1 As Double
                    If biology.food = 0 Then biology.energy = Max(0, biology.energy - beingAlive * energyFactor * sleepFactor)
              
                'Health
                    biology.health = Min(1, biology.health + beingAlive * biology.food)
                    Dim healthFactor = 1.5 As Double
                    Dim sleepFactor  = 2 As Double
                    If biology.energy = 0 Then biology.health = Max(0, biology.health - beingAlive * healthFactor * biology.sleep * sleepFactor)
                    healthIndicator = fx.Colors.ARGB((1 - biology.health) * 255, 255,   0,   0)          
            '-------------------------------------------------------------------------------------------


            'Decision Making
            '-------------------------------------------------------------------------------------------  
                If Creature.Status <> "SLEEP" Then
                    'Search for food              
                        If Creature.Biology.food < 0.75 Then                      
                            physical.mouth = physical.mouth + physical.mouthDir
                            If physical.mouth >= 0.5 Or physical.mouth <= 0 Then physical.mouthDir = -physical.mouthDir                                                  
                            For Each OtherCreature As Entity In Creatures                          
                                If Creature.ID = OtherCreature.ID Or OtherCreature.Biology.health = 0 Then Continue                          
                                Dim otherBiology = OtherCreature.Biology As Biology                          
                                If InRadius(Creature.Position.x, Creature.Position.y, _
                                            OtherCreature.Position.x, OtherCreature.Position.y, _
                                            awereness, OtherCreature.Physical.radius) _
                                Then
                                    target.x = OtherCreature.Position.x
                                    target.y = OtherCreature.Position.y                              
                                    velocity.magnitude = Max(0.66, Creature.Biology.energy) * (Rnd(85, 175) / 100)
                                    If InRadius(Creature.Position.x, Creature.Position.y, _
                                                OtherCreature.Position.x, OtherCreature.Position.y, _
                                                Creature.Physical.radius, 0) _
                                    Then
                                        physical.radius = physical.radius + physical.radius * 0.25
                                        physical.mass   = physical.mass   + physical.mass   * 0.10
                                        biology.food        = 1
                                        otherBiology.health = 0
                                        Exit
                                    End If
                                    Exit
                                End If                  
                            Next
                        Else
                            physical.mouth = 0.2                      
                            For Each OtherCreature As Entity In Creatures                          
                                If Creature.ID = OtherCreature.ID Or OtherCreature.Biology.health = 0 Then Continue                          
                                Dim otherBiology = OtherCreature.Biology As Biology
                                If         biology.male <> otherBiology.male _
                                    And Creature.Physical.radius > 4.5 _
                                    And OtherCreature.Physical.radius > 4.5 _
                                    And biology.children < MAX_NUMBER_OF_CHILDREN _
                                    And otherBiology.children < MAX_NUMBER_OF_CHILDREN _
                                    And InRadius(Creature.Position.x, Creature.Position.y, _
                                            OtherCreature.Position.x, OtherCreature.Position.y, _
                                            awereness, OtherCreature.Physical.radius) _
                                Then
                                    target.x = OtherCreature.Position.x
                                    target.y = OtherCreature.Position.y                              
                                    velocity.magnitude = Max(0.66, Creature.Biology.energy) * (Rnd(85, 175) / 100)
                                    If InRadius(Creature.Position.x, Creature.Position.y, _
                                                OtherCreature.Position.x, OtherCreature.Position.y, _
                                                Creature.Physical.radius, 0) _
                                    Then                                  
                                        For Each unbornCreature As Entity In Creatures
                                            If unbornCreature.biology.health = 0 Then
                                                If  Rnd(0, 2) = 1 Then
                                                    unbornCreature = GenerateCreature(unbornCreature, Creature.Position.x, Creature.Position.y)
                                                    biology.children = biology.children + 1
                                                    otherBiology.children = otherBiology.children + 1
                                                End If
                                                Exit
                                            End If
                                        Next
                                        RndSeed(Rnd(0, 2147483647))
                                        target.x = ((Rnd(MainForm.Width * 0.5 + Creature.Physical.radius, MainForm.Width * 1.5 - Creature.Physical.radius) - MainForm.Width) + (Rnd(Creature.Physical.radius, MainForm.Width - Creature.Physical.radius))) / 2
                                        RndSeed(Rnd(0, 2147483647))
                                        target.y = ((Rnd(MainForm.Height * 0.5 + Creature.Physical.radius, MainForm.Height * 1.5 - Creature.Physical.radius) - MainForm.Height) + (Rnd(Creature.Physical.radius, MainForm.Width - Creature.Physical.radius))) / 2
                                        velocity.magnitude = Max(0.66, Creature.Biology.energy) * (Rnd(60, 100) / 100)
                                        Exit
                                    End If
                                    Exit
                                End If
                            Next                                              
                        End If
                  
                        If InRadius(position.x, position.y, target.x, target.y, Creature.Physical.radius, 0) Then
                            RndSeed(Rnd(0, 2147483647))
                            target.x = ((Rnd(MainForm.Width * 0.5 + Creature.Physical.radius, MainForm.Width * 1.5 - Creature.Physical.radius) - MainForm.Width) + (Rnd(Creature.Physical.radius, MainForm.Width - Creature.Physical.radius))) / 2
                            RndSeed(Rnd(0, 2147483647))
                            target.y = ((Rnd(MainForm.Height * 0.5 + Creature.Physical.radius, MainForm.Height * 1.5 - Creature.Physical.radius) - MainForm.Height) + (Rnd(Creature.Physical.radius, MainForm.Width - Creature.Physical.radius))) / 2
                            velocity.magnitude = Max(0.66, Creature.Biology.energy) * (Rnd(60, 100) / 100)
                        End If                  
                  
                        Dim energyFactor = Creature.Physical.mass * 0.02 As Double
                        biology.energy = Max(0, biology.energy - beingAlive * energyFactor)                  
                Else
                    velocity.magnitude = velocity.magnitude * 0.9
                End If
              
            'Move
                Dim targetAngle = ATan2D(target.y - position.y, target.x - position.x) As Double
                Dim deltaAngle = Abs(velocity.angle - targetAngle) As Double              
                If deltaAngle < 180 Then
                    Dim turningDegrees = 4 * deltaAngle / 180 As Double
                    If targetAngle = velocity.angle Then
                        velocity.angle = velocity.angle
                    else if targetAngle < velocity.angle Then
                        velocity.angle = velocity.angle - turningDegrees
                    else if targetAngle > velocity.angle Then
                        velocity.angle = velocity.angle + turningDegrees
                    End If
                Else
                    Dim turningDegrees = 4 * (deltaAngle - 180) / 180 As Double
                    If targetAngle = velocity.angle Then
                        velocity.angle = velocity.angle
                    else if targetAngle < velocity.angle Then
                        velocity.angle = velocity.angle + turningDegrees
                    else if targetAngle > velocity.angle Then
                        velocity.angle = velocity.angle - turningDegrees
                    End If                  
                End If
          
                If velocity.angle >=  360 Then velocity.angle = velocity.angle - 360
                If velocity.angle <= -360 Then velocity.angle = velocity.angle + 360                                              
          
                velocity.x     = CosD(velocity.angle) * velocity.magnitude
                velocity.y     = SinD(velocity.angle) * velocity.magnitude
                position.x     = position.x + velocity.x
                position.y     = position.y + velocity.y
          
                If position.x < 0 Then position.x = position.x + cvs.Width
                If position.x > cvs.Width Then position.x = position.x - cvs.Width
                If position.y < 0 Then position.y = position.y + cvs.Height
                If position.y > cvs.Height Then position.y = position.y - cvs.Height
                          
            '-------------------------------------------------------------------------------------------
      
      
            'Tail B
                cvs.DrawCircle(Creature.Position.x - CosD(Creature.Velocity.angle) * Creature.Physical.radius * 1.5, _
                               Creature.Position.y - SinD(Creature.Velocity.angle) * Creature.Physical.radius * 1.5, _
                               Creature.Physical.radius * 0.75, Creature.Physical.color, True, 0)
                         
                cvs.DrawCircle(Creature.Position.x - CosD(Creature.Velocity.angle) * Creature.Physical.radius * 1.5, _
                               Creature.Position.y - SinD(Creature.Velocity.angle) * Creature.Physical.radius * 1.5, _
                               Creature.Physical.radius * 0.75, healthIndicator, True, 0)                     
                     
            'Tail A
                cvs.DrawCircle(Creature.Position.x - CosD(Creature.Velocity.angle) * Creature.Physical.radius * 2.5, _
                               Creature.Position.y - SinD(Creature.Velocity.angle) * Creature.Physical.radius * 2.5, _
                               Creature.Physical.radius * 0.5, Creature.Physical.color, True, 0)                     

                cvs.DrawCircle(Creature.Position.x - CosD(Creature.Velocity.angle) * Creature.Physical.radius * 2.5, _
                               Creature.Position.y - SinD(Creature.Velocity.angle) * Creature.Physical.radius * 2.5, _
                               Creature.Physical.radius * 0.5, healthIndicator, True, 0)                     

            'Head                           
                cvs.DrawCircle(Creature.Position.x, Creature.Position.y, Creature.Physical.radius, Creature.Physical.color, True, 0)
                cvs.DrawCircle(Creature.Position.x, Creature.Position.y, Creature.Physical.radius, healthIndicator, True, 0)          
      
            'Eyes
                If Creature.Status = "SLEEP" Then
                    cvs.DrawLine(Creature.Position.x + Creature.Physical.radius * 0.25, _
                                 Creature.Position.y - Creature.Physical.radius * 0.45, _
                                 Creature.Position.x + Creature.Physical.radius * 0.50, _
                                 Creature.Position.y - Creature.Physical.radius * 0.45, _
                                 fx.Colors.Black, 1)                           

                    cvs.DrawLine(Creature.Position.x - Creature.Physical.radius * 0.25, _
                                 Creature.Position.y - Creature.Physical.radius * 0.45, _
                                 Creature.Position.x - Creature.Physical.radius * 0.50, _
                                 Creature.Position.y - Creature.Physical.radius * 0.45, _
                                 fx.Colors.Black, 1)
                Else
                    If Creature.Biology.male = 1 Then
                        cvs.DrawCircle(Creature.Position.x + Creature.Physical.radius * 0.35, Creature.Position.y - Creature.Physical.radius * 0.45, Creature.Physical.radius * 0.25, fx.Colors.Blue, True, 0)
                        cvs.DrawCircle(Creature.Position.x - Creature.Physical.radius * 0.35, Creature.Position.y - Creature.Physical.radius * 0.45, Creature.Physical.radius * 0.25, fx.Colors.Blue, True, 0)
                    Else
                        cvs.DrawCircle(Creature.Position.x + Creature.Physical.radius * 0.35, Creature.Position.y - Creature.Physical.radius * 0.45, Creature.Physical.radius * 0.25, fx.Colors.Magenta, True, 0)
                        cvs.DrawCircle(Creature.Position.x - Creature.Physical.radius * 0.35, Creature.Position.y - Creature.Physical.radius * 0.45, Creature.Physical.radius * 0.25, fx.Colors.Magenta, True, 0)
                    End If
                End If

            'Mouth
                cvs.DrawCircle(Creature.Position.x, Creature.Position.y + Creature.Physical.radius * 0.55, Creature.Physical.radius * Creature.Physical.mouth, fx.Colors.Black, True, 0)
      
      
        End If
    Next
End Sub

Sub InRadius(x1 As Double, y1 As Double, x2 As Double, y2 As Double, r1 As Double, r2 As Double) As Boolean
    Dim dX = x1 - x2 As Double
    Dim dY = y1 - y2 As Double
    Dim sqRadialSum = (r1 + r2) * (r1 + r2) As Double
    Return ((dX * dX) + (dY * dY) <= sqRadialSum)
End Sub

Again, please forgive me the shameless copy-pasting, the hard-coding and the lack of logic and structure. This is not a serious project.
 

Attachments

  • ai.jar
    301 KB · Views: 155

JordiCP

Expert
Licensed User
Longtime User
The idea is promising!

Next insomnia night you could consider evolution: from time to time, with a random factor, when two creatures procreate, some of the biological factors of their descendant(s) changes a bit. It will probably change its behaviour and their chances to survive/procreate. Perhaps in some generations you will have the perfect predator on your PC ;)
 

ilan

Expert
Licensed User
Longtime User
really great, i really like your sources @wonder
i am sure you will surprise us with many cool sources in 2016
looking forward to see them :)
 
Top