Advertisement
Crashguard303

CG303 GAB V4.20

May 20th, 2012
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 60.76 KB | None | 0 0
  1. --[[
  2. Genetic Bands III by Crashguard303
  3.  
  4. Inspired by cartoon Villain's Script, I created this one, including freezing.
  5. This script also works on not-very-best puzzle-states.
  6.  
  7. Random Creating:
  8.  It creates a set of clusters (herd). Each cluster has a random set of bands,freezes and a drift value.
  9.  There is a random list, which segments have already been banded or frozen, so it is guaranteed that all are tried.
  10.  If all have been tried, this list is shuffled, all segments are tried again.
  11.  The drift shows, in which directions banding or freezing segments can move.
  12.  (-1 will increase current segment number by, +1 will increase segment number by 1, 0 won't exist)
  13.  
  14. Then, for this puzzle state, all clusters are tried.
  15. This means:
  16.  
  17. Pulling:
  18.  Bands and freezes are applied (plus constant bands, if you want), the puzzle is wiggled for one iteration.
  19.  
  20. Releasing:
  21.  Bands and freezes are removed.
  22.  4 different subroutines similar to blue fuse run.
  23.  They test different clashing-importance shake/wiggle combinations.
  24. The best result of the fuse is stored to the cluster score.
  25.  
  26. Sorting:
  27.  If all clusters were tried, they are sorted by the scores they created, double score results are moved to the end of the list.
  28.  The best cluster is on top, the worst or and equal cluster is on bottom at the list.
  29.  
  30. Breeding:
  31.  All clusters from BreedFirst to BreedLast are breeded, first best  with other random clusters, preferring good ones
  32.  The cluster with the most bands is mom, cluster with fewer bands is dad.
  33.  Bands of mom and drift value are copied at first,
  34.  then a random crossover point is generated within the length of dad's bands.
  35.  Bands from 1 to inclusive crossover point from the new cluster are replaced by bands of dad, rest of mom
  36.  The same happens to freezes.
  37.  
  38. Mutating:
  39.  For each band or freeze:
  40.   A random flag (Drift flag or multiplicator) (either 0 or 1)  is created, depending on mutation probability.
  41.   If this flag is 1, drift value (-1 or +1) is added to the segment index, in other case, the segment index stays the same.
  42.   Band length and strength are randomly changed between an amount of -0.1 to 0.1
  43.   When mutating, all values are checked after they are changed, to guarantee that they don't leave a legal value range.
  44.  
  45. Inverting:
  46.  For each band or freeze:
  47.   A random flag (inversion flag) (either o or 1) is created, depending on inverting probability.
  48.   If this flag is 1, segment values are inverted, which means multiplying them by -1
  49.   Negative segment values results banding or freezing skip, they are deactivated.
  50.   If a segment has a negative value and is inverted, the value is positive and activated again
  51.  
  52. Filling:
  53.  The rest of the herd (BreedLast+1 to HerdSize) is replaced by new random clusters, as described in Random Creating.
  54.  
  55. Restart:
  56.   When new clusters have been breeded or replaced, the recent best puzzle state is loaded.
  57.   and pulling is performed again.
  58.  
  59. END OF MAIN DESCRIPTION
  60. P.S.: If you find typos, you can keep them ;)
  61. ]]--
  62.  
  63.  
  64. function math.frandom(m,n,e)
  65.  -- float random, e is number of remaining decimal digits
  66.  local e2=10^e
  67.  return math.random(m*e2,n*e2)/e2
  68. end -- function
  69.  
  70. function math.sgn(x)
  71.  -- Signum function
  72.  
  73.  if x==nil then
  74.    return nil
  75.   elseif x>0 then
  76.    return 1
  77.   elseif x<-0 then
  78.    return -1
  79.   else
  80.    return x
  81.  end -- if
  82. end -- function
  83.  
  84. function CutOff(x,y)
  85.  -- Keep only y digits after decimal point from x
  86.  return math.floor(x*10^y)/10^y
  87. end -- function
  88.  
  89. BoolString={}
  90. BoolString[true]="In"
  91. BoolString[false]="Ex"
  92.  
  93. function UseSegIRange(UseList,A,B,StepSize,bool)
  94.  -- In table "UseList", append or remove segment range A to B
  95.  local UseList=UseList
  96.  local A=A -- range start
  97.  local B=B -- range end
  98.  if A>B then A,B=B,A end -- Swap range start and end, if values are not okay
  99.  local StepSize=StepSize
  100.  local bool=bool -- True=append, false=remove
  101.  
  102.  local k=A
  103.  repeat
  104.   UseList=UseList_AR(UseList,k,bool)
  105.   k=k+StepSize -- increase k by StepSize
  106.  until k>B -- until k exceeds B
  107.  return UseList
  108. end -- function
  109.  
  110. function UseSegIValues(UseList,field,bool)
  111.  -- In table "UseList", append or remove segments listed in table "field"
  112.  local UseList=UseList
  113.  local field=field  -- table to add
  114.  local bool=bool -- True=append, false=remove
  115.  
  116.  local k
  117.  if #field>0 then -- If table to add is not empty
  118.    for k=1,#field do -- cycle through all elements from table
  119.     UseList=UseList_AR(UseList,field[k],bool)
  120.    end -- k loop
  121.  end -- if #field
  122.  return UseList
  123. end -- function
  124.  
  125. function Use_ss(UseList,SSLetter,bool)
  126.  -- In table "UseList", append or remove segments with secondary structure "SSLetter"
  127.  local UseList=UseList
  128.  local SSLetter=SSLetter
  129.  local bool=bool -- True=append, false=remove
  130.  
  131.  local k
  132.  for k=1,NumSegs do -- Cycle through all segment indices
  133.   if structure.GetSecondaryStructure(k)==SSLetter then -- If current segment index has same ss as given
  134.     UseList=UseList_AR(UseList,k,bool)
  135.   end -- if get_ss
  136.  end -- k loop
  137.  return UseList
  138. end -- function
  139.  
  140. function Use_aa(UseList,AALetters,bool)
  141.  -- In table "UseList", append or remove segments with amino-acid in table "AALetters"
  142.  local UseList=UseList
  143.  local AALetters=AALetters
  144.  local bool=bool -- add or  remove
  145.  
  146.  if #AALetters>0 then -- Is there minimum one aa letter given?
  147.  
  148.   local k
  149.   for k=1,NumSegs do -- Cycle through all segments
  150.    local aa=get_aa(k) -- get current aa of segment index k
  151.  
  152.    local exit_condition=false
  153.    local l=0
  154.    repeat
  155.     l=l+1 -- Cycle through all given aa letters
  156.     if aa==AALetters[l] then -- If current segment k's aa is equal to AALetters[l]
  157.      UseList=UseList_AR(UseList,k,bool)
  158.      exit_condition=true -- l loop can end here
  159.     end -- if aa
  160.     if l==#AALetters then exit_condition=true end
  161.    until exit_condition==true
  162.   end -- k loop
  163.  end -- if AALetters
  164.  return UseList
  165. end -- function
  166.  
  167. function Use_distance(UseList,MinDist,MaxDist,MinQuantity,MaxQuantity,bool)
  168.  -- In table "UseList", append or remove segments which have
  169.  -- MinQuantity to MaxQuantity neighbours within distance MinDist to MaxDist
  170.  local MinDist=MinDist
  171.  local MaxDist=MaxDist
  172.  local MinQuantity=MinQuantity
  173.  local MaxQuantity=MaxQuantity
  174.  local bool=bool -- True=append, false=remove
  175.  
  176.  for k=1, NumSegs do -- Cycle through all segments
  177.   local QCount=0
  178.   for l=1,NumSegs do -- compare index k with all around
  179.    if l~=k then -- Don't count segment itself, only neighbours
  180.     local Distance=structure.GetDistance(k,l) -- Measure distance from segment k to segment l
  181.     if Distance>=MinDist then -- If equal or above min distance
  182.      if Distance<=MaxDist then -- If equal or below max distance
  183.       QCount=QCount+1 -- count this segment
  184.      end -- if Distance
  185.     end -- if Distance
  186.    end -- if l
  187.   end -- l loop
  188.   if QCount<=MaxQuantity then -- If count is equal or below max quantity
  189.    if QCount>=MinQuantity then -- If count is equal or above min quantity
  190.     UseList=UseList_AR(UseList,k,bool) -- add or remove from list
  191.    end -- if QCount
  192.   end -- if QCount
  193.  end -- k loop
  194.  return UseList
  195. end -- function
  196.  
  197. function Use_close_ligand(UseList,MaxDist,bool)
  198.  -- In table "UseList", append or remove segments which have
  199.  -- a spatial distance of MaxDist or closer to ligand.
  200.  local UseList=UseList
  201.  local MaxDist=MaxDist
  202.  local bool=bool -- True=append, false=remove
  203.  local LigandIdx=NumSegs+1 -- Ligand Index
  204.  
  205.  local k
  206.  for k=1,NumSegs do -- Cycle with k through all segments but not ligand
  207.   local Distance=structure.GetDistance(k,LigandIdx) -- Check spatial distance of segment k to ligand
  208.   if Distance<=MaxDist then -- If equal or below MaxDist
  209.    UseList=UseList_AR(UseList,k,bool) -- add or remove from list
  210.   end -- if
  211.  end -- k loop
  212.  return UseList
  213. end -- function
  214.  
  215. function UseList_AR(UseList,value,bool)
  216.  -- Append value "value" to UseList
  217.  -- or remove all value's out of UseList, depending on bool
  218.  local UseList=UseList
  219.  local value=value
  220.  local bool=bool -- True=append, false=remove
  221.  -- print(BoolString[bool],"cluding segment index ",value)
  222.    if bool==true then
  223.       UseList=UseList_Append(UseList,value)
  224.     else
  225.       UseList=UseList_Remove(UseList,value)
  226.     end -- if bool
  227.  return UseList
  228. end -- function
  229.  
  230. function UseList_Append(UseList,value)
  231.  -- Adds content of "value" at end of UseList
  232.  local UseList=UseList
  233.  local value=value
  234.  UseList[#UseList+1]=value
  235.  return UseList
  236. end -- function
  237.  
  238. function UseList_Remove(UseList,value)
  239.  -- Creates new use list "UseList2" out of "UseList", but without all content of "value"
  240.  local UseList=UseList
  241.  local value=value
  242.  local UseList2={} -- Initialize new uselist
  243.  if #UseList>0 then -- if old
  244.   for k=1,#UseList do -- Scan UseList
  245.    if UseList[k]~=value then -- If "value" is not found
  246.     UseList2[#UseList2+1]=UseList[k] -- append this content to new use list
  247.    end -- if UseList
  248.   end -- k loop
  249.  end -- if UseList
  250.  return UseList2
  251. end -- function
  252.  
  253. function CompactContent(OS,E,AS)
  254.  --[[
  255.  Adds string AS to temporary output string OS and counts number of added AS in E.
  256.  If OS contents 10 elements, line is printed out
  257.  
  258.  I only had to write this sub because there Lua standard library is not included.
  259.  We neither can do some string manipulation nor use a print command without linebreaks at the moment :/
  260.  ]]--
  261.  
  262.  local OS=OS -- Temporary string for output
  263.  local AS=AS  -- String to add
  264.  local E=E -- Element counter, how often AS was added
  265.  
  266.  E=E+1
  267.  if AS<10 then -- Sorry for this, but there are no string operations possible at the moment
  268.    OS=OS.."00"..AS
  269.   elseif AS<100 then
  270.    OS=OS.."0"..AS
  271.   else
  272.    OS=OS..AS
  273.  end -- if AS
  274.  
  275.  if E<10 then -- If there are not 10 elements per line
  276.    OS=OS.."   " -- add space
  277.   else -- If there are 10 elements per line
  278.    print(OS) -- print line out
  279.    OS="" -- clear output string
  280.    E=0 -- reset element counter
  281.  end -- if E
  282.  return OS,E
  283. end -- function
  284.  
  285. function CheckUselist(UseList)
  286.  -- If there are fewer than 3 specific segments to work on given, take all
  287.  local UseList=UseList
  288.  if #UseList<=3 then
  289.   print("No or too few specific segments to work on given.")
  290.   print("Banding and freezing will now manipulate all puzzle segments.")
  291.   UseList={}
  292.   local k
  293.   for k=1,NumSegs do -- Cycle through all segments
  294.    UseList[#UseList+1]=k -- extend UseList by 1 and add segment index
  295.   end -- k loop
  296.  end -- if UseList
  297.  print("Segment list is now:")
  298.  local OS="" -- Initialize output string
  299.  local E=0 -- Initialize element counter
  300.  local k
  301.  for k=1,#UseList do
  302.    OS,E=CompactContent(OS,E,UseList[k])
  303.  end -- k
  304.  if E>0 then
  305.   print(OS)
  306.  end
  307.  return UseList
  308. end -- function
  309.  
  310. function shuffle2(ShuffleProb)
  311.  -- Scrambles segment use list depending on ShuffleProb
  312.  print("Shuffling segment list")
  313.  
  314.  kend=#UseList-1
  315.  local k
  316.  for k=1,kend do -- Cycle through all UseList entries
  317.   if math.random()<ShuffleProb then -- If random value<probability
  318.   -- same as: if random_flag(ShuffleProb) then
  319.    local l=math.random(k+1,#UseList) -- pick random list entry behind k
  320.    UseList[k],UseList[l]=UseList[l],UseList[k] -- swap values of UseList index k with UseList index l
  321.   end -- if random
  322.  end -- k loop
  323.  UsedSegments=0 -- After Shuffling, set list pointer to 0
  324. end
  325.  
  326. function random_segment()
  327.  -- Gets a random segment index out of UseList which has not been used so far
  328.  
  329.  UsedSegments=UsedSegments+1 -- Increase UseList pointer
  330.  local Seg_result=UseList[UsedSegments] -- fetch segment index
  331.  if UsedSegments==#UseList then shuffle2(ShuffleProb) end
  332.  -- If this was the last value of UseList, shuffle list and reset pointer
  333.  
  334.  return Seg_result -- return random segment number
  335. end -- function
  336.  
  337. function FillHerd(StartAt,EndAt,TimeStamp)
  338.  local StartAt=StartAt -- First cluster index to generate (not cluster slot)
  339.  if StartAt<=HerdSize then
  340.   local EndAt=EndAt -- Last cluster index to generate (not cluster slot)
  341.   local TimeStamp=TimeStamp -- "birth date"
  342.   print("Generating Herd from ",StartAt," to ",EndAt)
  343.  
  344.   local k2
  345.   for k2=StartAt,EndAt do
  346.    -- print("Cluster: ",k2)
  347.    local k=ClusterPointer[k2] -- Fetch cluster slot by cluster index
  348.    ClusterScore[k]=0
  349.    ClusterDrift[k]=random_direction() -- Create value -1 or 1
  350.  
  351.    if (Mimic and k2==1) then -- If this is a Mimic band
  352.      ClusterType[k]="mimic" -- set cluster information for Mimic
  353.     else -- If this is not a Mimic band
  354.      ClusterType[k]="random" -- set cluster information for random
  355.    end -- if k2
  356.    ClusterType[k]=ClusterType[k].."-"..TimeStamp -- Show "birth date"
  357.  
  358.    if ClusterBands>0 then
  359.    ClusterSegA[k]={}
  360.    ClusterSegB[k]={}
  361.    ClusterLength[k]={}
  362.    ClusterStrength[k]={}
  363.  
  364.     local l
  365.     for l=1,ClusterBands do
  366.      if puzzle_is_ligand==false then -- If this is no ligand puzzle
  367.        ClusterSegA[k][l]=random_segment() -- get random segment number
  368.       else -- If this is a ligand puzzle
  369.        ClusterSegA[k][l]=NumSegs+1 -- Segment A is always ligand
  370.      end -- if puzzle_is_ligand
  371.  
  372.      if (Mimic==false or k2~=1) then -- If this is not a Mimic band
  373.       if random_flag(InvBProb) then -- and random flag for inverting is given
  374.        ClusterSegA[k][l]=-ClusterSegA[k][l] -- toggle cluster on/off by changing signum (+/-)
  375.       end -- if random_flag
  376.      end -- if k2
  377.  
  378.      repeat
  379.       ClusterSegB[k][l]=random_segment()
  380.       local IDistance=index_distance(ClusterSegA[k][l],ClusterSegB[k][l]) -- fetch index distance
  381.       local SDistance=structure.GetDistance(math.abs(ClusterSegA[k][l]),ClusterSegB[k][l]) -- fetch spatial distance
  382.      until IDistance>=MID_Game and SDistance<=MaxBL_Game
  383.      -- Segments must have a minimum index distance
  384.      -- and maximum spatial distance
  385.  
  386.      if (Mimic and k2==1) then -- If this is a Mimic band
  387.        ClusterLength[k][l]=FactorByLength(ClusterSegA[k][l],ClusterSegB[k][l])
  388.        ClusterStrength[k][l]=MaxBS
  389.       else -- if k2
  390.        ClusterLength[k][l]=math.frandom(0,1,6)
  391.        ClusterStrength[k][l]=math.frandom(MinBS,MaxBS,3)
  392.      end -- if k2
  393.  
  394.     end  -- l loop
  395.    end -- if ClusterBands
  396.  
  397.    if ClusterFreezes>0 then
  398.     ClusterFreeze[k]={}
  399.     local l
  400.     for l=1,ClusterFreezes do
  401.      ClusterFreeze[k][l]=random_segment()
  402.      if (Mimic and k2==1) or random_flag(InvFProb) then -- If this is a Mimic band or random flag for inverting freeze information is given
  403.       ClusterFreeze[k][l]=-ClusterFreeze[k][l] -- toggle freeze on/off by changing signum (+/-)
  404.      end -- if random_flag
  405.     end -- l loop
  406.    end -- if
  407.   end -- k loop
  408.  end -- if StartAt
  409. end -- function
  410.  
  411. function ShowHerd()
  412.  local k2
  413.  local l
  414.  
  415.  print("Clusters are:")
  416.  for k2=1,HerdSize do
  417.   local k=ClusterPointer[k2]
  418.   print("Cluster:",k2," score:",ClusterScore[k]," drift:",ClusterDrift[k])
  419.   if ClusterBands>0 then
  420.    local l
  421.    for l=1,ClusterBands do
  422.     print("Band ",l,": ",ClusterSegA[k][l]," to ",ClusterSegB[k][l])
  423.    end
  424.   end -- if ClusterBands
  425.  
  426.   if ClusterFreezes>0 then
  427.    local l
  428.    for l=1,ClusterFreezes do
  429.    print("Freeze ",l,": ",ClusterFreeze[k][l])
  430.    end -- l
  431.   end -- if
  432.  end -- k loop
  433. end -- function
  434.  
  435. function ShowHerdShort()
  436.  print("Clusters are:")
  437.  
  438.  local k2
  439.  for k2=1,HerdSize do
  440.   local k=ClusterPointer[k2]
  441.   print("Cluster:",k2,"(",k,") score:",ClusterScore[k])
  442.   print("Drift:",ClusterDrift[k])
  443.  end -- k loop
  444. end -- function
  445.  
  446. function ShowScoreList()
  447.  local k2
  448.  for k2=1,HerdSize do
  449.   local k=ClusterPointer[k2]
  450.   print("Cluster:",k2,"(",k,") delta:",ClusterScore[k])
  451.  end -- k
  452. end -- function
  453.  
  454. function SortHerd()
  455.  -- As we use pointers, we only have to swap the cluster "adresses" instead of copying all band/freeze values
  456.  local Finish=HerdSize-1
  457.  local k
  458.  for k=1,Finish do
  459.   local start=k+1
  460.   local l
  461.   for l=start,HerdSize do
  462.    if ClusterScore[ClusterPointer[l]]>ClusterScore[ClusterPointer[k]] then
  463.     -- print("Swapping cluster ",k,"(",ClusterPointer[k],"):",l,"(",ClusterPointer[l],")")
  464.     ClusterPointer[l],ClusterPointer[k]=ClusterPointer[k],ClusterPointer[l]
  465.    end -- if
  466.   end -- l
  467.  end -- k
  468. end -- function
  469.  
  470. function CreateCrossoverPoint(x)
  471.  -- create random crossover point
  472.  
  473.   if x==0 then
  474.     return 0
  475.    else -- if x ~=0
  476.     -- return math.random(0,x) -- create random value between 0 and x
  477.     return math.random(1,x-1) -- create random value between 1 and x-1
  478.   end -- if x
  479. end -- function
  480.  
  481. function Breed(TimeStamp)
  482.   -- Copy all clusters to another bank, same name for all cluster tables but with 2 at end
  483.   -- Breed two clusters from bank 2 back to old bank to prevent breeding collision.
  484.   -- If this wouldn't be done, and (for example) cluster 1 and 2 would be breeded to cluster 3,
  485.   -- cluster 3 couldn't be used as breeding source again, as it would be overwritten already.
  486.  
  487.   local TimeStamp=TimeStamp -- "birth date"
  488.  
  489.   ClusterScore2={}
  490.   -- ClusterType2={}
  491.   ClusterDrift2={}
  492.  
  493.   ClusterSegA2={}
  494.   ClusterSegB2={}
  495.   ClusterLength2={}
  496.   ClusterStrength2={}
  497.  
  498.   ClusterFreeze2={}
  499.  
  500.    local k
  501.    for k=1,HerdSize do
  502.     ClusterScore2[k]=ClusterScore[k]
  503.     ClusterDrift2[k]=ClusterDrift[k]
  504.  
  505.     if ClusterBands>0 then
  506.      ClusterSegA2[k]={}
  507.      ClusterSegB2[k]={}
  508.      ClusterLength2[k]={}
  509.      ClusterStrength2[k]={}
  510.      local l
  511.      for l=1,ClusterBands do
  512.        ClusterSegA2[k][l]=ClusterSegA[k][l]
  513.        ClusterSegB2[k][l]=ClusterSegB[k][l]
  514.        ClusterLength2[k][l]=ClusterLength[k][l]
  515.        ClusterStrength2[k][l]=ClusterStrength[k][l]
  516.      end -- l loop
  517.     end -- if ClusterBands
  518.  
  519.      if ClusterFreezes>0 then
  520.      ClusterFreeze2[k]={}
  521.      local l
  522.      for l=1,ClusterFreezes do
  523.        ClusterFreeze2[k][l]=ClusterFreeze[k][l]
  524.      end -- l loop
  525.     end -- if ClusterFreezes
  526.    end -- k loop
  527.  
  528.    FitnessOffset=ClusterScore[ClusterPointer[HerdSize]]
  529.    -- Take worst cluster score as fitness offset reference
  530.    -- By subtracting this score offset from each cluster score and adding 1,
  531.    -- it is guaranteed that worst cluster score is always 1, all other scores are better.
  532.    -- This will shift all cluster scores up, if worst cluster score is below 1, so there will be no values<1 for fitness calculation.
  533.    -- It will pull all scores down, if worst cluster score is above 1, to guarantee maximum privilege by fitness.
  534.    -- If all clusters would have similar big score values, they would be choosen equally.
  535.    -- By shifting the scores making the last score be 1, other scores are always x-times higher than 1.
  536.  
  537.    Fitness=0
  538.    local k
  539.    for k=1,HerdSize do
  540.     ClusterScore2[k]=ClusterScore2[k]-FitnessOffset+1 -- Shift cluster score copy by offset to met condition
  541.    -- We can overwrite this table, because it is only needed for breeding, and it won't affect the original table.
  542.    -- Original score will remain untouched.
  543.     Fitness=Fitness+ClusterScore2[k] -- Calculate fitness by adding all scores (offset included)
  544.  
  545.    end -- k loop
  546.  
  547.    local k
  548.    for k=BreedFirst,BreedLast do
  549.     ClusterBreed(k,TimeStamp)
  550.    end -- k loop
  551. end -- function
  552.  
  553. function Roulette()
  554.  -- Returns a random cluster index (not slot), the better their score, the more often they will appear
  555.  local TValue=math.random()*(Fitness+1) -- Target fitness value, which will stop the wheel
  556.  local CValue=0 -- Current value, where single cluster points will be added
  557.  local Wheel=math.random(1,HerdSize) -- Random initial wheel position
  558.  repeat
  559.   Wheel=Wheel+1 -- Spin Wheel
  560.   if Wheel>HerdSize then Wheel=1 end -- If Wheel made a full turn, it starts at 1 again
  561.   CValue=CValue+ClusterScore2[ClusterPointer[Wheel]]
  562.   -- Increase current value by score of cluster at wheel position
  563.  until CValue>TValue
  564.  return Wheel
  565. end -- function
  566.  
  567. function ClusterBreed(indexClusterB,TimeStamp)
  568.  local indexClusterB=indexClusterB -- Target cluster
  569.  local TimeStamp=TimeStamp -- "birth date"
  570.  
  571.  local indexClusterA1 -- Source cluster 1
  572.  if Parent1isRoulette==false then
  573.    indexClusterA1=indexClusterB-BreedFirst+1 -- Choose best, starting with 1
  574.   else
  575.    indexClusterA1=Roulette() -- Choose one by fitness roulette, the better the score, the more often it can be chosen
  576.  end -- if Parent1isRoulette
  577.  
  578.  local indexClusterA2 -- Source cluster 2
  579.  if Parent2isRoulette==true then
  580.    repeat
  581.     indexClusterA2=Roulette() -- Choose one by fitness roulette, the better the score, the more often it can be chosen
  582.    until indexClusterA2~=indexClusterA1 -- clusters must be different
  583.   else
  584.    indexClusterA2=indexClusterA1+1 -- Take next to Parent 1
  585.    if indexClusterA2>HerdSize then indexClusterA2=1 end
  586.  end -- if Parent2isRoulette
  587.  
  588.  local ClusterB=ClusterPointer[indexClusterB] -- Fetch save slot for target cluster
  589.  local ClusterA1=ClusterPointer[indexClusterA1] -- Fetch load slot for source cluster 1
  590.  local ClusterA2=ClusterPointer[indexClusterA2] -- Fetch load slot for source cluster 2
  591.  
  592.  local OS="Breeding "..indexClusterA1.."("..ClusterA1..") and "..indexClusterA2.."("..ClusterA2..") to "..indexClusterB.."("..ClusterB..")"
  593.  print(OS)
  594.  
  595.  ClusterType[ClusterB]="breeded".."-"..TimeStamp
  596.  
  597.  ClusterDrift[ClusterB]=ClusterDrift2[ClusterA1]
  598.  
  599.   if ClusterBands>0 then -- We only need to copy if there are any bands
  600.    local CrossoverEnd
  601.    if MultiCrossOver== false then
  602.     CrossoverEnd=CreateCrossoverPoint(ClusterBands) -- Create
  603.     print("Band crossover point: ",CrossoverEnd) -- and show crossover point
  604.    end -- if MultiCrossOver
  605.  
  606.    ClusterSegA[ClusterB]={}
  607.    ClusterSegB[ClusterB]={}
  608.    ClusterLength[ClusterB]={}
  609.    ClusterStrength[ClusterB]={}
  610.  
  611.    local BandsChild
  612.    local l
  613.    for l=1,ClusterBands do -- Is crossover point reached?
  614.     if CrossOverCheck(CrossoverEnd,l) then
  615.       BandsChild=ClusterA2 -- Take mom after crossover point
  616.      else
  617.       BandsChild=ClusterA1 -- Take dad until crossover point
  618.     end -- if CrossoverEnd
  619.     ClusterSegA[ClusterB][l]=ClusterSegA2[BandsChild][l]
  620.     ClusterSegB[ClusterB][l]=ClusterSegB2[BandsChild][l]
  621.     ClusterLength[ClusterB][l]=ClusterLength2[BandsChild][l]
  622.     ClusterStrength[ClusterB][l]=ClusterStrength2[BandsChild][l]
  623.    end -- l loop
  624.   end -- if ClusterBands
  625.  
  626.   if ClusterFreezes>0 then -- We only need to copy if there are any freezes
  627.   local CrossoverEnd
  628.    if MultiCrossOver== false then
  629.     CrossoverEnd=CreateCrossoverPoint(ClusterFreezes) -- Create
  630.     print("Freeze crossover point: ",CrossoverEnd) -- and show crossover point
  631.    end -- if MultiCrossOver
  632.  
  633.    ClusterFreeze[ClusterB]={}
  634.  
  635.    local FreezesChild
  636.    local l
  637.    for l=1,ClusterFreezes do -- For all freezes
  638.     if CrossOverCheck(CrossoverEnd,l) then -- Is crossover point reached?
  639.       FreezesChild=ClusterA2 -- Take mom after crossover point
  640.      else
  641.       FreezesChild=ClusterA1 -- Take dad until crossover point
  642.     end -- if CrossoverEnd
  643.     ClusterFreeze[ClusterB][l]=ClusterFreeze2[FreezesChild][l]
  644.    end -- l loop
  645.   end -- if ClusterFreezes
  646.  
  647.   -- Cluster mutating starts here
  648.   -- Secondary cluster set not needed anymore
  649.   -- Mutation is directly performed on target cluster
  650.  
  651.   if ClusterBands>0 then
  652.   local l
  653.    for l=1,ClusterBands do
  654.     if puzzle_is_ligand==false then -- only on non-ligand-puzzles mutate segment A
  655.      if random_flag(DriftProb) then
  656.       ClusterSegA[ClusterB][l]=drift_segment(ClusterSegA[ClusterB][l],ClusterDrift[ClusterB])
  657.      end -- if random_flag
  658.     end -- if puzzle_is_ligand
  659.  
  660.     if random_flag(InvBProb) then
  661.      ClusterSegA[ClusterB][l]=-ClusterSegA[ClusterB][l] -- invert
  662.     end -- if random_flag
  663.  
  664.     repeat
  665.      if random_flag(DriftProb) then
  666.       ClusterSegB[ClusterB][l]=drift_segment(ClusterSegB[ClusterB][l],ClusterDrift[ClusterB])
  667.      end -- if random_flag
  668.      local Distance=index_distance(ClusterSegA[ClusterB][l],ClusterSegB[ClusterB][l])
  669.     until Distance>=MID_Game -- Segments must have a minimum index distance
  670.  
  671.     if random_flag(DriftProb) then -- mutation allowed
  672.      ClusterLength[ClusterB][l]=drift_band_attribute(ClusterLength[ClusterB][l],1,3,0,1,6)
  673.      -- change bandlength by value + or - randomly 10e-[1 to 3 randomly]
  674.      -- keep bandlength between 0 and 1
  675.      -- if error occurs, generate new bandstrength value with 6 decimal digits
  676.     end -- if random_flag
  677.  
  678.     if random_flag(DriftProb) then -- mutation allowed
  679.      ClusterStrength[ClusterB][l]=drift_band_attribute(ClusterStrength[ClusterB][l],1,3,MinBS,MaxBS,3)
  680.      -- change bandstrength by value + or - randomly 10e-[1 to 3 randomly]
  681.      -- keep bandstrength between MinBS and MaxBS
  682.      -- if error occurs, generate new bandlength value with 3 decimal digits
  683.     end -- if random_flag
  684.    end  -- l loop
  685.   end -- if ClusterBands
  686.  
  687.   if ClusterFreezes>0 then
  688.    local l
  689.    for l=1,ClusterFreezes do
  690.     if random_flag(DriftProb) then
  691.     ClusterFreeze[ClusterB][l]=drift_segment(ClusterFreeze[ClusterB][l],ClusterDrift[ClusterB])
  692.     end -- if random_flag
  693.  
  694.     if random_flag(InvFProb) then
  695.      ClusterFreeze[ClusterB][l]=-ClusterFreeze[ClusterB][l] -- invert
  696.     end -- if random_flag
  697.    end -- l loop
  698.   end -- if
  699. end -- function
  700.  
  701. function drift_segment(Segment,Drift)
  702.  local Drift=Drift
  703.  local Seg2=Segment
  704.  
  705.  local Seg2sgn=math.sgn(Seg2)
  706.  Seg2=math.abs(Seg2)+Drift
  707.  
  708.  if Seg2<1 then
  709.    Seg2=NumSegs
  710.   elseif Seg2>NumSegs then
  711.    Seg2=1
  712.  end -- if Seg2
  713.  
  714.  Seg2=Seg2*Seg2sgn
  715.  
  716.  return Seg2
  717. end -- function
  718.  
  719. function drift_band_attribute(Target,RndE1,RndE2,Min,Max,RndE3)
  720.  -- apply random drift on variable Target resulting Target2 (Target2=Target+random value)
  721.  -- drift value can be positive or negative
  722.  -- and is 10^-[RndE1 to RndE2 randomly]
  723.  -- for example if RndE1 is 1 and RndE2 is 3, resulting value can be 10^-1,10-2 or 10^-3
  724.  
  725.  -- If Min or Max is exceeded, value of Target2 is ring-wrapped (moebius transformation, no clamping):
  726.  -- If maximum is exceeded, the amount of exceedment (Target2-Value) is applied to minimum
  727.  -- If minimum is exceeded, the amount of exceedment (Target2-Value) is applied to maximum
  728.  
  729.  local Target2=Target
  730.  
  731.  local Target2=Target2+random_direction()*10^-math.random(RndE1,RndE2)
  732.  
  733.  if Target2>Max then
  734.    Target2=Min+(Target2-Max)
  735.   elseif Target2<Min then
  736.    Target2=Max+(Target2-Min)
  737.  end -- if Target2
  738.  
  739.  if Target2>Max or Target2<Min then
  740.   Target2=math.frandom(Min,Max,RndE3)
  741.  end -- if Target2
  742.  
  743.  return Target2
  744. end -- function
  745.  
  746. function CrossOverCheck(CrossoverEnd,Pos)
  747.  local CrossoverEnd=CrossoverEnd
  748.  local Pos=Pos
  749.  
  750.  if MultiCrossOver then
  751.    if random_flag(0.5) then
  752.      return true
  753.     else
  754.      return false
  755.    end -- if random_flag
  756.   else -- if MultiCrossOver is false
  757.    if Pos>CrossoverEnd then
  758.      return true
  759.     else
  760.      return false
  761.    end -- if Pos
  762.  end -- if
  763. end -- function
  764.  
  765. function random_flag(Prob)
  766.  -- Returns false or true randomly
  767.  -- how often true appears depends on probability Prob
  768.  local Prob=Prob
  769.  
  770.  if math.random()<Prob then
  771.    return true
  772.   else
  773.    return false
  774.  end -- if random
  775. end -- function
  776.  
  777. function random_direction()
  778.  -- returns either -1 or 1
  779.  return math.random(0,1)*2-1
  780. end -- function
  781.  
  782. function structure.WiggleBackbone(iter)
  783.  structure.WiggleAll(iter,true,false)
  784. end -- function
  785.  
  786. function structure.WiggleSidechains(iter)
  787.  structure.WiggleAll(iter,false,true)
  788. end -- function
  789.  
  790. function xtool(method,iter,tL2)
  791.   -- unifies score-conditional shake and wiggle into one function
  792.   local OS=""
  793.   local iter=iter
  794.   local tL2=tL2
  795.   if iter>0 then
  796.     OS="max iter:"..iter
  797.   end -- if
  798.   -- print("Method:",method," ",OS," threshold:",tL2)
  799.   local curr_iter=0
  800.   local exit_condition=false
  801.   repeat
  802.    curr_iter=curr_iter+1
  803.    -- print(" Testing with iterations: ",curr_iter)
  804.    local tempScore=current.GetEnergyScore()
  805.    if method=="s" then
  806.      structure.ShakeSidechainsAll(curr_iter)
  807.     elseif method=="wb" then
  808.      structure.WiggleBackbone(curr_iter)
  809.     elseif method=="ws" then
  810.      structure.WiggleSidechains(curr_iter)
  811.     else
  812.      structure.WiggleAll(curr_iter)
  813.    end -- if method
  814.    local tempScore2=current.GetEnergyScore()
  815.    local rDelta=(tempScore2-tempScore)/curr_iter
  816.    -- print(" Rel. change: ",rDelta," pts/iteration")
  817.    if curr_iter==iter then exit_condition=true end
  818.    if math.abs(rDelta)<tL2 then exit_condition=true end
  819.   until exit_condition==true
  820. end -- function
  821.  
  822. -- Inspired by vertex's blue fuse script
  823. -- You may want to tweak this function
  824.  
  825. function PinkFuse()
  826.     save.Quicksave(3) -- store state before fuse
  827.      print("Release 1")
  828.      behavior.SetClashImportance(0.1)
  829.      xtool("s",Shakes,ScoreThreshold)
  830.      BestScoreCheck()
  831.       behavior.SetClashImportance(0.7)
  832.       xtool("wa",Wiggles,ScoreThreshold)
  833.       BestScoreCheck()
  834.     FuseEnd()
  835.  
  836.     save.Quickload(3) -- load state before fuse
  837.      print("Release 2")
  838.      behavior.SetClashImportance(0.3)
  839.      xtool("s",Shakes,ScoreThreshold)
  840.      BestScoreCheck()
  841.       behavior.SetClashImportance(0.6)
  842.       xtool("wa",Wiggles,ScoreThreshold)
  843.       BestScoreCheck()
  844.     FuseEnd()
  845.  
  846.     save.Quickload(3) -- load state before fuse
  847.      print("Release 3")
  848.      behavior.SetClashImportance(0.5)
  849.      xtool("wa",Wiggles,ScoreThreshold)
  850.      BestScoreCheck()
  851.       behavior.SetClashImportance(1)
  852.       xtool("wa",Wiggles,ScoreThreshold)
  853.       BestScoreCheck()
  854.        behavior.SetClashImportance(0.7)
  855.        xtool("wa",Wiggles,ScoreThreshold)
  856.        BestScoreCheck()
  857.     FuseEnd()
  858.  
  859.     save.Quickload(3) -- load state before fuse
  860.      print("Release 4")
  861.      behavior.SetClashImportance(0.7)
  862.      xtool("wa",Wiggles,ScoreThreshold)
  863.      BestScoreCheck()
  864.       behavior.SetClashImportance(1)
  865.       xtool("wa",Wiggles,ScoreThreshold)
  866.       BestScoreCheck()
  867.        behavior.SetClashImportance(0.5)
  868.        xtool("wa",Wiggles,ScoreThreshold)
  869.        BestScoreCheck()
  870.     FuseEnd()
  871. end
  872.  
  873. function FuseEnd()
  874.     -- Fuse try finishing with CI=1
  875.     behavior.SetClashImportance(1)
  876.     xtool("wa",Wiggles,ScoreThreshold)
  877.     xtool("s",Shakes,ScoreThreshold)
  878.     xtool("wa",Wiggles,ScoreThreshold)
  879.     BestScoreCheck()
  880. end -- function
  881.  
  882. function BestScoreCheck()
  883.    local TempScore=current.GetEnergyScore()
  884.  
  885.    if LastBest then
  886.     if TempScore>ACS5 then
  887.      save.Quicksave(5) -- Set best cluster result for this generation
  888.      ACS5=TempScore
  889.      -- print("ACS5 is ",ACS5)
  890.     end -- if TempScore
  891.    end -- if LastBest
  892.  
  893.     if TempScore>ACS4 then
  894.      save.Quicksave(4) -- Set best cluster result for current cluster
  895.      ACS4=TempScore
  896.     end -- if TempScore
  897.  
  898.    if TempScore>BestScore then
  899.     -- recentbest.Save()
  900.     BestScore=TempScore
  901.     print("New best total score: ",BestScore)
  902.     BSChange=true
  903.    end -- if
  904. end -- function
  905.  
  906. function PullDownEqualResults()
  907.  print("Checking for double results")
  908.  -- Compare all cluster points with next in list
  909.  -- If next has the same score, move this cluster to end.
  910.  
  911.  local kEnd=HerdSize-1
  912.  local k
  913.  for k=1,kEnd do
  914.   while ClusterScore[ClusterPointer[k]]==ClusterScore[ClusterPointer[k+1]] do
  915.   -- If next has the same score
  916.    ClusterScore[ClusterPointer[k+1]]=ClusterScore[ClusterPointer[HerdSize]]-1
  917.    -- make its score more worse then the baddest cluster
  918.    SortHerd() -- so it is placed at the end when sorting by score
  919.   end -- while ClusterScore
  920.  end -- k
  921. end -- function
  922.  
  923. function InitializeClusterData()
  924.  ClusterScore={}
  925.  ClusterType={}
  926.  ClusterDrift={}
  927.  
  928.   ClusterSegA={}
  929.   ClusterSegB={}
  930.   ClusterLength={}
  931.   ClusterStrength={}
  932.  
  933.   ClusterFreeze={}
  934.  
  935.  ClusterPointer={}
  936.  local k
  937.  for k=1,HerdSize do
  938.   ClusterPointer[k]=k
  939.  end -- k
  940. end -- function
  941.  
  942. function PrintStartingTests()
  943.  print()
  944.  local OS=" "
  945.  if Runs==1 then
  946.    OS=OS.."1 run"
  947.   else
  948.    if Runs>1 then
  949.      OS=OS..Runs
  950.     else
  951.      OS=OS.."infinite"
  952.    end -- if
  953.    OS=OS.." runs"
  954.  end -- if
  955.  OS="Starting cluster tests for "..OS.."."
  956.  print(OS)
  957. end -- function
  958.  
  959. function select_close_ligand()
  960.  local LigandSegment=NumSegs+1
  961.  local k
  962.  for k=1,NumSegs do
  963.   if structure.GetDistance(k,LigandSegment)<=MutateLigandDistance then
  964.    selection.Select(k)
  965.    -- print(k," is close enough to ligand for mutating.")
  966.   end -- if get_segment_distance
  967.  end -- k loop
  968. end -- function
  969.  
  970. function SetRebuildWorst()
  971.  -- Acitvate rebuild worst if forced or condidtions are met
  972.  if RebuildForce==nil then
  973.    --[[
  974.    if BSChange then
  975.      RebuildWorst=false
  976.     else
  977.      RebuildWorst=true
  978.    end -- if BSChange
  979.    ]]--
  980.    RebuildWorst=BSValueCheck()
  981.   else
  982.    RebuildWorst=RebuildForce
  983.  end -- if RebuildForce
  984. end -- function
  985.  
  986. function BSValueCheck()
  987.  -- Returns true if current generation's best cluster didn't do much
  988.  local ChangeTooSmall=false
  989.  if BSValue>=0 then -- If last generation's best cluster score is better than at generation start
  990.    if BSValue<SCPT then -- but below limit
  991.     ChangeTooSmall=true
  992.    end -- if BSValue
  993.   else -- if BSValue<0  -- If last generation's best cluster score is not better than at generation start
  994.    if BSValue>SCNT then  -- but above limit
  995.     ChangeTooSmall=true
  996.    end -- if BSValue
  997.  end -- if BSValue
  998.  return ChangeTooSmall
  999. end -- function
  1000.  
  1001. function SetLSC(LSC)
  1002.  -- Changes first cluster to trest if forced or conditions are met
  1003.  local LSC=LSC
  1004.  if LSCForce==nil then
  1005.    if BSChange or BSValueCheck()==false then -- If there was a considerable change
  1006.      LSC=1 -- check all clusters again in next generation
  1007.     else -- If there was no considerable change
  1008.      LSC=LSC+1 -- increase start cluster for this generation (don't test best again)
  1009.      if LSC>BreedFirst then LSC=BreedFirst end -- but not further than BreedFirst
  1010.    end -- if BSChange
  1011.   else -- if LSCForce not nil
  1012.    LSC=LSCForce
  1013.  end -- if LSCForce
  1014.  return LSC
  1015. end -- function
  1016.  
  1017. function GAB()
  1018.  -- save.Quickload(1): Puzzle state at GAB Start
  1019.  -- save.Quickload(2): Puzzle state at generation start
  1020.  -- save.Quickload(3): Puzzle state at fuse start
  1021.  -- save.Quickload(4): Best result for current cluster
  1022.  -- save.Quickload(5): Best result for current generation
  1023.  
  1024.  print("Starting GAB-III.")
  1025.  print ("Minimum allowed bandlength: ",MinBL_Game)
  1026.  print ("Maximum allowed bandlength: ",MaxBL_Game)
  1027.  
  1028.  print ("Random seed is: ",RNDseed)
  1029.  math.randomseed(RNDseed) -- initialize random seed
  1030.  
  1031.  UseList=CheckUselist(UseList)
  1032.  shuffle2(ShuffleProb) -- Shuffle UseList and reset pointer
  1033.  
  1034.  InitializeClusterData()
  1035.  
  1036.  FillHerd(1,HerdSize,1) -- From 1 to HerdSize
  1037.  
  1038.  -- ShowHerd()
  1039.  
  1040.  band.DeleteAll() -- clean bands
  1041.  freeze.UnfreezeAll() -- and freezes
  1042.  behavior.SetClashImportance(1)
  1043.  selection.DeselectAll()
  1044.  recentbest.Save()
  1045.  
  1046.  save.Quicksave(1) -- Save initial puzzle state
  1047.  BestScore=current.GetEnergyScore() -- initialize best score (ACS1)
  1048.  
  1049.  PrintStartingTests(Runs)
  1050.  
  1051.  local LSC=1
  1052.  CRun=0 -- set CRun to 0, counting up after each cluster generation
  1053.  repeat
  1054.   CRun=CRun+1 -- Increase current run value
  1055.   if CRun>1 then
  1056.     if RecentHybrid>0 then -- If RecentHybrid>0, tweak RecentUse
  1057.      if (CRun-1)%RecentHybrid==0 then -- Each RecentHybrid runs
  1058.        RecentUse=true -- use recent best
  1059.       else -- If not
  1060.        RecentUse=false -- don't use recent best
  1061.      end -- if CRun
  1062.     end -- if RecentHybrid
  1063.     if LastBest==false then
  1064.       if RecentUse then
  1065.         print("Loaded recent best.")
  1066.         recentbest.Restore() -- Load best result so far
  1067.        else
  1068.         print("Loaded initial state.")
  1069.         save.Quickload(1) -- Load initial state
  1070.       end -- if RecentUse
  1071.      else -- if LastBest is true
  1072.       print("Loaded last generation's best.")
  1073.       save.Quickload(5) -- Load best cluster result of last generation
  1074.     end -- if LastBest
  1075.     SetRebuildWorst()
  1076.     LSC=SetLSC(LSC)
  1077.   end -- if CRun
  1078.  
  1079.   if RebuildWorstGen then -- If rebuild is requestet at geneartion start
  1080.    rebuild_worst() -- do it
  1081.   end
  1082.  
  1083.   BSChange=false -- Reset improvement information
  1084.  
  1085.   save.Quicksave(2) -- Set this state as start state for current generation
  1086.   ACS2=current.GetEnergyScore() -- Get score at start for this generation
  1087.   print()
  1088.   print("Score now: ",ACS2)
  1089.  
  1090.   local k2 -- Cluster counter (cluster number not in braces)
  1091.   for k2=LSC,HerdSize do
  1092.    local k=ClusterPointer[k2] -- fetch slot number(adress) resulting from k2 (cluster number in braces)
  1093.    print()
  1094.    local OS="Gen.:"..CRun.." cluster:"..k2.."("..k..")/"..HerdSize.." drift:"..ClusterDrift[k].." type:"..ClusterType[k]
  1095.    print(OS)
  1096.  
  1097.    if k2>LSC then
  1098.       -- print("Loaded Quicksave 1.")
  1099.       save.Quickload(2)
  1100.    end -- if k2
  1101.  
  1102.    band.DeleteAll() -- remove all bands, because recent best can contain some
  1103.    freeze.UnfreezeAll() -- and freezing to apply others
  1104.  
  1105.    if ClusterBands>0 then
  1106.     local l -- Band counter
  1107.     for l=1,ClusterBands do
  1108.      if ClusterSegA[k][l]>0 then
  1109.        band.AddBetweenSegments(ClusterSegA[k][l],ClusterSegB[k][l])
  1110.        local TempBandCount=band.GetCount()
  1111.        -- fetch current band number index to make setting its length and strength possible
  1112.  
  1113.        local Length=LengthWithFactor(ClusterSegA[k][l],ClusterSegB[k][l],ClusterLength[k][l])
  1114.        
  1115.        if (Mimic==false or l~=1) then -- If this is not a Mimic band
  1116.         if Length>structure.GetDistance(ClusterSegA[k][l],ClusterSegB[k][l]) then -- and random generated target length is bigger than actual distance
  1117.           Length=Length+BLchangeUpPush -- add push up value
  1118.           -- print("Pushed up.")
  1119.           if Length>MaxBL_Game then
  1120.            Length=MaxBL_Game
  1121.           end -- if >
  1122.          else -- if random generated target length is smaller or equal than actual distance
  1123.           Length=Length+BLchangeDownPush -- add push down value
  1124.           -- print("Pushed down.")
  1125.           if Length<MinBL_Game then
  1126.            Length=MinBL_Game
  1127.           end -- if <
  1128.         end -- if Length
  1129.        end -- if Mimic
  1130.        
  1131.        local Length1R=CutOff(ClusterLength[k][l],3) -- Cut after 3 decimal digits before displaying
  1132.        local Length2R=CutOff(Length,3) -- Cut after 3 decimal digits before displaying
  1133.  
  1134.        local OS="Band "..l..": "..ClusterSegA[k][l]..":"..ClusterSegB[k][l]
  1135.        OS=OS.." L:"..Length1R.."="..Length2R
  1136.        if ShowBF then
  1137.         OS=OS.." S:"..ClusterStrength[k][l]
  1138.        end -- if
  1139.        print(OS)
  1140.  
  1141.        band.SetGoalLength(TempBandCount,Length) -- Set current band length
  1142.        band.SetStrength(TempBandCount,ClusterStrength[k][l]) -- Set current band strength
  1143.  
  1144.       else -- if ClusterSegA[k][l] is <0, which means band is deactivated
  1145.       if ShowBF then
  1146.        local OS="Band "..l..": off"
  1147.        print(OS)
  1148.       end -- if
  1149.      end -- if ClusterSegA
  1150.     end -- l loop
  1151.    end -- if ClusterBands
  1152.  
  1153.    if RebuildWorstGen==false then rebuild_worst() end
  1154.  
  1155.    selection.DeselectAll() -- Before freezing, so we can select segments to freeze
  1156.  
  1157.    if ClusterFreezes>0 then -- if there are segments to freeze
  1158.     local l -- Freeze counter
  1159.     for l=1,ClusterFreezes do  -- select all segments to freeze
  1160.      if ClusterFreeze[k][l]>0 then
  1161.        if ShowBF then
  1162.         local OS="Freeze "..l..": "..ClusterFreeze[k][l]
  1163.         print(OS)
  1164.        end -- if
  1165.        selection.Select(ClusterFreeze[k][l])
  1166.       else
  1167.       if ShowBF then
  1168.        local OS="Freeze "..l..": off"
  1169.        print(OS)
  1170.       end -- if
  1171.      end -- if ClusterFreez
  1172.     end -- l loop
  1173.    end -- if ClusterFreezes
  1174.  
  1175.    if puzzle_is_ligand then -- if this is a ligand puzzle
  1176.      selection.Select(NumSegs+1) --  select ligand for freezing
  1177.      freeze.FreezeSelected(true,true) -- freeze backbone and sidechains
  1178.     else -- if this is not a ligand puzzle
  1179.       if ClusterFreezes>0 then -- but there are segments to freeze
  1180.        freeze.FreezeSelected(true,false) -- freeze backbone only
  1181.       end -- if ClusterFreezes
  1182.    end -- if puzzle_is_ligand
  1183.  
  1184.    if ConstantBands==true then
  1185.     add_constant_bands() -- You can add some bands or freezes in this routine, which should appear each try
  1186.    end -- if
  1187.  
  1188.    print("Pulling...")
  1189.    behavior.SetClashImportance(CI_pull)
  1190.    selection.SelectAll () -- Select all segments to wiggle
  1191.    structure.WiggleAll(PWiggles) -- Just a small pull
  1192.  
  1193.    band.DeleteAll() -- clean up bands before saving
  1194.    freeze.UnfreezeAll() -- clean up freezes before saving
  1195.  
  1196.    if LastBest then -- If LastBest Mode
  1197.     if k2==LSC then -- and this is the first try of current generation
  1198.      ACS5=current.GetEnergyScore()
  1199.      -- initialize current generation best score
  1200.     end -- if k2
  1201.    end -- if LastBest
  1202.  
  1203.    save.Quicksave(4) -- Initialize this state as reference for current cluster best score
  1204.    ACS4=current.GetEnergyScore() -- and initialize current cluster best score
  1205.    BestScoreCheck() -- raise BestScore ACS4, if result is better
  1206.  
  1207.    xMutate(Mutating1) -- including BestScoreCheck
  1208.  
  1209.    Release() -- including Fuse and BestScoreCheck
  1210.  
  1211.    xMutate(Mutating2) -- including BestScoreCheck
  1212.  
  1213.    ClusterScore[k]=ACS4-ACS2 -- Store best score minus start score for this try as cluster score
  1214.    print("Difference to start: ",ClusterScore[k])
  1215.   end -- k loop, take next cluster
  1216.  
  1217.   print()
  1218.   print("Sorting Cluster list by score")
  1219.   SortHerd() -- Sort herd by score difference
  1220.   ShowScoreList()
  1221.  
  1222.   BSValue=ClusterScore[ClusterPointer[1]] -- Fetch best score difference
  1223.  
  1224.   PullDownEqualResults() -- Move duplicate results to end of herd
  1225.  
  1226.   Breed(CRun+1) -- Range: BreedFirst to BreedLast
  1227.  
  1228.   if BSValueCheck() or BSValue<=0 then -- If generation's best cluster has low or negative score difference
  1229.    print("No or few improvement for this generation.")
  1230.    if HerdSize<IncHerdSize then -- and herd size increasing is allowed
  1231.     print("Increasing herd size.")
  1232.     local k
  1233.     for k=1,2 do -- Increase herd size by 2 individuums
  1234.      HerdSize=HerdSize+1 -- Increase herd size
  1235.      ClusterPointer[HerdSize]=HerdSize -- and number of cluster save slots; set them to its own value
  1236.     end -- k loop
  1237.     BreedLast=BreedLast+1 -- Increase breed slots by 1
  1238.    end -- if incHerdSize
  1239.   end -- if BSChange
  1240.  
  1241.   FillHerd(BreedLast+1,HerdSize,CRun+1)
  1242.   -- generate random clustes behind breeded ones
  1243.   -- ShowHerdShort()
  1244.  
  1245.  until CRun==Runs
  1246. end -- function GAB
  1247.  
  1248. function FactorByLength(SegA,SegB)
  1249.  -- As mimic doesn't use random band lengths (with random factor) but tries to imitate current puzzle state,
  1250.  -- we have not to generate but to calculate the factor value
  1251.  -- This is the opposite of function LengthWithFactor
  1252.  
  1253.  local Min=SpatLimit(SegA,SegB,BLchangeDown)
  1254.  local Max=SpatLimit(SegA,SegB,BLchangeUp)
  1255.  
  1256.  return (structure.GetDistance(SegA,SegB)-Min)/(Max-Min)
  1257. end -- function
  1258.  
  1259. function LengthWithFactor(SegA,SegB,Factor)
  1260.  -- Apply length factor to range between minimum allowed band length and maximum allowed band length
  1261.  -- Factor=0 results minimum allowed band length
  1262.  -- Factor=1 results maximum allowed band length
  1263.  
  1264.  local Min=SpatLimit(SegA,SegB,BLchangeDown)
  1265.  local Max=SpatLimit(SegA,SegB,BLchangeUp)
  1266.  
  1267.  -- local OS="Length range without push: "..CutOff(Min,3)..":"..CutOff(Max,3)
  1268.  -- print(OS)
  1269.  
  1270.  return Factor*(Max-Min)+Min
  1271. end -- function
  1272.  
  1273. function SpatLimit(SegA,SegB,Distance)
  1274.  
  1275.  local Distance2=structure.GetDistance(SegA,SegB)+Distance
  1276.  
  1277.  if Distance2<MinBL_Game then
  1278.    Distance2=MinBL_Game
  1279.   elseif Distance2>MaxBL_Game then
  1280.    Distance2=MaxBL_Game
  1281.  end -- if Distance2
  1282.  
  1283.  return Distance2
  1284. end -- funtction
  1285.  
  1286. function index_distance(SegA,SegB)
  1287.  -- Fetch segment index distance
  1288.  
  1289.  return math.abs(math.abs(SegA)-SegB)
  1290. end -- function
  1291.  
  1292. function Release()
  1293.   if Releasing then
  1294.     -- print("Score after pulling: ",ACS4)
  1295.     print("Releasing...")
  1296.     save.Quickload(4) -- load best cluster result so far
  1297.     selection.SelectAll ()
  1298.     if Fuse then
  1299.       PinkFuse() -- save.Quicksave(4), raise BestScore and ACS4, if result is better
  1300.      else
  1301.       behavior.SetClashImportance(1)
  1302.       structure.ShakeSidechainsAll(1)
  1303.       structure.WiggleAll(12)
  1304.       BestScoreCheck() -- save.Quicksave(4), raise BestScore and ACS4, if result is better
  1305.     end -- if fuse
  1306.    end -- if Releasing
  1307. end -- function
  1308.  
  1309. function rebuild_worst()
  1310.  if RebuildWorst then
  1311.   print("Rebuilding worst...")
  1312.   selection.DeselectAll()
  1313.  
  1314.   local WorstScore=current.GetSegmentEnergyScore(1)
  1315.   local WorstIndex=1
  1316.  
  1317.   local k
  1318.   for k=2,NumSegs do
  1319.    local SegmentScore=current.GetSegmentEnergyScore(k)
  1320.    if SegmentScore<WorstScore then
  1321.     WorstScore=SegmentScore
  1322.     WorstIndex=k
  1323.    end -- if SegmentScore
  1324.   end -- k
  1325.  
  1326.   if (WorstIndex-RebuildRange)<1 then
  1327.     WorstIndex=1+RebuildRange
  1328.    elseif (WorstIndex+RebuildRange)>NumSegs then
  1329.     WorstIndex=NumSegs-RebuildRange
  1330.   end -- if
  1331.  
  1332.   local SegA=WorstIndex-RebuildRange
  1333.   local SegB=WorstIndex+RebuildRange
  1334.  
  1335.   for k=SegA,SegB do
  1336.    selection.Select(k)
  1337.   end -- k loop
  1338.   structure.RebuildSelected(RebuildIter)
  1339.   selection.DeselectAll()
  1340.  end -- if RebuildWorst
  1341. end -- function
  1342.  
  1343. function xMutate(Mutating)
  1344.    if Mutating then
  1345.     save.Quickload(4) -- load best result for this cluster so far
  1346.     print("Mutating...")
  1347.     if puzzle_is_ligand then
  1348.       selection.DeselectAll() -- clear selection
  1349.       select_close_ligand() -- select all segments close as MutateLigandDistance or less to ligand
  1350.      else
  1351.       selection.SelectAll ()
  1352.     end -- if puzzle_is_ligand
  1353.     do_mutate(1)
  1354.     BestScoreCheck() -- Check if it made an improvement
  1355.    end -- if Mutating
  1356. end -- function
  1357.  
  1358. function detect_ligand(flag)
  1359.  --[[
  1360.  ligand puzzle detection
  1361.  normally, segments have a secondary structure of "E", "H" or "L"
  1362.  and they always have a spatial distance of about 3.75 to 3.85 to their next index neighbour.
  1363.  a ligand is more far away.
  1364.  
  1365.  this function should respond true if this is a ligand puzzle, and false if it is not.
  1366.  if flag is nil, ligand auto-detection is enabled, distance of last two segments is checked
  1367.  if flag is not nil, ligand auto-detection is disabled, result is flag
  1368.  
  1369.  It also returns the last segment index which is no ligand
  1370.  ]]--
  1371.  
  1372.  local flag=flag
  1373.  
  1374.  local LastPos=structure.GetCount() -- fetch very last segment index number
  1375.  
  1376.  if flag==nil then -- Only if flag is nil, detect if there is a ligand and change flag
  1377.    print("Detecting if there is a ligand.")
  1378.    local ss=structure.GetSecondaryStructure(LastPos)
  1379.    flag=not(ss=="L" or ss=="H" or ss=="E" )
  1380.    -- if last segment's ss is neither "l" nor "h" nor "e"
  1381.    flag=flag or (structure.GetDistance(LastPos-1,LastPos)>=3.9)
  1382.    -- or distance to second last segment is bigger or equal than 3.9
  1383.  end -- if
  1384.  
  1385.  local OS="This should be "
  1386.  if flag then
  1387.    OS=OS.."a"
  1388.    LastPos=LastPos-1
  1389.   else
  1390.    OS=OS.."no"
  1391.  end -- if flag
  1392.  OS=OS.." ligand puzzle."
  1393.  print(OS)
  1394.  
  1395.  return flag,LastPos
  1396. end -- function
  1397.  
  1398. function create_UseList(flag)
  1399.  -- Creates segment use list depending on which puzzle-type is there
  1400.  
  1401.  local flag=flag
  1402.  
  1403.  UseList={}
  1404.                       -- Initialize list of segments to use
  1405.                       -- UseList extensions (true) are applied to list, so multiple selected segments will appear more often
  1406.  if flag==false then -- If this is no ligand puzzle
  1407.    UseList=UseSegIRange(UseList,1,NumSegs,1,true)
  1408.                       -- Set every segment index from 1 to puzzle size as bandable
  1409.    UseList=Use_distance(UseList,0,8,10,1200,false)
  1410.                       -- Consider all segments which have min 10 to max 1200 neighbours
  1411.                       -- over a distance of 0 to 8 as non-solitary and remove them from list
  1412.    UseList=UseSegIRange(UseList,1,NumSegs,1,true)
  1413.                       -- Add a complete segment set again to make sure that distance check didn't erase all
  1414.    UseList=Use_ss(UseList,"L",true)
  1415.                       -- Add segments with this secondary structure
  1416.                         -- "L"=loop
  1417.                         -- "H"=helix
  1418.                         -- "E"=sheet
  1419.    -- UseList=UseSegIRange(UseList,1,NumSegs,2,false)
  1420.                       -- Set every 2nd segment index between 1 to puzzle size as not bandable, example
  1421.    -- UseList=UseSegIValues(UseList,{1;3;9},true)
  1422.                       -- Include these single segments as bandable, example
  1423.    -- UseList=UseSegIValues(UseList,{2;5;10},false)
  1424.                       -- Exclude these single segments as bandable, example
  1425.    -- UseList=Use_aa(UseList,{"g";"a"},true)
  1426.                       -- Set this amino acid as bandable, example
  1427.   else -- If this is a ligand puzzle
  1428.    UseList=Use_close_ligand(UseList,20,true)
  1429.                       -- Set segments which have a maximum spatial distance of 20 to ligand as bandable
  1430.  end -- if flag
  1431. end -- function
  1432.  
  1433. function LastBandLengthStrength(Length,Strength)
  1434.  -- sets length and strength of the very last band to default values
  1435.  local TempBandCount=band.GetCount()
  1436.  band.SetGoalLength(TempBandCount,Length)
  1437.  band.SetStrength(TempBandCount,Strength)
  1438. end -- function
  1439.  
  1440. function add_constant_bands()
  1441.  -- Add some constant bands to fix parts of the puzzle here
  1442.  -- and/or freeze some parts
  1443.  
  1444.  band.AddBetweenSegments(40,15)
  1445.  LastBandLengthStrength(5,0.1)
  1446.  
  1447.  --[[
  1448.  selection.DeselectAll()
  1449.  for k=10,11 do
  1450.   selection.Select(k)
  1451.  end -- k
  1452.  freeze.FreezeSelected(true,false)
  1453.  ]]--
  1454. end -- function
  1455.  
  1456.  Runs=0
  1457.                      -- Number of runs (generations), integer value
  1458.                        -- Set to <1 to run infinitely
  1459.  puzzle_is_ligand,NumSegs=detect_ligand()
  1460.                      -- puzzle_is_ligand: Ligand flag, boolean value
  1461.                        -- true for ligand puzzle
  1462.                        -- false for non-ligand-puzzle
  1463.                      -- NumSegs: Last segment index which is no ligand, integer value
  1464.                      -- detect_ligand(): Ligand auto detection.
  1465.                        -- If it fails, use detect_ligand(true) to declare that this is a ligand puzzle
  1466.                        -- and detect_ligand(false) to declare that this is a no ligand puzzle
  1467.  create_UseList(puzzle_is_ligand)
  1468.                       -- Initialize segment working list
  1469.                       -- Depending on puzzle type
  1470.                       -- Advanced Users: see function create_UseList for description of uselist creating features
  1471.  MID_Game=3
  1472.                        -- Minimum index distance of segment indices, integer value >=2
  1473.                        -- As the game doesn't allow banding the segments with themselves or the nearest neighbour,
  1474.                        -- This value is needed to prevent game errors,
  1475.                        -- but you can also use it to prevent sharp backbone turns.
  1476.  MinBL_Game=3.8
  1477.                        -- Minimum band length limiter, float value >=0 and <=MaxBL_Game
  1478.                        -- Opposite of MaxBL_Game
  1479.                        -- Prevents bands getting too short
  1480.  MaxBL_Game=10000
  1481.                        -- Maximum band length limiter, float value <=10000 and >=MinBL_Game
  1482.                        -- In rough, values about 20 or lower tend to compress the puzzle, values above 20 allow decompressing (stretching)
  1483.                        -- Maximum expedient value for a puzzle is about (number of segments-1)*3.8,
  1484.                         -- which would stretch the region between connected segments completely out.
  1485.  BLchangeDown=-3.8*2
  1486.                        -- Maximum band change down, float value <=0
  1487.                        -- Generated bands are maximum this value shorter (plus BLchangeDownPush) than spatial distance of banded segments
  1488.  BLchangeDownPush=-3.8/2
  1489.                        -- Value added to BLchangeDown, float value <=0
  1490.                        -- This value is added to non-mimic bands to guarantee a certain change in length  
  1491.  BLchangeUp=3.8*1.5
  1492.                        -- Maximum band change up, float value >=0
  1493.                        -- Generated bands are maximum this value longer (plus BLchangeUpPush) than spatial distance of banded segments
  1494.  BLchangeUpPush=3.8/2
  1495.                        -- Value added to BLchangeUp, float value >=0
  1496.                        -- This value is added to non-mimic bands to guarantee a certain change in length
  1497.  BreedFirst=3
  1498.                       -- First cluster to change by breeding, integer value
  1499.                       -- All clusters before this index will be kept as good solution and as potential parents for breeding new solutions
  1500.                         -- Setting this to 1 is not a good idea, because you will loose good clusters
  1501.  BreedLast=5
  1502.                       -- Last cluster to change by breeding, integer value >=BreedFirst and <=HerdSize
  1503.                         -- Will be increased if no better solution was found
  1504.  HerdSize=8
  1505.                       -- Number of clusters, integer value >=BreedLast
  1506.                         -- Will be increased if no better solution was found
  1507.  IncHerdSize=16
  1508.                       -- Increase herdsize, integer value
  1509.                         -- Allows increasing the herdsize if no better solution was found (will generate more clusters)
  1510.                         -- if >HerdSize, allow increasing herdsize until this amount
  1511.                         -- if <=HerdSize, no increasing
  1512.  ShowBF=true
  1513.                       -- Shows band and freeze details, boolean value
  1514.                         -- if true (default), segments which are banded or frozen are shown by text
  1515.  ClusterBands=4
  1516.                       -- Maximum Bands to create per cluster, integer value >=0
  1517.  ClusterFreezes=3
  1518.                       -- Maximum segments to freeze by random, integer value >=0
  1519.  MinBS=0.8
  1520.                       -- Minimum strength per (random chosen) band, float value
  1521.                         -- Use decimal number between .1 and 10
  1522.  MaxBS=1.2
  1523.                       -- Minimum strength per (random chosen) band, float value
  1524.                         -- Use decimal number between .1 and 10 and >=MinBS
  1525.  Shakes=1
  1526.                       -- Number of iterations for fuse-shake, integer value
  1527.  Wiggles=4
  1528.                       -- Number of iterations for fuse-wiggle, integer value
  1529.  PWiggles=1
  1530.                       -- Number of iterations for pulling, integer value
  1531.  CI_pull=1
  1532.                       -- Clashing importance for pulling, float value >=0 and <=1
  1533.                         -- Default is 1
  1534.                         -- Reduce this to make pulling more drastic
  1535.  Releasing=true
  1536.                       -- Release flag, boolean value
  1537.                         -- true (default)= After pulling, releasing is performed.
  1538.                         -- false= releasing is skipped
  1539.  Fuse=true
  1540.                       -- Fuse flag, boolean value
  1541.                         -- true  (default)= After pulling, Fuse is performed.
  1542.                         -- false= after pulling, just a shake(1) and wiggle_all(12) with CI=1 is performed
  1543.  MutateLigandDistance=15
  1544.                       -- Radius length for selection sphere around ligand, where mutating is performed.
  1545.                         -- Selects only segments which are this or more close to the ligand for mutating.
  1546.  ScoreThreshold=0.5
  1547.                       -- Threshold value for shake and wiggles, float value >=0
  1548.                         -- This won't repeat some w/s, if absolute score change per itertation is below this
  1549.  MultiCrossOver=true
  1550.                       -- Multi crossover flag, boolean value
  1551.                         -- false (default)= One crossover point for each breeding is generated.
  1552.                         -- true= Each gene can be from mom or dad
  1553.  Parent1isRoulette=false
  1554.                       -- Roulette flag for breeding parent 1, boolean value
  1555.                         -- if false (default), parent is cluster with best score and downwards
  1556.                           -- use this to force good clusters for breeding
  1557.                         -- if true, parent is chosen by fitness roulette
  1558.  Parent2isRoulette=true
  1559.                       -- Roulette flag for breeding parent 2, boolean value
  1560.                       -- if true (default), parent is chosen by fitness roulette
  1561.                       -- if false, parent is next to parent 1
  1562.                         -- use this to force good clusters for breeding
  1563.  DriftProb=0.3
  1564.                       -- band drift (cluster mutation) probability, float value >=0 and <1
  1565.                         -- Probability, if drift is added or not
  1566.  InvBProb=0.2
  1567.                       -- Inverting (deactivating/reactivating) probability for bands, float value >=0 and <1
  1568.                         -- Makes inversion happen depending on this probability value
  1569.  InvFProb=0.3
  1570.                       -- Inverting (deactivating/reactivating) probability for freezes, float value >=0 and <1
  1571.                         -- Makes inversion happen depending on this probability value
  1572.  ShuffleProb=0.9
  1573.                       -- Shuffle rate, float value >=0 and <=1
  1574.                         -- Used to scramble random segment list, where bands are applied
  1575.                         -- 0 lets the list be as it is
  1576.                         -- 1 swaps all list entries with a random one behind them in list
  1577.  RecentUse=true
  1578.                         -- recent best flag, boolean value
  1579.                           -- true= recent best is used for each generation
  1580.                           -- false= initial state is used for each generation
  1581.                             -- prevents getting stuck on local maximum (recommended for endgame)
  1582.                           -- If using RecentHybrid or LastBest, this value is ignored
  1583.  RecentHybrid=0
  1584.                         -- Hybrid behaviour between RecentUse=false/true, integer value >=0
  1585.                           -- If ==0, regular behaviour as set in RecentUse
  1586.                           -- If >0, recent best is used only all RecentHybrid's generations
  1587.                            -- (counting from generation 2)
  1588.                           -- 1 would have the same effect as RecentUse=true
  1589.                           -- I recommend values>=2 when using it
  1590.  LastBest=false
  1591.                         -- Flag for using best cluster of current generation, boolean value
  1592.                         -- Default is false
  1593.                         -- If true, neither recent best nor initial puzzle state are loaded, but best result of current generation,
  1594.                         -- allowing unimproving the puzzle to get out of local maximum
  1595.                         -- Try this, you are really stuck on a puzzle.
  1596.  LSCForce=nil
  1597.                        -- Loop start cluster force flag, integer value
  1598.                          -- If nil (default), best clusters will only be tested again
  1599.                            -- if there was an improvement in last generation
  1600.                          -- If >0, start at this cluster after first generation
  1601.                            -- If 1, test all clusters again (also good ones)
  1602.                            -- If BreedFirst, test only new generated clusters
  1603.  SCPT=1
  1604.                         -- Score change positive tolerance, float value >=0
  1605.                           -- Activates rebuild (if allowed)
  1606.                           -- if current generation start score and best cluster score difference
  1607.                           -- is below this positive value (not good enough)
  1608.  SCNT=-10
  1609.                         -- Score change negative tolerance, float value <=0
  1610.                           -- Activates rebuild (if allowed)
  1611.                           -- if current generation start score and best cluster score difference
  1612.                           -- is above this negative value (not bad enough)
  1613.  RebuildWorstGen=true
  1614.                         -- Rebuild worst at generation start flag, boolean value
  1615.                           -- If true, rebuild worst is executed once for current generation
  1616.                           -- If false, rebuild worst is executed for each cluster (not recommended)
  1617.                           -- If nil, rebuild is never executed.
  1618.  RebuildWorst=false
  1619.                         -- Rebuild flag at script start, boolean value
  1620.                           -- If true,
  1621.                           -- rebuild is executed in first generation
  1622.  RebuildForce=nil
  1623.                         -- Force RebuildWorst, boolean value
  1624.                         -- Sets how RebuildWorst is changed.
  1625.                           -- If nil (default), worst segment is only rebuilt
  1626.                             -- if there was no improvement in last generation
  1627.                           -- If true, worst segment is always rebuilt before pulling
  1628.                           -- If false, worst segment is never rebuilt before pulling
  1629.  RebuildRange=2
  1630.                         -- Rebuild range, integer value>=1
  1631.                           -- For example, if 1 and worst segment is 3, segments from 2 to 4 are rebuilt.
  1632.                           -- if 2 and worst segment is 3, segments from 1 to 5 are rebuilt.
  1633.  RebuildIter=1
  1634.                       -- Iterations for rebuild worst, integer value>0
  1635.  Mutating1=puzzle_is_ligand
  1636.                       -- if true, puzzle segment mutating after pulling is performed
  1637.  Mutating2=false
  1638.                       -- if true, puzzle segment mutating after releasing is performed
  1639.  ConstantBands=false
  1640.                       -- Add constant bands flag, boolean value
  1641.                         -- if true, adds user-defined bands and freezes of add_constant_bands function above
  1642.                         -- before regular test-cluster is applied
  1643.  Mimic=false
  1644.                         -- Mimic flag, boolean value
  1645.                           -- if true, first cluster tries to imitate initial puzzle state
  1646.  RNDseed=os.time()
  1647.                       -- Random Seed
  1648.                         -- Here, the initial value is set to system time, so we get different random numbers
  1649.                         -- for each PC and each time the script is started.
  1650.                         -- If you want the same numbers (for testing purposes/results), take an arbitrary constant value.
  1651. GAB()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement