def divideElement(el): mid = el.size/2 xList = el.bin[:mid] yList = el.bin[mid:] x = BinaryString(xList) y = BinaryString(yList) return [x,y]
def disturbPlusOne(x): xValue = x.binToInt() plusOne = BinaryString.newFromInt(xValue + 1) minusOne = BinaryString.newFromInt(xValue - 1) fitnessPlusOne = getElementFitness(plusOne) fitnessMinusOne = getElementFitness(minusOne) if fitnessMinusOne > fitnessPlusOne: return BinaryString.changeSize(minusOne, x.size) return BinaryString.changeSize(plusOne, x.size)
def getElementValueAndFitness(el): mid = el.size/2 maxValueBS = BinaryString([0] + (mid-1)*[1]) multiplier = 1.0/maxValueBS.binToInt() [x,y] = divideElement(el) xValue = abs(10 * x.binToInt() * multiplier) - 5 yValue = abs(10 * y.binToInt() * multiplier) - 5 value = f(xValue,yValue) return [xValue, yValue, value]
def populationFitnessCalculation(population): fitnessList = [] bestFitness = 0 bestIndex = 0 maxValueBS = BinaryString([0] + (population[0].size-1)*[1]) multiplier = 1.0/maxValueBS.binToInt() for i in range(len(population)): value = abs(population[i].binToInt() * multiplier) fitnessList.append(g(value)) if fitnessList[i] > bestFitness: bestFitness = fitnessList[i] bestIndex = i return [fitnessList, bestIndex]
def fitnessCalculation(population): fitnessList = [] bestFitness = 0 bestIndex = 0 for i in range(len(population)): fitnessList.append(zero.size - BinaryString.hammingDistance(zero, population[i])) if fitnessList[i] >= bestFitness: bestFitness = fitnessList[i] bestIndex = i return [fitnessList, bestIndex]
def populationFitnessCalculation(population): fitnessList = [] bestFitness = float('inf') bestIndex = 0 mid = population[0].size/2 maxValueBS = BinaryString([0] + (mid-1)*[1]) multiplier = 1.0/maxValueBS.binToInt() for i in range(len(population)): [x,y] = divideElement(population[i]) xValue = abs(10 * x.binToInt() * multiplier) - 5 yValue = abs(10 * y.binToInt() * multiplier) - 5 value = f(xValue,yValue) fitnessList.append(value) if fitnessList[i] < bestFitness: bestFitness = fitnessList[i] bestIndex = i return [fitnessList, bestIndex]
def crossover2by2(population, fitnessList): #Retorna a população sem alteração caso não deva fazer o crossover if not shouldCrossover: return population newPopulation = population #Para cada 2 individuos da população faça for i in range(0, len(population), 2): #Verifica se deve aplicar crossover para o par should = random() <= crossoverProbability if should: #Se sim, gera um ponto e cruza os indivíduos [x1,y1] = divideElement(population[i]) [x2,y2] = divideElement(population[i+1]) point1 = randint(crossoverRangeStart, crossoverRangeEnd) point2 = randint(crossoverRangeStart, crossoverRangeEnd) [crossX1, crossX2] = BinaryString.crossover(x1,x2,point1) [crossY1, crossY2] = BinaryString.crossover(y1,y2,point2) newPopulation[i] = BinaryString(crossX1.bin + crossY1.bin) newPopulation[i+1] = BinaryString(crossX2.bin + crossY2.bin) return newPopulation
def crossover2by2(population, fitnessList): #Retorna a população sem alteração caso não deva fazer o crossover if not shouldCrossover: return population newPopulation = population #Para cada 2 individuos da população faça for i in range(0, len(population), 2): #Verifica se deve aplicar crossover para o par should = random() <= crossoverProbability if should: #Se sim, gera um ponto e cruza os indivíduos point = randint(crossoverRangeStart, crossoverRangeEnd) [newPopulation[i], newPopulation[i+1]] = BinaryString.crossover(population[i],population[i+1],point) return newPopulation
def _Load(self, fobj): self._stream = BinaryString(fobj.read(), verbose=self._is_verbose) self._header = FileHeader(verbose=self._is_verbose) self._groundLevel = None self._rockLevel = None self._numTileOpts = -1 self._tileOptMap = None self._tileOpts = None self._totalTileOpts = 0 self._numWallOpts = -1 self._wallOptMap = None self._wallOpts = None self._totalWallOpts = 0 self._width = None self._height = None self.LoadMetadata() self.LoadCounts() self.LoadOpts() self.LoadReferencedWorld() self.GenerateTileTypes() self.LoadMapTiles(self._maxTilesX, self._maxTilesY)
# encoding: utf-8 from BinaryString import BinaryString from InputMethods import readIntMin, readIntInterval, readFloatInterval, readIntInterval, readOption, readFloat, secondsToString from NatureInspiredAlgorithms import geneticAlgorithm import matplotlib.pyplot as plt import time import math from random import random, randint from copy import deepcopy #DEFINIÇÃO DE CONSTANTES E VARIÁVEIS GLOBAIS zero = BinaryString([1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1]) withElitism = False shouldCrossover = False crossoverProbability = 0 crossoverRangeStart = 0 crossoverRangeEnd = zero.size - 1 shouldMutate = False mutationProbability = 0 #------------------------------------------------------- #DEFINIÇÃO DE FUNÇÕES #Calculo da aptidão da população def fitnessCalculation(population): fitnessList = [] bestFitness = 0 bestIndex = 0
def LoadMapTiles(self, width, height): self.verbose("Offset: %s" % (self._stream.get_pos(),)) data = zlib.decompress(self._stream.getContent(remainder=True), -15) stream = BinaryString(data) print(' '.join(hex(ord(c))[2:] for c in stream._content[stream._pos:stream._pos+32])) offsets = [0, 0, 0, 0, 0, 0] x, y = 0, 0 while y < height: while x < width: self.log(x, y, width, height, stream) assert x >= 0 header1 = stream.readByte() header2 = stream.readByte() if (header1 & 1) == 1 else 0 section = (header1 & 14) >> 1 hasOwnType = (section in (1, 2, 7)) tileIdx = 0 if hasOwnType: if (header1 & 16) != 16: tileIdx = stream.readByte() else: tileIdx = stream.readUInt16() light = 255 if (header1 & 32) != 32 else stream.readByte() rleType = ((header1 & 192) >> 6) rle = 0 if rleType == 1: rle = stream.readByte() elif rleType == 2: rle = stream.readInt16() else: rle = 0 self.rawset(x, y, (header1, header2, tileIdx, light, rle, section)) if section == 0: x += rle else: if section == 1: pass # tileIdx += posTileOpts elif section == 2: pass # tileIdx += posWallOpts elif section in (3, 4, 5): pass # tileIdx += num22 + section - 3 elif section == 6: pass #if y < self._groundLevel: # offset = num7 * y / self._groundLevel # tileIdx += num23 + offset; #else: # y = num26 #tile = [self._tileTypes[tileIdx], light, (header2 >> 1) & 31] tile = [tileIdx, light, (header2 >> 1) & 31] self.rawset(x, y, (header1, header2, tileIdx, light, rle, section)) # SetTile(x, y, tile) if light == 256: while rle > 0: x += 1 # SetTile(x, y, tile) self.rawset(x, y, (header1, header2, tileIdx, light, rle, section)) rle -= 1 else: while rle > 0: x += 1 tile[1] = stream.readByte() self.rawset(x, y, (header1, header2, tileIdx, light, rle, section)) # SetTile(x, y, tile) rle -= 1 x += 1 y += 1
class Map(object): LOOKUP_NONE = 0 LOOKUP_TILE = 1 LOOKUP_LIQUID = 2 LOOKUP_WALL = 3 LOOKUP_SKY = 4 LOOKUP_DIRT = 5 LOOKUP_ROCK = 6 def __init__(self, fname=None, fobj=None, verbose=False): self._header = None self.HeaderEmpty = 0 self.HeaderTile = 1 self.HeaderWall = 2 self.HeaderWater = 3 self.HeaderLava = 4 self.HeaderHoney = 5 self.HeaderHeavenAndHell = 6 self.HeaderBackground = 7 self.MaxTileOpts = 12 self.MaxWallOpts = 2 self.MaxLiquidTypes = 3 self.MaxSkyGradients = 256 self.MaxDirtGradients = 256 self.MaxRockGradients = 256 self.tileOptionCounts = [0]*419 self.tileLookup = [[None]*self.MaxTileOpts for _ in xrange(419)] self.liquidLookup = [None]*(self.MaxLiquidTypes+1) self.wallLookup = [[None]*self.MaxWallOpts for _ in xrange(225)] self.skyLookup = [None]*self.MaxSkyGradients self.dirtLookup = [None]*self.MaxDirtGradients self.rockLookup = [None]*self.MaxRockGradients self.colorLookup = [] self.skyGradient = ((50, 40, 255), (145, 185, 255)) self.dirtGradient = ((88, 61, 46), (37, 78, 123)) self.rockGradient = ((74, 67, 60), (53, 70, 97)) self.missingTiles = [] self.missingWalls = [] self._groundLevel = None self._rockLevel = None self._is_verbose = verbose self._raw_tiles = {} self._log = '' tileColors = list(csv.reader(open("MapTile_Colors.csv"))) for t,o,r,g,b in tileColors[1:]: t, o = int(t), int(o) r, g, b = int(r), int(g), int(b) self.tileLookup[t][o] = (r, g, b) liquidColors = list(csv.reader(open("MapTile_LiquidColors.csv"))) for t, r, g, b in liquidColors[1:]: t = int(t) r, g, b = int(r), int(g), int(b) self.liquidLookup[t+1] = (r, g, b) wallColors = list(csv.reader(open("MapTile_WallColors.csv"))) for t,o,r,g,b in wallColors[1:]: t, o = int(t), int(o) r, g, b = int(r), int(g), int(b) self.wallLookup[t][o] = (r, g, b) for i in range(1, IDs.Tile.Count): if set(self.tileLookup[i]) == set([None]): self.missingTiles.append(i) for i in range(1, IDs.Wall.Count): if set(self.wallLookup[i]) == set([None]): self.missingWalls.append(i) if fname is not None and fobj is not None: raise ValueError("fname and fobj are mutually exclusive") if fname is None and fobj is not None: self.Load(fobj) if fname is not None and fobj is None: self.Load(open(fname, 'r')) def GetLookup(self, lookup_id): lookups = { Map.LOOKUP_TILE: self.tileLookup, Map.LOOKUP_LIQUID: self.liquidLookup, Map.LOOKUP_WALL: self.wallLookup, Map.LOOKUP_SKY: self.skyLookup, Map.LOOKUP_DIRT: self.dirtLookup, Map.LOOKUP_ROCK: self.rockLookup} if lookup_id in lookups: return lookups[lookup_id] raise IndexError("Lookup ID %s invalid" % (lookup_id,)) def TileToLookup(self, tile, i=None, j=None, light=255, transparentTiles=False, transparentWalls=False, transparentLiquid=False, transparentBg=False): """ Returns which lookup table (see Map.LOOKUP_* constants), lookup index, and lookup option for the tile object given """ lookup, option = 0, 0 type = tile.Type wall = tile.Wall extra = 0 if tile.IsActive and \ type not in self.missingTiles and \ not transparentTiles: # Case 1: active tiles if type == IDs.Tile.RainbowBrick: extra = tile.TileColor if type == IDs.Tile.DemonAltar: if tile.U >= 54: option = 1 elif type == IDs.Tile.Sunflower: if tile.U < 34: option = 1 elif type == IDs.Tile.Pots: # these can't be factored by more than 2 (trust me, I tried) if tile.V < 144: option = 0 elif tile.V < 252: option = 1 elif tile.V < 360 or 900 < tile.V < 1008: option = 2 elif tile.V < 468: option = 3 elif tile.V < 576: option = 4 elif tile.V < 648: option = 5 elif tile.V < 792: option = 6 elif tile.V < 898: option = 8 elif tile.V < 1006: option = 7 elif tile.V < 1114: option = 0 elif tile.V < 1222: option = 3 else: option = 7 elif type == IDs.Tile.ShadowOrbs: if tile.U >= 36: option = 1 elif type == IDs.Tile.LongMoss: option = _clamp(tile.U / 22, 0, 5) elif type == IDs.Tile.SmallPiles: if tile.V < 18: u = tile.U / 18 if u < 6 or 28 <= u <= 32: option = 0 elif u < 22 or 33 <= u <= 35: option = 1 elif u < 28: option = 2 elif u < 48: option = 3 elif u < 54: option = 4 else: u = tile.U / 36 if u < 6 or 19 <= u <= 24 or u == 33 or 38 <= u <= 40: option = 0 elif u < 16: option = 2 elif u < 19 or 31 <= u <= 32: option = 1 elif u < 31: option = 3 elif u < 38: option = 4 elif type == IDs.Tile.LargePiles: u = tile.U / 54 if u < 7: option = 2 elif u < 22 or u in (33, 34, 35): option = 0 elif u < 25: option = 1 elif u == 25: option = 5 elif u < 32: option = 3 elif type == IDs.Tile.LargePiles2: u = tile.U / 54 if u < 3 or u in (14, 15, 16): option = 0 elif u < 6: option = 6 elif u < 9: option = 7 elif u < 14: option = 4 # the code literally has these two elif u < 18: option = 4 # the code literally has these two elif u < 23: option = 8 elif u < 25: option = 0 elif u < 29: option = 1 elif type in (IDs.Tile.ImmatureHerbs, IDs.Tile.MatureHerbs, IDs.Tile.BloomingHerbs): option = _clamp(tile.U / 18, 0, 6) elif type == IDs.Tile.AdamantiteForge: option = 1 if tile.U >= 52 else 0 elif type == IDs.Tile.MythrilAnvil: option = 1 if tile.U >= 28 else 0 elif type == IDs.Tile.PressurePlates: option = 1 if tile.U != 0 else 0 elif type == IDs.Tile.Painting3X3: u = tile.U / 54 + tile.V / 54 * 36 if 0 <= u <= 11 or 47 <= u <= 53: option = 0 elif 12 <= u <= 15 or 18 <= u <= 35: option = 1 elif 16 <= u <= 17: option = 2 elif 41 <= u <= 45: option = 3 elif u == 46: option = 4 elif type == IDs.Tile.Painting6X4: if 22 <= tile.V / 72 <= 24: option = 1 elif type == IDs.Tile.Torches: if tile.U < 66: pass # the decompiled code literally has this option = 0 elif type == IDs.Tile.Containers: u = tile.U / 36 if u in (1, 2, 10, 13, 15): # Gold Chest option = 1 elif u in (3, 4): # Shadow option = 2 elif u == 6: # Unknown option = 3 elif u in (11, 17): # Water option = 4 elif type == IDs.Tile.Statues: if 1548 <= tile.U <= 1654: option = 1 elif 1656 <= tile.U <= 1798: option = 2 elif type == IDs.Tile.HolidayLights: if j is not None: option = j % 3 elif type == IDs.Tile.RainbowBrick: if j is not None: option = j % 3 elif type == IDs.Tile.Stalactite: if tile.U < 54: option = 0 elif tile.U < 106 or tile.U >= 216: option = 1 elif tile.U >= 162: option = 3 else: option = 2 elif type == IDs.Tile.ExposedGems: option = _clamp(tile.U / 18, 0, 6) elif type == IDs.Tile.DyePlants: option = tile.U / 34; else: option = 0 assert option < len(self.tileLookup[tile.Type]) return Map.LOOKUP_TILE, tile.Type, option elif tile.LiquidType != Tile.LiquidType.None_ and \ tile.LiquidAmount > 32 and not transparentLiquid: # Case 2: inactive tiles with liquid return Map.LOOKUP_LIQUID, tile.LiquidType, 0 elif wall != 0 and \ wall not in self.missingWalls and \ not transparentWalls: # Case 3: walls extra = tile.WallColor if wall == IDs.Wall.Planked and i is not None: option = i % 2 elif wall in (IDs.Wall.PurpleStainedGlass, IDs.Wall.YellowStainedGlass, IDs.Wall.BlueStainedGlass, IDs.Wall.GreenStainedGlass, IDs.Wall.RedStainedGlass, IDs.Wall.Glass, IDs.Wall.Confetti): extra = 0 else: option = 0 return Map.LOOKUP_WALL, wall, option elif i is not None and j is not None and not transparentBg: # Case 4: inactive tiles with a gradient if j < self._groundLevel: return Map.LOOKUP_SKY, 0, 0 elif j < self._rockLevel: return Map.LOOKUP_DIRT, 0, 0 elif j < self._height - 204: return Map.LOOKUP_ROCK, 0, 0 else: return Map.LOOKUP_ROCK, 1, 0 return Map.LOOKUP_NONE, 0, 0 def DoColorLookup(self, key, lookup, option=0): "Usage: m.DoColorLookup(*m.TileToLookup(t, i, j))" result = None if key == Map.LOOKUP_NONE: result = None elif key == Map.LOOKUP_TILE: result = self.tileLookup[lookup][option] elif key == Map.LOOKUP_LIQUID: result = self.liquidLookup[lookup] elif key == Map.LOOKUP_WALL: result = self.wallLookup[lookup][option] elif key == Map.LOOKUP_SKY: result = self.skyGradient[lookup] elif key == Map.LOOKUP_DIRT: result = self.dirtGradient[lookup] elif key == Map.LOOKUP_ROCK: result = self.rockGradient[lookup] else: print("Invalid lookup: %s %s %s" % (key, lookup, option)) result = (255, 255, 255) return result def rawget(self): return self._raw_tiles def rawset(self, x, y, tile): self._raw_tiles[(x, y)] = tile def log(self, x, y, w, h, stream): self._log = "x:%d y:%d wxh: %dx%d pos: %d" % (x, y, w, h, stream.get_pos()) def verbose(self, *args): if self._is_verbose: for arg in args: sys.stderr.write("%s\n" % (arg,)) def Load(self, fobj): try: self._Load(fobj) except (IOError, EOFError, IndexError, AssertionError) as e: print(self._log) print(self._raw_tiles) raise def _Load(self, fobj): self._stream = BinaryString(fobj.read(), verbose=self._is_verbose) self._header = FileHeader(verbose=self._is_verbose) self._groundLevel = None self._rockLevel = None self._numTileOpts = -1 self._tileOptMap = None self._tileOpts = None self._totalTileOpts = 0 self._numWallOpts = -1 self._wallOptMap = None self._wallOpts = None self._totalWallOpts = 0 self._width = None self._height = None self.LoadMetadata() self.LoadCounts() self.LoadOpts() self.LoadReferencedWorld() self.GenerateTileTypes() self.LoadMapTiles(self._maxTilesX, self._maxTilesY) def LoadMetadata(self): self._header.Version = self._stream.readUInt32() self._header.MetaMagic = self._stream.readUInt64() self._header.MetaRevision = self._stream.readUInt32() self._header.WorldBits = self._stream.readUInt64() self._header.AssertValid() def LoadCounts(self): self._worldName = self._stream.readString() self._worldID = self._stream.readInt32() self._maxTilesY = self._stream.readInt32() self._maxTilesX = self._stream.readInt32() self._numTileOpts = self._stream.readInt16() self._numWallOpts = self._stream.readInt16() self._numLiquidOpts = self._stream.readInt16() self._numSkyOpts = self._stream.readInt16() self._numDirtOpts = self._stream.readInt16() self._numRockOpts = self._stream.readInt16() self._tileOptMap = self._stream.readBitArray(self._numTileOpts) self._wallOptMap = self._stream.readBitArray(self._numWallOpts) def LoadOpts(self): self._tileOpts = [1]*self._numTileOpts self._wallOpts = [1]*self._numWallOpts for i in range(self._numTileOpts): if self._tileOptMap[i]: self._tileOpts[i] = self._stream.readByte() self._totalTileOpts += self._tileOpts[i] self.verbose("read all tile opts") for i in range(self._numWallOpts): if self._wallOptMap[i]: self._wallOpts[i] = self._stream.readByte() self._totalWallOpts += self._wallOpts[i] self.verbose("read all wall opts") def FromWorld(self, world): self._world = world self._groundLevel = world.GetFlag('GroundLevel') self._rockLevel = world.GetFlag('RockLevel') self._width = world.Width() self._height = world.Height() def LoadReferencedWorld(self): w = World.World(load_tiles=False, load_chests=False, load_signs=False, load_npcs=False, load_tents=False) w.Load(open(World.World.FindWorld(worldid=self._worldID))) self._world = w self._groundLevel = w.GetFlag('GroundLevel') self._rockLevel = w.GetFlag('RockLevel') self._width = w.Width() self._height = w.Height() def GenerateTileTypes(self): self._tileTypes = [0]*(self._totalTileOpts + self._totalWallOpts + self._numLiquidOpts + self._numSkyOpts + self._numDirtOpts + self._numRockOpts + 2) self._tileTypes[0] = 0 self._posTileOpts = 0 self._posWallOpts = 0 self._posLiquidOpts = 0 self._posSkyOpts = 0 self._posDirtOpts = 0 self._posRockOpts = 0 #self._colorTypes = [(0, 0, 0, 0)]*len(self._numColors) self.verbose("Total tile types: %s" % (len(self._tileTypes),)) def LoadMapTiles(self, width, height): self.verbose("Offset: %s" % (self._stream.get_pos(),)) data = zlib.decompress(self._stream.getContent(remainder=True), -15) stream = BinaryString(data) print(' '.join(hex(ord(c))[2:] for c in stream._content[stream._pos:stream._pos+32])) offsets = [0, 0, 0, 0, 0, 0] x, y = 0, 0 while y < height: while x < width: self.log(x, y, width, height, stream) assert x >= 0 header1 = stream.readByte() header2 = stream.readByte() if (header1 & 1) == 1 else 0 section = (header1 & 14) >> 1 hasOwnType = (section in (1, 2, 7)) tileIdx = 0 if hasOwnType: if (header1 & 16) != 16: tileIdx = stream.readByte() else: tileIdx = stream.readUInt16() light = 255 if (header1 & 32) != 32 else stream.readByte() rleType = ((header1 & 192) >> 6) rle = 0 if rleType == 1: rle = stream.readByte() elif rleType == 2: rle = stream.readInt16() else: rle = 0 self.rawset(x, y, (header1, header2, tileIdx, light, rle, section)) if section == 0: x += rle else: if section == 1: pass # tileIdx += posTileOpts elif section == 2: pass # tileIdx += posWallOpts elif section in (3, 4, 5): pass # tileIdx += num22 + section - 3 elif section == 6: pass #if y < self._groundLevel: # offset = num7 * y / self._groundLevel # tileIdx += num23 + offset; #else: # y = num26 #tile = [self._tileTypes[tileIdx], light, (header2 >> 1) & 31] tile = [tileIdx, light, (header2 >> 1) & 31] self.rawset(x, y, (header1, header2, tileIdx, light, rle, section)) # SetTile(x, y, tile) if light == 256: while rle > 0: x += 1 # SetTile(x, y, tile) self.rawset(x, y, (header1, header2, tileIdx, light, rle, section)) rle -= 1 else: while rle > 0: x += 1 tile[1] = stream.readByte() self.rawset(x, y, (header1, header2, tileIdx, light, rle, section)) # SetTile(x, y, tile) rle -= 1 x += 1 y += 1
maxIt = readIntMin('\nNumero maximo de iteracoes do algoritmo: ', 1) maxItNoImprove = readIntMin('\nNumero maximo de iteracoes do algoritmo sem evoluir a aptidao: ', 1) multipleExecutions = readOption('\nDeseja executar diversas vezes com esse parametros para obter estatisticas? (s/n)\n','s','n') #Dobra o tamanho para considerar dois valores em um individuo stringSize = stringSize * 2 if multipleExecutions: n = readIntMin('Numero de execucoes do algoritmo: ', 1) itCountList = [] itAvgBestFitnessList = [] itFitnnesList = [] bestGeneAmongIts = BinaryString([0,1,0,1]) bestFitnessAmongIts = float('inf') gotToLimitIt = 0 print('\nExecutando...') start = time.time() nextPoint = 0 for i in range(n): population = [] for j in range(popSize): population.append(BinaryString.newRandom(stringSize)) [population, bestGene, bestFitness, lastFitnessList, lastBestGeneIndex, generationCount, avgFitnessList, bestFitnessList] = geneticAlgorithm(population, maxIt,rouletteWheelSelection, crossover2by2, mutate, populationFitnessCalculation, shouldStop, newFitnessIsBetter, maxItNoImprove) itCountList.append(generationCount) itFitnnesList.append(bestFitness) itAvgBestFitnessList.append(sum(bestFitnessList)/len(bestFitnessList))
def getElementValueAndFitness(x): maxValueBS = BinaryString([0] + (x.size-1)*[1]) multiplier = 1.0/maxValueBS.binToInt() value = abs(x.binToInt() * multiplier) return [value, g(value)]
def disturbMutating(x): newBinStr = BinaryString(x.bin) newBinStr.mutate(0.1) return newBinStr