def addcombinationscheat(): for i in range(10): plant1index = random.randint(0, numberofshopplants - 1) plant2index = random.randint(0, numberofshopplants - 1) plant1 = shopplantlist[plant1index] plant2 = shopplantlist[plant2index] devprint("###### making cross between " + plant1.name + " and " + plant2.name) shopplantlist.append(makecross(plant1, plant2))
def crossnodes(nodes): def randnode(): return random.choice(nodes) # make a fresh plant node pnode = PlantNode([], 0, 0) attributes = dir(object.__getattribute__(nodes[0], "item")) # pick randomly in the attributes for attrkey in attributes: if attrkey[0] == '_': pass else: attr = getattr(randnode(), attrkey) newattr = None if attrkey == "children": newattr = [ ] # ignore children because we are only crossing two nodes elif attrkey == "plantshapelist": newattr, shapedonernode = combineshapes(nodes) else: newattr = attr pnode = pnode.destructiveset(attrkey, newattr) #### hand tuned attributes, which override the randomly picked ones above # chance to pick difference nodes for the repeat numbers if random.random() < 0.01: devprint("repeat nums from different nodes") pnode = pnode.destructiveset( "repeatnumseparate", nodes[random.randint(0, len(nodes) - 1)].repeatnumseparate) pnode = pnode.destructiveset( "repeatnumcircle", nodes[random.randint(0, len(nodes) - 1)].repeatnumcircle) else: repeatnumindex = random.randint(0, len(nodes) - 1) pnode = pnode.destructiveset("repeatnumseparate", nodes[repeatnumindex].repeatnumseparate) pnode = pnode.destructiveset("repeatnumcircle", nodes[repeatnumindex].repeatnumcircle) return pnode
def random_node_at_layer(layerlists : List[List[List[PlantNode]]], layerindex, addedsofar : List[PlantNode]): devprint("random node at layer " + str(layerindex)) # sort by length so that we can access layers that exist layerlists = sorted(layerlists, key = len) maxlayer = len(layerlists[-1])-1 def random_node_from_layer(chosenlayerindex): # choose an i such that all the layers on i and over have enough layers i = 0 while len(layerlists[i])-1 < chosenlayerindex: i += 1 possibleplantlayerlists = layerlists[i:] possiblenodes = [] for plantlayerlist in possibleplantlayerlists: for potentialnode in plantlayerlist[chosenlayerindex]: if not potentialnode in addedsofar: possiblenodes.append(potentialnode) # if all of the nodes have been chosen before pick a new one if len(possiblenodes) == 0: return random.choice(random.choice(random.choice(possibleplantlayerlists))) else: return random.choice(possiblenodes) def random_node(): # most of the time pick from one of the same layer in the else random_layer = layerindex if layerindex > maxlayer: random_layer = random.randint(0, maxlayer) elif picknodeafterlayerchance(layerindex): # chance for after index random_layer = random.randint(layerindex, maxlayer) elif picknodebeforelayerp(layerindex): random_layer = random.randint(0, max(layerindex-1, 0)) return random_node_from_layer(random_layer) # chance to cross nodes chosen_node = None original_node = None if random.random() < crossnodeschance: devprint("crossing nodes") chosen_node = crossnodes([random_node(), random_node()]) else: original_node = random_node() chosen_node = copy.deepcopy(random_node()) # if layer index is one, usually make it point up, always fixes if angle offset is math.pi/2 or more, since that is horizontal if layerindex == 0: if random.random() < abs(chosen_node.angleoffset)/(math.pi/2): devprint("fixing first node's angle offset to be 0") chosen_node = chosen_node.destructiveset("angleoffset", 0) return chosen_node, original_node
def crossnodes(nodes): def randnode(): return random.choice(nodes) # make a fresh plant node pnode = PlantNode([], 0, 0) attributes = dir(object.__getattribute__(nodes[0], "item")) # pick randomly in the attributes for attrkey in attributes: if attrkey[0] == '_': pass else: attr = getattr(randnode(), attrkey) newattr = None if attrkey == "children": newattr = [] # ignore children because we are only crossing two nodes elif attrkey == "plantshapelist": newattr, shapedonernode = combineshapes(nodes) else: newattr = attr pnode = pnode.destructiveset(attrkey, newattr) #### hand tuned attributes, which override the randomly picked ones above # chance to pick difference nodes for the repeat numbers if random.random() < 0.01: devprint("repeat nums from different nodes") pnode = pnode.destructiveset("repeatnumseparate", nodes[random.randint(0, len(nodes)-1)].repeatnumseparate) pnode = pnode.destructiveset("repeatnumcircle", nodes[random.randint(0, len(nodes)-1)].repeatnumcircle) else: repeatnumindex = random.randint(0, len(nodes)-1) pnode = pnode.destructiveset("repeatnumseparate", nodes[repeatnumindex].repeatnumseparate) pnode = pnode.destructiveset("repeatnumcircle", nodes[repeatnumindex].repeatnumcircle) return pnode
def random_node_at_layer(layerlists: List[List[List[PlantNode]]], layerindex, addedsofar: List[PlantNode]): devprint("random node at layer " + str(layerindex)) # sort by length so that we can access layers that exist layerlists = sorted(layerlists, key=len) maxlayer = len(layerlists[-1]) - 1 def random_node_from_layer(chosenlayerindex): # choose an i such that all the layers on i and over have enough layers i = 0 while len(layerlists[i]) - 1 < chosenlayerindex: i += 1 possibleplantlayerlists = layerlists[i:] possiblenodes = [] for plantlayerlist in possibleplantlayerlists: for potentialnode in plantlayerlist[chosenlayerindex]: if not potentialnode in addedsofar: possiblenodes.append(potentialnode) # if all of the nodes have been chosen before pick a new one if len(possiblenodes) == 0: return random.choice( random.choice(random.choice(possibleplantlayerlists))) else: return random.choice(possiblenodes) def random_node(): # most of the time pick from one of the same layer in the else random_layer = layerindex if layerindex > maxlayer: random_layer = random.randint(0, maxlayer) elif picknodeafterlayerchance(layerindex): # chance for after index random_layer = random.randint(layerindex, maxlayer) elif picknodebeforelayerp(layerindex): random_layer = random.randint(0, max(layerindex - 1, 0)) return random_node_from_layer(random_layer) # chance to cross nodes chosen_node = None original_node = None if random.random() < crossnodeschance: devprint("crossing nodes") chosen_node = crossnodes([random_node(), random_node()]) else: original_node = random_node() chosen_node = copy.deepcopy(random_node()) # if layer index is one, usually make it point up, always fixes if angle offset is math.pi/2 or more, since that is horizontal if layerindex == 0: if random.random() < abs(chosen_node.angleoffset) / (math.pi / 2): devprint("fixing first node's angle offset to be 0") chosen_node = chosen_node.destructiveset("angleoffset", 0) return chosen_node, original_node
def randomcombinecolors(c1, c2): devprint("combine colors") weight1 = random.uniform(0, 1) return combinecolors(c1, c2, weight1)
def picknodebeforelayerp(currentlayer): pickp = random.random() < 0.02 + (currentlayer - 1) * 0.01 if pickp: devprint("Picking node before layer at layer " + str(currentlayer)) return pickp
def picknodeafterlayerchance(currentlayer): pickp = random.random() < 0.03 + min(currentlayer * 0.2, 0.25) if pickp: devprint("picking node after layer at layer " + str(currentlayer)) return pickp
def simulatedifficulty(subgrid, maxships, settings, pixelsize): result = simulatesmart(subgrid, maxships, settings, pixelsize) devprint(result) return result
def drawplant(head_node): devprint("drawing plant") surface = Surface((40, 43), SRCALPHA) rootpos = (surface.get_width()/2, surface.get_height()-3) # the stack has the node, the currentx, and the currenty for each node in it # currentx and currenty are without resizing of the surface stack = [] # keeps track of offset needed because of resizing the surface resizeoffset = (0, 0) for i in range(head_node.repeatnumseparate): stack.append(head_node) firstx = potwidth * random.random() * head_node.brancharea + rootpos[0] stack.append(firstx) stack.append(rootpos[1]) stack.append(math.pi/2) # base angle strait up to start with callcount = 0 while len(stack) != 0 and callcount < 1000: callcount += 1 base_angle = stack.pop() currenty = stack.pop() currentx = stack.pop() node = stack.pop() randomspacings = [0] spacingLength = 0 for i in range(node.repeatnumcircle-1): randomspacings.append(random.uniform(node.anglespace-node.anglevariance*node.anglespace, node.anglespace+node.anglevariance*node.anglespace)) spacingLength += randomspacings[i+1] startspacing = random.uniform(-node.anglevariance*node.anglespace, node.anglevariance*node.anglespace)/2 * random.choice((-1, 1)) # start angle so that it points up on average angle = base_angle + startspacing - (spacingLength/2) + node.angleoffset*random.choice((-1, 1)) # update the random spacing to be final angles for i in range(len(randomspacings)): angle = angle + randomspacings[i] randomspacings[i] = angle for i in range(node.repeatnumcircle): # draw all the plantshapes at this angle # pick a random angle out of the list angle = randomspacings.pop(random.randint(0, len(randomspacings)-1)) widthscalar = 1 + random.random()*node.widthvariance heightscalar = 1 + random.random()*node.heightvariance # now add the current node surface, mainltranslated, mainloffset, new_resize_offset = surface_with_node(surface, node, angle, (currentx, currenty), resizeoffset, widthscalar, heightscalar) resizeoffset = new_resize_offset # find the new currentx and currenty mainlistlen = len(mainltranslated) # add all the children at the current position for childnode in node.children: futureindexpositions = getfuturenodeindexpositions(childnode.repeatnumseparate, mainlistlen, childnode.brancharea, childnode.branchoffset) for i in range(childnode.repeatnumseparate): futurex = mainltranslated[futureindexpositions[i]][0]+mainloffset[0] futurey = mainltranslated[futureindexpositions[i]][1]+mainloffset[1] stack.append(childnode) stack.append(futurex) stack.append(futurey) futureangle = listangleatindex(mainltranslated, futureindexpositions[i]) stack.append(futureangle) finalsurfaceanchor = (rootpos[0] + resizeoffset[0], rootpos[1]+resizeoffset[1]) # draw dirt clumps at bottom clumpradius = 4 clumprange = 14 clumpnum = 4 for i in range(clumpnum): gfxdraw.filled_circle(surface, int(finalsurfaceanchor[0] + i * clumprange/clumpnum - clumprange/2)+1, int(finalsurfaceanchor[1]), int(random.uniform(clumpradius/3, clumpradius)), brighten(dirtcolor, -10)) return surface, finalsurfaceanchor
def simulatesmart(subgrid, loopcount, settings, pixelsize): # time increment will decide how quickly the ship moves, needs to be high enough to escape scroll timeincrement = (1000.0/basescrollspeed)/5 maxdeaths = int(subgrid.rect.w/pixelsize)*4 deathcount = 0 wincount = 0 game = GridGame([subgrid], Ship(), scrollgrowthrate = 0) # initialize variables used in the loop # positions in pixel coordinates oldx = None oldy = None xpos = None ypos = None time = None deaths = None direction = None for i in range(loopcount): direction = (1, 0) deaths = 0 xpos = 2 ypos = int((1/pixelsize - 1) * i/loopcount) oldx = xpos oldy = ypos time = 0 while True: # if you hit something, try again if game.gameoverp(time, settings, pixelsize, shippospixels = (xpos, ypos)): deathcount += 1 deaths += 1 if deaths > maxdeaths: break # was moving left or right if direction[1] == 0: if random.random() < 0.4: direction = (-direction[0], 0) else: direction = (0, random.choice((-1, 1))) elif direction[0] == 0: if random.random() < 0.1: direction = (-1, 0) elif random.random() < 0.7: direction = (1, 0) else: direction = (0, -direction[1]) # opposite verticle directio xpos = oldx ypos = oldy time -= timeincrement # win if made to the end if xpos*pixelsize >= subgrid.rect.w: # if it has, it made it wincount += 1 break # movement oldx = xpos oldy = ypos xpos += direction[0] ypos += direction[1] time += timeincrement devprint(wincount) devprint(deathcount) if deathcount == 0: return wincount else: return float(wincount)/deathcount
def picknodebeforelayerp(currentlayer): pickp = random.random() < 0.02 + (currentlayer-1)*0.01 if pickp: devprint("Picking node before layer at layer " + str(currentlayer)) return pickp
def picknodeafterlayerchance(currentlayer): pickp = random.random() < 0.03 + min(currentlayer*0.2, 0.25) if pickp: devprint("picking node after layer at layer " + str(currentlayer)) return pickp
def surface_with_node(surface, node, angle, offset_in, current_resize_offset, widthscalar, heightscalar): transformedlists = transformtopointlists(node.plantshapelist, node.shiftchance, angle, widthscalar, heightscalar) mainloffset = None mainltranslated = None def currentoffset(): return (offset_in[0] + current_resize_offset[0], offset_in[1] + current_resize_offset[1]) def surface_offset(pointlist_bounds): return Rect(currentoffset()[0]-node.anchor[0]+pointlist_bounds[0], currentoffset()[1]-node.anchor[1]+pointlist_bounds[1], pointlist_bounds.width, pointlist_bounds.height) # go through all the plantshapes and their corresponding transformed lists for i in range(len(transformedlists)): currentlist = transformedlists[i] bounds = getlistbounds(currentlist) # make the surface shape_surface = Surface((bounds.width, bounds.height), SRCALPHA) # translate points into this surface shiftedlist = offsetpointlist(currentlist, (-bounds[0], -bounds[1])) # draw the plant shape onto the new surface plantshape = node.plantshapelist[i] if plantshape.fillcolor != None: gfxdraw.filled_polygon(shape_surface, shiftedlist, plantshape.fillcolor) if plantshape.outlinecolor != None: gfxdraw.polygon(shape_surface, shiftedlist, plantshape.outlinecolor) # apply the texture if any for ptexture in plantshape.textures: addtexture(shape_surface, ptexture) # now check if resizing is needed newsurfacerect = surface.get_rect().union(surface_offset(bounds)) if not newsurfacerect == surface.get_rect(): new_surface = Surface((newsurfacerect.width, newsurfacerect.height), SRCALPHA) new_surface.blit(surface, (-newsurfacerect.x, -newsurfacerect.y)) current_resize_offset = (current_resize_offset[0]-newsurfacerect.x, current_resize_offset[1]-newsurfacerect.y) surface = new_surface devprint("Resized surface to " + str(new_surface.get_width()) + " by " + str(new_surface.get_height())) surface.blit(shape_surface, surface_offset(bounds)) # also save the first list for other nodes to go off of if i == 0: # save the offset of l without the resizing mainloffset = surface_offset(bounds) # also remove the current resize offset mainloffset = (mainloffset[0] - current_resize_offset[0], mainloffset[1]-current_resize_offset[1]) mainltranslated = shiftedlist return surface, mainltranslated, mainloffset, current_resize_offset
def drawplant(head_node): devprint("drawing plant") surface = Surface((40, 43), SRCALPHA) rootpos = (surface.get_width()/2, surface.get_height()-3) # the stack has the node, the currentx, and the currenty for each node in it # currentx and currenty are without resizing of the surface stack = [] # keeps track of offset needed because of resizing the surface resizeoffset = (0, 0) for i in range(head_node.repeatnumseparate): stack.append(head_node) firstx = potwidth * random.random() * head_node.brancharea + rootpos[0] stack.append(firstx) stack.append(rootpos[1]) stack.append(math.pi/2) # base angle strait up to start with callcount = 0 while len(stack) != 0 and callcount < 1000: callcount += 1 base_angle = stack.pop() currenty = stack.pop() currentx = stack.pop() node = stack.pop() randomspacings = [0] spacingLength = 0 for i in range(node.repeatnumcircle-1): randomspacings.append(random.uniform(node.anglespace-node.anglevariance*node.anglespace, node.anglespace+node.anglevariance*node.anglespace)) spacingLength += randomspacings[i+1] startspacing = random.uniform(-node.anglevariance*node.anglespace, node.anglevariance*node.anglespace)/2 * random.choice((-1, 1)) # start angle so that it points up on average angle = base_angle + startspacing - (spacingLength/2) + node.angleoffset*random.choice((-1, 1)) # update the random spacing to be final angles for i in range(len(randomspacings)): angle = angle + randomspacings[i] randomspacings[i] = angle for i in range(node.repeatnumcircle): # draw all the plantshapes at this angle # pick a random angle out of the list angle = randomspacings.pop(random.randint(0, len(randomspacings)-1)) widthscalar = 1 + random.random()*node.widthvariance heightscalar = 1 + random.random()*node.heightvariance # now add the current node surface, mainltranslated, mainloffset, new_resize_offset = surface_with_node(surface, node, angle, (currentx, currenty), resizeoffset, widthscalar, heightscalar) resizeoffset = new_resize_offset # find the new currentx and currenty mainlistlen = len(mainltranslated) # add all the children at the current position for childnode in node.children: futureindexpositions = getfuturenodeindexpositions(childnode.repeatnumseparate, mainlistlen, childnode.brancharea) for i in range(childnode.repeatnumseparate): futurex = mainltranslated[futureindexpositions[i]][0]+mainloffset[0] futurey = mainltranslated[futureindexpositions[i]][1]+mainloffset[1] stack.append(childnode) stack.append(futurex) stack.append(futurey) futureangle = listangleatindex(mainltranslated, futureindexpositions[i]) stack.append(futureangle) finalsurfaceanchor = (rootpos[0] + resizeoffset[0], rootpos[1]+resizeoffset[1]) # draw dirt clumps at bottom clumpradius = 4 clumprange = 14 clumpnum = 4 for i in range(clumpnum): gfxdraw.filled_circle(surface, int(finalsurfaceanchor[0] + i * clumprange/clumpnum - clumprange/2)+1, int(finalsurfaceanchor[1]), int(random.uniform(clumpradius/3, clumpradius)), brighten(dirtcolor, -10)) return surface, finalsurfaceanchor