Rem Project: PriDe
Rem Created: 3/26/2006 10:27:53 AM
 
Rem ***** Main Source File *****
 
 
`Initialize Neural Net
Rem Project: ANNTM ("Auntie Em"): Artificial Neural Network Through Memblocks
Rem Created: 12/30/2005 7:15:12 PM
 
#Constant G_Curve 0
#Constant G_Weight 1
#Constant G_Threshold 2
 
 
`Each "Cluster" memblock is a group of 32 neurons. One cluster can be attached to a second cluster.
`That second cluster can be attached to a third cluster, and so on.
`Each neuron in a cluster can be "linked" to any or all of the 32 neurons in the attached cluster.
 
`End Clusters: Clusters do not have to be assigned a target cluster. If this is the case, the neurons in the cluster will never fire.
`Neurons that do not fire, do not lose their charge (and will eventually max out). It is advisable to read an End Cluster periodically
`and do something with the charges in the neurons, then set all the neurons in that cluster to 0 (see Clear_Charges)
 
`Neurons have 5 parts: Charge, Threshold, Curve, Weight, and Links.
`  Charge: This is how much "electricity" the neuron is holding, represented as a value between 0 and 15
`  Threshold: This is at what point the neuron will release it's charge. If the Charge value => Threshold, then the neuron "fires".
`  Curve: This is used to scale the input values coming into a neuron.
`  Weight: This is the amount of "charge" a neuron releases when it fires.
`  Links: 4 bytes long. Each bit represents a link to a relative neuron in a linked cluster of neurons. The 3rd bit would represent the 3rd neuron.
 
 
Global AI_Score
Global AI_Average
Global Epoch_Timer as DWord
Global Epoch_Counter as DWord
`Epoch_Length is how many frames make a single Epoch
Global Epoch_Length = 4
`Pain is an offset from 0 to 14 which adjusts each neuron's charge by -Pain
`Basically: this mathematically reflects negative "pain" values without storing negative values (which requires an extra bit)
`Remember that this value lowers the maximum output as well.
Global Pain = 7
 
 
`Set up initial clusters (read about clusters above).
`Some arrays are based on how many cluster there are, so it is important to initialize all the clusters first.
`Also, clusters must be sequential and start with Memblock 1. The Make_Free_Cluster function handles this automatically.
`If you need to create other memblocks, you should start those at a much higher value (like Memblock 100).
Global Mem1
Global Mem2
Mem1=Make_Free_Cluster
Mem2=Make_Free_Cluster
 
Type Genes
   Curve as Integer
   Weight as Integer
   Threshold as Integer
Endtype
`Gene is the learning "genetic code". Typically, the "genetic code" would record and consider the population
`of all AI of the same type.
`In this case though, we only have one AI, and that type of evolution would take a really long time.
`So we are going to take the population of possibilities and use those instead. Since a neuron can hold a value of
`0 to 15, we will track how well each setting does and keep track over many Epochs.
`We are tracking: # of Clusters, 32 neurons (0-31), and 16 possible settings (0-15).
`So our Dim is:
`Dim Gene( Clusters ,31, 15) as Genes
`The BestGenes array records which single Gene setting (0-15) is the best.
Dim BestGenes( Clusters ,31 ) as Genes
`Note: A future update would be to convert this to a memblock as well.
 
 
`LinkCrawler is a genetic array that handles the evolution of the neuron links, one at a time per cluster.
`The crawler stays with each neuron for specific number of epochs, and then moves on to the next neuron.
Dim LinkCrawler( Clusters , 33 ) as Integer
 
 
`=============Prime the Neural Net AI=================
 
If File Exist("PrideNet1.ann")
   Open To Read 1,"PrideNet1.ann"
   Read Memblock 1,Mem1
   Close File 1
   Open To Read 1,"PrideNet2.ann"
   Read Memblock 1,Mem2
   Close File 1
Else
   ` Create and Attach two Neuron Clusters
   Assign_Cluster(Mem1,Mem2)
 
   Initialize_Links()
   For i =0 to 7
      For j = 0 to 5
         Link_Neuron(Mem1,i,j)
      Next j
   Next i
   For i =8 to 11
      Link_Neuron(Mem1,i,0)
      Link_Neuron(Mem1,i,1)
   Next i
 
   Epoch_Timer=Epoch_Length+1
   Epoch()
 
   `Increase all the 1st cluster's neuron charges by 2.
   Pump_Charges(Mem1)
 
Endif
 
