Advertisement
Crashguard303

CG303 GAB+EO V5.40

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