func (g *Genome) mutateAddNode(innovations InnovationsObserver, nodeIdGenerator network.NodeIdGenerator, opts *neat.Options) (bool, error) {
	if len(g.Genes) == 0 {
		return false, nil  
	}
	found := false
	var gene *Gene
	if len(g.Genes) < 15 {
		for _, gn := range g.Genes {
			if gn.IsEnabled && gn.Link.InNode.NeuronType != network.BiasNeuron && rand.Float32() >= 0.3 {
				gene = gn
				found = true
				break
			}
		}
	} else {
		tryCount := 0
		for tryCount < 20 && !found {
			geneNum := rand.Intn(len(g.Genes))
			gene = g.Genes[geneNum]
			if gene.IsEnabled && gene.Link.InNode.NeuronType != network.BiasNeuron {
				found = true
			}
			tryCount++
		}
	}
	if !found || gene == nil {
		return false, nil
	}
	gene.IsEnabled = false
	link := gene.Link
	oldWeight := link.ConnectionWeight
	trait := link.Trait
	inNode, outNode := link.InNode, link.OutNode
	if inNode == nil || outNode == nil {
		return false, fmt.Errorf("mutateAddNode: Anomalous link found with either IN or OUT node not set. %s", link)
	}
	var gene1, gene2 *Gene
	var node *network.NNode
	innovationFound := false
	for _, inn := range innovations.Innovations() {
		if inn.innovationType == newNodeInnType &&
			inn.InNodeId == inNode.Id &&
			inn.OutNodeId == outNode.Id &&
			inn.OldInnovNum == gene.InnovationNum {
			node = network.NewNNode(inn.NewNodeId, network.HiddenNeuron)
			node.Trait = g.Traits[0]
			gene1 = NewGeneWithTrait(trait, 1.0, inNode, node, link.IsRecurrent, inn.InnovationNum, 0)
			gene2 = NewGeneWithTrait(trait, oldWeight, node, outNode, false, inn.InnovationNum2, 0)
			innovationFound = true
			break
		}
	}
	if !innovationFound {
		newNodeId := nodeIdGenerator.NextNodeId()
		node = network.NewNNode(newNodeId, network.HiddenNeuron)
		node.Trait = g.Traits[0]
		if activationType, err := opts.RandomNodeActivationType(); err != nil {
			return false, err
		} else {
			node.ActivationType = activationType
		}
		gene1Innovation := innovations.NextInnovationNumber()
		gene1 = NewGeneWithTrait(trait, 1.0, inNode, node, link.IsRecurrent, gene1Innovation, 0)
		gene2Innovation := innovations.NextInnovationNumber()
		gene2 = NewGeneWithTrait(trait, oldWeight, node, outNode, false, gene2Innovation, 0)
		innovation := NewInnovationForNode(inNode.Id, outNode.Id, gene1Innovation, gene2Innovation, node.Id, gene.InnovationNum)
		innovations.StoreInnovation(*innovation)
	} else if node != nil && g.hasNode(node) {
		neat.InfoLog(
			fmt.Sprintf("GENOME: Add node innovation found [%t] in the same genome [%d] for node [%d]\n%s",
				innovationFound, g.Id, node.Id, g))
		return false, nil
	}
	if node != nil && gene1 != nil && gene2 != nil {
		g.Genes = geneInsert(g.Genes, gene1)
		g.Genes = geneInsert(g.Genes, gene2)
		g.Nodes = nodeInsert(g.Nodes, node)
		return true, nil
	}
	return false, nil
}
This mutator adds a node to a Genome by inserting it in the middle of an existing link between two nodes.
This broken link will be disabled and now represented by two links with the new node between them.
The innovations list from population is used to compare the innovation with other innovations in the list and see
whether they match. If they do, the same innovation numbers will be assigned to the new genes. If a disabled link
is chosen, then the method just exits with false.
package genetics
import (
	"errors"
	"fmt"
	"github.com/yaricom/goNEAT/v2/neat"
	"github.com/yaricom/goNEAT/v2/neat/math"
	"github.com/yaricom/goNEAT/v2/neat/network"
	"math/rand"
)
func (g *Genome) mutateConnectSensors(innovations InnovationsObserver, _ *neat.Options) (bool, error) {
	if len(g.Genes) == 0 {
		return false, errors.New("genome has no genes")
	}
	sensors := make([]*network.NNode, 0)
	outputs := make([]*network.NNode, 0)
	for _, n := range g.Nodes {
		if n.IsSensor() {
			sensors = append(sensors, n)
		} else {
			outputs = append(outputs, n)
		}
	}
	disconnectedSensors := make([]*network.NNode, 0)
	for _, sensor := range sensors {
		connected := false
		for _, gene := range g.Genes {
			if gene.Link.InNode.Id == sensor.Id {
				connected = true
				break
			}
		}
		if !connected {
			disconnectedSensors = append(disconnectedSensors, sensor)
		}
	}
	if len(disconnectedSensors) == 0 {
		return false, nil
	}
	sensor := disconnectedSensors[rand.Intn(len(disconnectedSensors))]
	linkAdded := false
	for _, output := range outputs {
		found := false
		for _, gene := range g.Genes {
			if gene.Link.InNode == sensor && gene.Link.OutNode == output {
				found = true
				break
			}
		}
		if !found {
			var gene *Gene
			innovationFound := false
			for _, inn := range innovations.Innovations() {
				if inn.innovationType == newLinkInnType &&
					inn.InNodeId == sensor.Id &&
					inn.OutNodeId == output.Id &&
					!inn.IsRecurrent {
					gene = NewGeneWithTrait(g.Traits[inn.NewTraitNum], inn.NewWeight,
						sensor, output, false, inn.InnovationNum, 0)
					innovationFound = true
					break
				}
			}
			if !innovationFound {
				traitNum := rand.Intn(len(g.Traits))
				newWeight := float64(math.RandSign()) * rand.Float64() * 10.0
				nextInnovId := innovations.NextInnovationNumber()
				gene = NewGeneWithTrait(g.Traits[traitNum], newWeight, sensor, output,
					false, nextInnovId, newWeight)
				newInnovation := NewInnovationForLink(sensor.Id, output.Id, nextInnovId,
					newWeight, traitNum)
				innovations.StoreInnovation(*newInnovation)
			} else if gene != nil && g.hasGene(gene) {
				neat.InfoLog(
					fmt.Sprintf("GENOME: Connect sensors innovation found [%t] in the same genome [%d] for gene: %s\n%s",
						innovationFound, g.Id, gene, g))
				return false, nil
			}
			if gene != nil {
				g.Genes = geneInsert(g.Genes, gene)
				linkAdded = true
			}
		}
	}
	return linkAdded, nil
}
func (g *Genome) mutateAddLink(innovations InnovationsObserver, opts *neat.Options) (bool, error) {
	if g.Phenotype == nil {
		return false, errors.New("attempt to add link to genome with no phenotype")
	} else if len(g.Nodes) == 0 {
		return false, errors.New("genome has no nodes to be connected by new link")
	}
	nodesLen := len(g.Nodes)
	doRecur := false
	if rand.Float64() < opts.RecurOnlyProb {
		doRecur = true
	}
	firstNonSensor := 0
	for _, n := range g.Nodes {
		if n.IsSensor() {
			firstNonSensor++
		} else {
			break
		}
	}
	tryCount := 0
	var node1, node2 *network.NNode
	found := false
	for tryCount < opts.NewLinkTries {
		nodeNum1, nodeNum2 := 0, 0
		if doRecur {
			loopRecur := false
			if rand.Float64() > 0.5 {
				loopRecur = true
			}
			if loopRecur {
				nodeNum1 = firstNonSensor + rand.Intn(nodesLen-firstNonSensor)  
				nodeNum2 = nodeNum1
			} else {
				for nodeNum1 == nodeNum2 {
					nodeNum1 = rand.Intn(nodesLen)
					nodeNum2 = firstNonSensor + rand.Intn(nodesLen-firstNonSensor)  
				}
			}
		} else {
			for nodeNum1 == nodeNum2 {
				nodeNum1 = rand.Intn(nodesLen)
				nodeNum2 = firstNonSensor + rand.Intn(nodesLen-firstNonSensor)  
			}
		}
		node1 = g.Nodes[nodeNum1]
		node2 = g.Nodes[nodeNum2]
		linkExists := false
		if node2.IsSensor() {
			linkExists = true
		} else {
			for _, gene := range g.Genes {
				if gene.Link.InNode.Id == node1.Id &&
					gene.Link.OutNode.Id == node2.Id &&
					gene.Link.IsRecurrent == doRecur {
					linkExists = true
					break
				}
			}
		}
		if !linkExists {
			thresh := nodesLen * nodesLen
			count := 0
			recurFlag := g.Phenotype.IsRecurrent(node1.PhenotypeAnalogue, node2.PhenotypeAnalogue, &count, thresh)
			if count > thresh {
				if neat.LogLevel == neat.LogLevelDebug {
					neat.DebugLog(
						fmt.Sprintf("GENOME: LOOP DETECTED DURING A RECURRENCY CHECK -> "+
							"node in: %s <-> node out: %s", node1.PhenotypeAnalogue, node2.PhenotypeAnalogue))
				}
			}
			if (!recurFlag && doRecur) || (recurFlag && !doRecur) {
				tryCount++
			} else {
				tryCount = opts.NewLinkTries
				found = true
			}
		} else {
			tryCount++
		}
	}
	if node1 != nil && node2 != nil && found {
		var gene *Gene
		innovationFound := false
		for _, inn := range innovations.Innovations() {
			if inn.innovationType == newLinkInnType &&
				inn.InNodeId == node1.Id &&
				inn.OutNodeId == node2.Id &&
				inn.IsRecurrent == doRecur {
				gene = NewGeneWithTrait(g.Traits[inn.NewTraitNum], inn.NewWeight, node1, node2, doRecur, inn.InnovationNum, 0)
				innovationFound = true
				break
			}
		}
		if !innovationFound {
			traitNum := rand.Intn(len(g.Traits))
			newWeight := float64(math.RandSign()) * rand.Float64() * 10.0
			nextInnovId := innovations.NextInnovationNumber()
			gene = NewGeneWithTrait(g.Traits[traitNum], newWeight, node1, node2,
				doRecur, nextInnovId, newWeight)
			innovation := NewInnovationForRecurrentLink(node1.Id, node2.Id, nextInnovId,
				newWeight, traitNum, doRecur)
			innovations.StoreInnovation(*innovation)
		} else if gene != nil && g.hasGene(gene) {
			neat.InfoLog(
				fmt.Sprintf("GENOME: Mutate add link innovation found [%t] in the same genome [%d] for gene: %s\n%s",
					innovationFound, g.Id, gene, g))
			return false, nil
		}
		if gene != nil && gene.Link.InNode.Id == gene.Link.OutNode.Id && !doRecur {
			neat.WarnLog(fmt.Sprintf("Recurent link created when recurency is not enabled: %s", gene))
			return false, fmt.Errorf("wrong gene created\n%s", g)
		}
		if gene != nil {
			g.Genes = geneInsert(g.Genes, gene)
		}
	}
	return found, nil
}