`=====================================================GAME=====================================================
 
 
`Gambling game called PriDe
 
 
Game:
 
 
Game_SetUp:
Set Display Mode 800,600,32
CLS
Print "Welcome to PRIDE"
Print
Print "Pride is a thinking gambling game."
Print "The object is to outwit your opponent on several levels."
Print
Print "First, is the Player Selection: Choose either the"
Print "Alpha Player (Red), or the Numeric Player (White)"
Print "(Note: there is no advantage to either player)"
Print "[1] Alpha (Red)"
Print "[2] Numeric (White)"
Global Player
Global Player$
Player$="Numeric (White)"
Do
   Input "Select: ",Player
   If Player = 1
      Player$="Alpha (Red)"
      Exit
   Endif
   If Player = 2 Then exit
Loop
 
CLS
Print
Print "Next, you will see the game board."
Print "Like this:"
Print "   1  2"
Print "A [ ][ ]"
Print "B [ ][ ]"
Print
Print "The Game:"
Print "Dealing: Each section will have a red or white number from 1 to 5 in it."
Print
Print "Betting: Each player reviews the board and bets to Win or Lose."
Print "         You can bet 1 minimum to 5 maximum. This will not be the whole bet amount."
Print "         Bets are kept secret until the Payout phase."
Print
Print "Select Row/Column: The Alpha Player selects either row A or B."
Print "                   The Numeric Player selects either column 1 or 2."
Print
Print "Playing: Both player's reveal their selections simultaniously."
Print "         The color/number selected is value in the row and column selected by"
Print "         the players."
Print
Print "Scoring: If the selected value is Red, the Alpha player 'wins'. Numeric 'loses'."
Print "         If the selected value is White, the Numeric player 'wins'. Alpha 'loses'."
Print "         Each initial bet amount is multiplied by the selected value and the results"
Print "         are added together. This amount is deducted from each player's funds and"
Print "         added to to the pot."
Print
Print "Payout: If no player bets correctly (to win or lose), the total amount remains in"
Print "        the 'pot'. If one player bet correctly, that player wins the total pot."
Print "        If both players bet correctly, the total amount remains in the 'pot'."
Print
Print "Press any key to continue"
Wait Key
Cls
Print "Strategies to consider:"
Print
Print "Your bet is 50% controlled by you and 50% controlled by your opponent. Consider your"
Print "bet carefully. If you think you have a good chance to win, you will probably want to"
Print "force the highest bet you can. Otherwise, you may want to limit the bet as much as"
Print "possible. The dilemma comes when it appears you have a 50% chance of winning."
Print
Print "You can try to trick your opponent. One option may look like a sure win, but it may"
Print "also have a lower bet multiplier. Consider the possibility of going against the sure"
Print "bet in order to get the higher payout. Of course, your opponent might consider this"
Print "as well."
Print
Print "If you have a 50-50 chance of winning a hand, consider the payout strategies. Which"
Print "choice you make will have the most potential and the least risk. Consider what your"
Print "opponent might think is a great strategy as well. And then throw in the possibility"
Print "that your opponent is taking what you are thinking into consideration as well."
Print
Print "Press any key to continue."
 
Wait Key
 
Dim board(3)
Global Pot
 
Global Funds1
Funds1=500
Global Funds2
Funds2=500
 
Global Bet1
Global BetType1
Global Bet2
Global BetType2
 
Do
   `Save Neural Net
   If File Exist("PrideNet1.ann")
      Delete File "PrideNet1.ann"
   Endif
   Open To Write 1,"PrideNet1.ann"
   Write Memblock 1,Mem1
   Close File 1
   If File Exist("PrideNet2.ann")
      Delete File "PrideNet2.ann"
   Endif
   Open To Write 1,"PrideNet2.ann"
   Write Memblock 1,Mem2
   Close File 1
   Epoch()
 
   `Deal phase
   Deal
 
 
   `Bet Phase
   Set_All_Charges(Mem2,0)
   Fire_Neurons(Mem1)
 
   b=Read_Charge(Mem2,0)+Read_Charge(Mem2,1)
   b=Sigmoidal(b-(b*.5),1)*4+1
   Bet2=b
   t1=Read_Charge(Mem2,2):t2=Read_Charge(Mem2,3)
   t=(t2>t1)+1
   BetType2=t
   Set Cursor 0,110
 
   Ink Rgb(200,200,255),0
   Do
      Input "Bet to [1]Win or [2]Lose? :",BetType1
      `BetType1=rnd(1)+1
      If BetType1=1 or BetType1=2 then Exit
   Loop
   Do
      Input "Amount to bet (1-5)? :",Bet1
      `Bet1=Rnd(4)+5
      If Bet1=>1 and Bet1<=5 then Exit
   Loop
 
   `Select Phase
   a1=Read_Charge(Mem2,4):a2=Read_Charge(Mem2,5)
   a=(a2>a1)+1
   If Player=1
      Do
         Input "Select Row ([1]Row A or [2]Row B): ",Row
         `Row=Rnd(1)+1
         If Row = 1 or Row=2 Then exit
      Loop
      Col=a
      ABet=Bet1:AType=BetType1
      NBet=Bet2:NType=BetType2
   Else
      Do
         Input "Select Column ([1]Col 1 or [2]Col 2): ",Col
         `Col=Rnd(1)+1
         If Col = 1 or Col=2 Then exit
      Loop
      Row=a
      NBet=Bet1:NType=BetType1
      ABet=Bet2:AType=BetType2
   Endif
 
   `Play Phase
   Print "Bets and selections are made. Press any key to continue."
   Wait Key
   Print
   Print "Alpha Player bet ";ABet;" to ";
   If AType=1 Then Print "Win." Else Print "Lose."
   Print "Alpha Player selected Row ";
   If Row=1 Then Print "A." Else Print "B."
 
   Print
   Print "Numeric Player bet ";NBet;" to ";
   If NType=1 Then Print "Win." Else Print "Lose."
   Print "Numeric Player selected Col ";Col
   Print
   s=(row-1)*2+(col-1)
   Print "The selected Value is ";Abs(Board(s));"-";
   If Board(s)>0
      Print "White."
   Else
      Print "Red."
   Endif
   totalbet=(Abs(Board(s))*Bet1+Abs(Board(s))*Bet2)*2
   Print "Total Bet = ";totalbet;". Pot = ";pot+totalbet*2;"."
   Print "Press any key to continue."
   Wait Key
 
   `Scoring phase
   Funds1=Funds1-totalbet
   Funds2=Funds2-totalbet
   pot=pot+totalbet*2
   win1=0
   win2=0
   `Scoring if player=1
   If Board(s)<0
      If AType=1 Then Win1=1
      If NType=2 then Win2=1
   Endif
   If Board(s)>0
      If AType=2 Then Win1=1
      If NType=1 then Win2=1
   Endif
   `Flip win values if Player=2
   If Player=2
      Win1=(Win1=0)
      Win2=(Win2=0)
   Endif
 
   `Payout phase
   If Win1<>Win2
      If Win1=1
         Print "You have won the pot for ";pot;"!"
         Funds1=Funds1+pot
         AI_Score=AI_Score-pot
      Else
         Print "The AI has won the pot for ";pot;"."
         Funds2=Funds2+pot
         AI_Score=AI_Score+pot
      Endif
      pot=0
   Else
      If Win1=0
         Print "You have both bet incorrectly. This hand is a draw."
      Else
         Print "You have both bet correctly. This hand is a draw."
      Endif
   Endif
   Print
   Print "Press any key to deal the next hand."
   Wait key
   If Funds1<0 Then Funds1=Funds1+300
   If Funds1>1000 Then Funds1=Funds1-300
   If Funds2<0 Then Funds2=Funds2+300
   If Funds2>1000 Then Funds2=Funds2-300
 
Loop
 
End
 
#Constant Deal Deal()
Function Deal()
   Cls
   Ink Rgb(50,50,255),0
   Box 30,30,60,60
   Box 70,30,100,60
   Box 30,70,60,100
   Box 70,70,100,100
   Ink Rgb(255,255,255),0
   Center Text 45,5,"1"
   Center Text 85,5,"2"
   Ink Rgb(255,0,0),0
   Center Text 10,40,"A"
   Center Text 10,80,"B"
   For i = 0 to 3
      board(i)=(rnd(4)+1)*(Rnd(1)*2-1)
      if Player=1
         c=board(i)+5
      Else
         c=5-board(i)
      Endif
      Set_Charge(Mem1,i,c)
      if Player=1
         c=5-board(i)
      Else
         c=board(i)+5
      Endif
      Set_Charge(Mem1,i+4,c)
      t=t+board(i)
   Next i
   t=Sigmoidal(t,1)*15
   Set_Charge(Mem1,8,t)
   if board(0)>0 Then Ink RGB(255,255,255),0 Else Ink Rgb(255,0,0),0
   Center Text 45,40,Str$(Abs(board(0)))
   if board(1)>0 Then Ink RGB(255,255,255),0 Else Ink Rgb(255,0,0),0
   Center Text 85,40,Str$(Abs(board(1)))
   if board(2)>0 Then Ink RGB(255,255,255),0 Else Ink Rgb(255,0,0),0
   Center Text 45,80,Str$(Abs(board(2)))
   if board(3)>0 Then Ink RGB(255,255,255),0 Else Ink Rgb(255,0,0),0
   Center Text 85,80,Str$(Abs(board(3)))
   Ink Rgb(200,200,255),0
   Text 120,5,"Pot = "+Str$(Pot)
   c=Sigmoidal(Pot-(pot*.5),75)*15
   Set_Charge(Mem1,9,c)
   Text 120,20,"Player has "+Str$(Funds1)
   c=Sigmoidal(Funds1-(Funds1*.5),250)*15
   Set_Charge(Mem1,10,c)
   Text 120,35,"AI has "+Str$(Funds2)
   c=Sigmoidal(Funds2-(Funds2*.5),250)*15
   Set_Charge(Mem1,11,c)
   Text 120,55,"Player is "+Player$
Endfunction
 
 
 
 
`=========================================================ANNTM==================================================
 
 
Charges:
`Set_Charge is used to set a neuron's charge to a specific value between 0 and 15
Function Set_Charge(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   Byt=Set_Right_Nibble(0,rit)
   If Value>15 then Value=15
   Byt=Set_Left_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
`Add_Charge is used to add a "charge" value to the neuron's existing charge.
Function Add_Charge(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Right_Nibble(0,rit)
   Value=lft+Value
   If Value>15 then Value=15
   Byt=Set_Left_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
`Deduct_Charge is used to subtract a charge value from the neuron's existing charge.
Function Deduct_Charge(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Right_Nibble(0,rit)
   If lft>Value
      Value=lft-Value
   Else
      Value=0
   Endif
   If Value>15 then Value=15
   Byt=Set_Left_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
Function Read_Charge(Memblock, Neuron)
   If Neuron>31 then ExitFunction 0
   If Memblock Exist(Memblock)=0 Then ExitFunction 0
   NOff=Neuron*6
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   lft=Get_Left_Nibble(Byt)-Pain
Endfunction lft
 
 
`Clear_Charges: sets all the neuron charges to the provided Value in the given cluster.
Function Set_All_Charges(Memblock,Value)
   For i = 0 to 31
      Set_Charge(Memblock,i,Value)
   Next i
Endfunction
 
`Drain_Charges: Subtracts 1 from all the neuron charges in the given cluster. Useful for a timer or score drain.
Function Drain_Charges(Memblock)
   For i = 0 to 31
      Deduct_Charge(Memblock,i,1)
   Next i
Endfunction
 
`Pump_Charges: Adds 1 to all the neuron charges in the given cluster. Useful for a timer or score boost.
Function Pump_Charges(Memblock)
   For i = 0 to 31
      Add_Charge(Memblock,i,1)
   Next i
Endfunction
 
Clusters:
`Fire_Neurons runs through all a cluster's neurons and checks if they should be fired or not.
`If a neuron is fired, it's Weight is applied to all linked neurons in the target cluster
`and the firing neuron's charge is set to 0.
`If the Cluster does not have a Target Cluster Assigned to it, then the neurons are not fired.
Function Fire_Neurons(SourceMem)
   If SourceMem=0 Then ExitFunction
   If Memblock Exist(SourceMem)=0 Then ExitFunction
   TargetMem=Cluster_Link(SourceMem)
   If TargetMem=0 Then ExitFunction
   If Memblock Exist(TargetMem)=0 Then ExitFunction
   Link as DWord
   For i = 0 to 31
      Charge=Read_Charge(SourceMem,i)
      Threshold=Read_Threshold(SourceMem,i)
      If Charge=>Threshold : `Fire Neuron
         Weight#=Read_Weight(SourceMem,i)
         Link = Neuron_Link_Dword(SourceMem,i)
         For j=0 to 31
            If (Link && 2^j) <> 0
               Curve#=Read_Curve(TargetMem,j)
               Result=Sigmoidal(Weight#-7.5,Curve#*.5)*5
               Add_Charge(TargetMem,j,Result)
            Endif
         Next j
         Set_Charge(SourceMem,i,0)
      Endif
   Next i
Endfunction
 
`Assign_Cluster:
`Assigns a Target Memblock Cluster to a Source Memblock Cluster (recorded in the source).
`When the Source Neurons fire, the Target Neurons will receive the resulting charges.
`This function can also be used to create the memblocks.
`A Source Cluster can only be assigned a single Target Cluster. However, a Target Cluster can be
`the target of one or more Source Clusters.
Function Assign_Cluster(Source,Target)
   If Memblock Exist(Source)=0
      Make Memblock Source,200
   Endif
   If Memblock Exist(Target)=0
      Make Memblock Target,200
   Endif
   t as word
   t=Target
   Write Memblock Word Source,198,t
Endfunction
 
Function Cluster_Link(Source)
   If Memblock Exist(Source)=0 Then Exitfunction 0
   target=Memblock Word(Source,198)
Endfunction target
 
 
Links:
`======================================================
`=======================Links==========================
`======================================================
 
`Link_Neuron:
`Links a single Source Neuron to a single Target Neuron. A Neuron can have up to 32 targets.
`The target neurons are also determined by the Source neuron's cluster target (see Assign_Cluster).
`Memblock must be a valid Memblock Cluster. Source must be a byte <= 31. Target must be a byte <= 31.
Function Link_Neuron(Memblock, Source as Byte, Target as Byte)
   If Memblock Exist(Memblock)=0 Then ExitFunction
   If Source>31 Then ExitFunction
   If Target>31 then ExitFunction
   Link as Dword
   Link = Neuron_Link_Dword(Memblock,Source)
   Link = Link || 2^Target
   Write_Neuron_Link_Dword(Memblock,Source,Link)
Endfunction
 
Function DeLink_Neuron(Memblock, Source as Byte, Target as Byte)
   If Memblock Exist(Memblock)=0 Then ExitFunction
   If Source>31 Then ExitFunction
   If Target>31 then ExitFunction
   Link as Dword
   Link=Neuron_Link_DWord(Memblock,Source)
   Link = Link .. Link :`Invert Link
   Link = Link || 2^Target :`OR the appropriate bit
   Link = Link .. Link : `Invert Link back to the original settings
   Write_Neuron_Link_Dword(Memblock,Source,Link)
Endfunction
 
Function Neuron_Link_Dword(Memblock,Neuron)
   zero as dword = 0
   If Memblock Exist(Memblock)=0 Then ExitFunction zero
   Links=Neuron*6+2
   DW as DWord
   DW=Memblock Dword(Memblock,Links)
Endfunction DW
 
Function Write_Neuron_Link_DWord(Memblock,Neuron,DW as DWord)
   If Memblock Exist(Memblock)=0 Then ExitFunction
   Links=Neuron*6+2
   Write Memblock DWord Memblock,Links,DW
Endfunction
 
 
`======================================================
`=====================Thresholds=======================
`======================================================
Thresholds:
 
`Set_Threshold is used to set a neuron's threshold to a specific value between 0 and 15
Function Set_Threshold(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Left_Nibble(0,lft)
   If Value>15 then Value=15
   Byt=Set_Right_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
`Add_Threshold is used to add to the to the neuron's existing threshold value.
Function Add_Threshold(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Left_Nibble(0,lft)
   Value=rit+Value
   If Value>15 then Value=15
   Byt=Set_Right_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
`Deduct_Threshold is used to subtract a value from the neuron's existing threshold value.
Function Deduct_Threshold(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Left_Nibble(0,lft)
   If rit>Value
      Value=rit-Value
   Else
      Value=0
   Endif
   If Value>15 then Value=15
   Byt=Set_Right_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
Function Read_Threshold(Memblock, Neuron)
   If Neuron>31 then ExitFunction 0
   If Memblock Exist(Memblock)=0 Then ExitFunction 0
   NOff=Neuron*6
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)-Pain
Endfunction rit
 
`Set_All_Thresholds: sets all the neuron thresholds to the specified Value in the given cluster.
Function Set_All_Thresholds(Memblock,Value)
   For i = 0 to 31
      Set_Threshold(Memblock,i,Value)
   Next i
Endfunction
 
`Drain_Thresholds: Subtracts 1 from all the neuron thresholds in the given cluster.
Function Drain_Thresholds(Memblock)
   For i = 1 to 31
      Deduct_Threshold(Memblock,i,1)
   Next i
Endfunction
 
`Pump_Thresholds: Adds 1 to all the neuron thresholds in the given cluster.
Function Pump_Thresholds(Memblock)
   For i = 1 to 31
      Add_Threshold(Memblock,i,1)
   Next i
Endfunction
 
 
`======================================================
`=======================Curves=========================
`======================================================
Curves:
 
`Set_Curve is used to set a neuron's Curve to a specific value between 0 and 15
Function Set_Curve(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6+1
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   Byt=Set_Right_Nibble(0,rit)
   If Value>15 then Value=15
   Byt=Set_Left_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
`Add_Curve is used to add a value to the neuron's existing Curve.
Function Add_Curve(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6+1
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Right_Nibble(0,rit)
   Value=lft+Value
   If Value>15 then Value=15
   Byt=Set_Left_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
`Deduct_Curve is used to subtract a Curve value from the neuron's existing Curve.
Function Deduct_Curve(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6+1
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Right_Nibble(0,rit)
   If lft>Value
      Value=lft-Value
   Else
      Value=0
   Endif
   If Value>15 then Value=15
   Byt=Set_Left_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
Function Read_Curve(Memblock, Neuron)
   If Neuron>31 then ExitFunction 0
   If Memblock Exist(Memblock)=0 Then ExitFunction 0
   NOff=Neuron*6+1
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   lft=Get_Left_Nibble(Byt)
Endfunction lft
 
 
`Clear_Curves: sets all the neuron Curves to the specified Value.
Function Set_All_Curves(Memblock,Value)
   For i = 0 to 31
      Set_Curve(Memblock,i,Value)
   Next i
Endfunction
 
`Drain_Curves: Subtracts 1 from all the neuron Curves in the given cluster. Useful for a timer or score drain.
Function Drain_Curves(Memblock)
   For i = 1 to 31
      Deduct_Curve(Memblock,i,1)
   Next i
Endfunction
 
`Pump_Curves: Adds 1 to all the neuron Curves in the given cluster. Useful for a timer or score boost.
Function Pump_Curves(Memblock)
   For i = 1 to 31
      Add_Curve(Memblock,i,1)
   Next i
Endfunction
 
 
 
`======================================================
`=======================Weights========================
`======================================================
Weights:
 
`Set_Weight is used to set a neuron's Weight to a specific value between 0 and 15
Function Set_Weight(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6+1
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Left_Nibble(0,lft)
   If Value>15 then Value=15
   Byt=Set_Right_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
`Add_Weight is used to add to the to the neuron's existing Weight value.
Function Add_Weight(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6+1
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Left_Nibble(0,lft)
   Value=rit+Value
   If Value>15 then Value=15
   Byt=Set_Right_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
`Deduct_Weight is used to subtract a value from the neuron's existing Weight value.
Function Deduct_Weight(Memblock, Neuron, Value as Byte)
   If Neuron>31 then ExitFunction
   If Memblock Exist(Memblock)=0 Then ExitFunction
   NOff=Neuron*6+1
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
   lft=Get_Left_Nibble(Byt)
   Byt=Set_Left_Nibble(0,lft)
   If rit>Value
      Value=rit-Value
   Else
      Value=0
   Endif
   If Value>15 then Value=15
   Byt=Set_Right_Nibble(Byt,Value)
   Write Memblock Byte Memblock,NOff,Byt
Endfunction
 
Function Read_Weight(Memblock, Neuron)
   If Neuron>31 then ExitFunction 0
   If Memblock Exist(Memblock)=0 Then ExitFunction 0
   NOff=Neuron*6+1
   Byt as Byte
   Byt=Memblock Byte(Memblock,NOff)
   rit=Get_Right_Nibble(Byt)
Endfunction rit
 
`Set_All_Weights: sets all the neuron Weights to the specified Value in the given cluster.
Function Set_All_Weights(Memblock,Value)
   For i = 0 to 31
      Set_Weight(Memblock,i,Value)
   Next i
Endfunction
 
`Drain_Weights: Subtracts 1 from all the neuron Weights in the given cluster.
Function Drain_Weights(Memblock)
   For i = 1 to 31
      Deduct_Weight(Memblock,i,1)
   Next i
Endfunction
 
`Pump_Weights: Adds 1 to all the neuron Weights in the given cluster.
Function Pump_Weights(Memblock)
   For i = 1 to 31
      Add_Weight(Memblock,i,1)
   Next i
Endfunction
 
 
`This function is added to set, or reset, our neurons randomly.
Function Initialize_AI()
   dw as DWord
   For i = 1 to Clusters
      For j=0 to 31
         Set_Threshold(i,j,Rnd(14)+1)
         Set_Weight(i,j,Rnd(14)+1)
         Set_Curve(i,j,Rnd(14)+1)
      Next j
   Next i
Endfunction
 
`This function is added to set, or reset, our neuron links randomly.
Function Initialize_Links()
   dw as DWord
   For i = 1 to Clusters
      For j=0 to 31
         d1=Rnd(255):d2=rnd(255):d3=Rnd(255):d4=Rnd(255)
         dw=d1+(d2 << 8) + (d3 << 16) + (d4 << 24)
         Write_Neuron_Link_DWord(i,j,dw)
      Next j
   Next i
Endfunction
 
Function Epoch()
   Inc Epoch_Timer
   If Epoch_Timer<Epoch_Length Then ExitFunction
 
   `Here's where we score our neuron settings and store them for later:
   For i = 1 to Clusters
      For j = 0 to 31
         n=Read_Curve(i,j)
         curve=Int(Sigmoidal((AI_Score-AI_Average)+(Get_Gene(i,j,n,G_Curve)*10),500)*10)
         Write_Gene(i,j,n,G_Curve,curve)
         n=Read_Weight(i,j)
         weight=Int(Sigmoidal((AI_Score-AI_Average)+(Get_Gene(i,j,n,G_Weight)*10),500)*10)
         Write_Gene(i,j,n,G_Weight,weight)
         n=Read_Threshold(i,j)
         threshold=Int(Sigmoidal((AI_Score-AI_Average)+(Get_Gene(i,j,n,G_Threshold)*10),500)*10)
         Write_Gene(i,j,n,G_Theshold,threshold)
      Next j
   Next i
 
   `Initialize the AI with some random values.
   Initialize_AI()
   `Now populate the AI with some best scores. The more Epochs that go by, the less mutation occurs.
   `Note: this is sort of an inverse mutation function. The gene starts off by default as mutated.
   `      Then if the random selection comes up, the mutation is replaced by a successful gene.
   `      The more Epochs that go by, the more likely the mutations will be replaced, but never 100%.
   Get_Best_Genes()
   For i = 1 to Clusters
      For j = 0 to 31
         If Rnd(20+Epoch_Counter)<Epoch_Counter
            Set_Curve(i,j,BestGenes(i,j).curve)
         Endif
         If Rnd(20+Epoch_Counter)<Epoch_Counter
            Set_Weight(i,j,BestGenes(i,j).weight)
         Endif
         If Rnd(20+Epoch_Counter)<Epoch_Counter
            Set_Threshold(i,j,BestGenes(i,j).threshold)
         Endif
      Next j
      Link_Learning()
   Next i
 
   `Calculate the new average score
   Inc Epoch_Counter
   `Weighted average so the current performance is based on past performance.
   AI_Average=((AI_Average * (Epoch_Counter-1))+AI_Score)/Epoch_Counter
 
   AI_Score=0
   Epoch_Timer=0
 
Endfunction
 
 
`This function chooses the "best" genes, the genes with the highest scores.
`A feature has been added to typically select 1 of the best 3 (usually) to avoid getting stuck in a niche.
Function Get_Best_Genes()
   For i = 1 to Clusters
      For j = 0 to 31
         best_curve=-9999
         best_weight=-9999
         best_threshold=-9999
         For k=0 to 15
            If best_curve<=Get_Gene(i,j,n,G_Curve) and rnd(3)=1  :`Typically will choose one of the best 3, but not always.
               best_curve=Get_Gene(i,j,n,G_Curve)
               BC=k
            Endif
            If best_weight<Get_Gene(i,j,n,G_Weight) and rnd(3)=1
               best_weight=Get_Gene(i,j,n,G_Weight)
               BW=k
            Endif
            If best_threshold<Get_Gene(i,j,n,G_Threshold) and rnd(3)=1
               best_threshold=Get_Gene(i,j,n,G_Threshold)
               BT=k
            Endif
         Next k
         BestGenes(i,j).curve=BC
         BestGenes(i,j).weight=BW
         BestGenes(i,j).threshold=BT
      Next j
   Next i
Endfunction
 
`Returns the Gene Setting score value from the cluster
Function Get_Gene(Cluster,Neuron as byte,Score as byte,Gene as byte)
   zero as dword = 0
   If Gene>2 Then Exitfunction zero
   If Score>15 Then Exitfunction zero
   If Neuron>31 Then Exitfunction zero
   r as Dword
   rbyte=200+Neuron*24+Int(Score/2)+(Gene*8)
   r=Memblock Byte(Cluster,rbyte)
   If Int(Score/2)*2=Score
      r=Get_Left_Nibble(r)
   Else
      r=Get_Right_Nibble(r)
   Endif
Endfunction r
 
`Write the Gene Setting score value to the cluster
Function Write_Gene(Cluster,Neuron as byte,Score as byte,Gene as byte, Value as Byte)
   zero as dword = 0
   If Gene>2 Then Exitfunction zero
   If Score>15 Then Exitfunction zero
   If Neuron>31 Then Exitfunction zero
   If Value>15 Then Value=15
   r as Dword
   rbyte=200+Neuron*24+Int(Score/2)+(Gene*8)
   r=Memblock Byte(Cluster,rbyte)
   If Int(Score/2)*2=Score
      r=Get_Left_Nibble(r)
   Else
      r=Get_Right_Nibble(r)
   Endif
Endfunction r
 
 
Function Link_Learning()
   links as Dword
   For i = 1 to Clusters
      `The "Crawling" part
      Inc LinkCrawler(i,33)
      If LinkCrawler(i,33)>100
         LinkCrawler(i,33)=0
         Inc LinkCrawler(i,32)
         If LinkCrawler(i,32)>31 then LinkCrawler(i,32)=0
         links = Neuron_Link_Dword(i,LinkCrawler(i,32))
         For j = 0 to 31
            bit=(Get_Bit(links,j)*2)-1
            LinkCrawler(i,j)=5*bit
         Next j
      Endif
      links=Neuron_Link_Dword(i,LinkCrawler(i,32))
      EC=Epoch_Counter-(LinkCrawler(i,32)*100)
      For j = 0 to 31
         sign=Get_Bit(links,j)*2-1
         LinkCrawler(i,j)=LinkCrawler(i,j)+((Int(Sigmoidal(AI_Score-AI_Average,500)*11)-5)*sign)
         If Rnd(20+EC)<EC
            If LinkCrawler(i,j)>0
               Link_Neuron(i,LinkCrawler(i,32),j)
            Else
               DeLink_Neuron(i,LinkCrawler(i,32),j)
            Endif
         Else
            if rnd(1)
               Link_Neuron(i,LinkCrawler(i,32),j)
            Else
               DeLink_Neuron(i,LinkCrawler(i,32),j)
            Endif
         Endif
      Next j
   Next i
Endfunction
 
 
#Constant Clusters Count_Memblocks()
Function Count_Memblocks()
   i=0
   Do
      If Memblock Exist(i+1)=0
         Exit
      Endif
      inc i
   Loop
EndFunction i
 
#Constant Free_Cluster Free_Memblock()
Function Free_Memblock()
   i=1
   Do
      If Memblock Exist(i)=0 Then Exit
      inc i
   Loop
Endfunction i
 
#Constant Make_Free_Cluster Free_Cluster()
Function Free_Cluster()
   mb=Free_Memblock()
   Make Memblock mb,1240
Endfunction mb
 
 
Function Sigmoidal(value#,curve#)
   `the sigmoidal formula. Graph this on a spreadsheet to see how it works.
   result#=1.0/(1.0+2.04541^-((value#)/(curve#*.1)))
   `The result# is a value between >0 and <1. Curve is the number standard deviations in a normal distribution.
Endfunction result#
 
`Simple Nibble Functions.
Function Set_Nibble(bt as byte, value as byte, nibble as byte)
   if nibble=0 then bt = Set_Right_Nibble(bt,value)
   if nibble=1 then bt = Set_Left_Nibble(bt,value)
Endfunction bt
 
Function Set_Left_Nibble(bt as byte,value as byte)
   value = value << 4
   bt = bt || value
Endfunction bt
 
Function Set_Right_Nibble(bt as byte,value as byte)
   value = value << 4
   value = value >> 4
   bt = bt || value
Endfunction bt
 
Function Get_Nibble(bt as byte, nibble as byte)
   if nibble=0 then bt=Get_Right_Nibble(bt)
   if nibble=1 then bt=Get_Left_Nibble(bt)
Endfunction bt
 
Function Get_Left_Nibble(bt as byte)
   bt = bt >> 4
Endfunction bt
 
Function Get_Right_Nibble(bt as byte)
   bt = bt << 4
   bt = bt >> 4
Endfunction bt
 
Function Get_Bit(value as DWord, bt as byte)
   bit as Dword
   bit= 2^bt
   r=Value && bit
   r=(r>0)
Endfunction r