1. Between two commas called a parentpart
2. Some parentparts from parent1 and parent2 become a group
3. A group decides an offspringpart
package main
import (
	"bufio"
	"fmt"
	"log"
	"math/rand"
	"os"
	"time"
)
// substringBetweenCommas extracts substring between nth and mth commas (1-based)
func substringBetweenCommas(line string, nth, mth int) (string, error) {
	if nth >= mth {
		return "", fmt.Errorf("invalid indices: nth >= mth")
	}
	commas := []int{}
	for i, c := range line {
		if c == ',' {
			commas = append(commas, i)
		}
	}
	// Check if having enough commas
	if mth > len(commas) {
		return "", fmt.Errorf("not enough commas")
	}
	start := 0
	if nth > 0 {
		// +1 to skip comma itself
		start = commas[nth-1] + 1
	}
	end := commas[mth-1]
	if start > end || start > len(line) || end > len(line) {
		return "", fmt.Errorf("invalid substring indices")
	}
	return line[start:end], nil
}
// pickOffspringParts picks offspring parts from parents with ensured swapping
func pickOffspringParts(p1G, p1g, p2G, p2g string) (string, string) {
	if rand.Intn(2) == 0 {
		if rand.Intn(2) == 0 {
			return p1G, p2G
		}
		return p1G, p2g
	}
	if rand.Intn(2) == 0 {
		return p2G, p1G
	}
	return p2G, p1g
}
// extractParts extracts multiple parts between specified comma indexes
func extractParts(line string, pairs [][2]int) ([]string, error) {
	parts := make([]string, 0, len(pairs))
	for _, pair := range pairs {
		part, err := substringBetweenCommas(line, pair[0], pair[1])
		if err != nil {
			return nil, err
		}
		parts = append(parts, part)
	}
	return parts, nil
}
func main() {
	rand.Seed(time.Now().UnixNano())
	filePath := "CharacterAppearanceData.txt"
	// lines to grab (1-based lines)
	lines, err := readLines(filePath)
	if err != nil {
		log.Fatal(err)
	}
	if len(lines) < 2 {
		log.Fatal("File must have at least two lines")
	}
	// Pick two distinct random lines
	i1 := rand.Intn(len(lines))
	i2 := rand.Intn(len(lines) - 1)
	if i2 >= i1 {
		i2++
	}
	line1 := lines[i1]
	line2 := lines[i2]
	fmt.Printf("Selected lines: %d and %d\n\n", i1+1, i2+1)
	fmt.Printf("Line %d: %s\nLine %d: %s\n\n", i1+1, line1, i2+1, line2)
	// Comma index pairs to extract for each group
	groups := [][2]int{{1, 2}, {2, 3}, {3, 4}, {4, 5}}
	// Example: extract parts between 1th-2th commas and 2th-3th commas
	parts1, err := extractParts(line1, groups)
	if err != nil {
		log.Fatalf("Error extracting parts from line %d: %v", i1+1, err)
	}
	// Example: extract parts between 3th-4th commas and 4th-5th commas
	parts2, err := extractParts(line2, groups)
	if err != nil {
		log.Fatalf("Error extracting parts from line %d: %v", i2+1, err)
	}
	// Use pairs of parts from parents:
	// Example: select parts for offspring between 1th-2th commas and 2th-3th commas
	offspringPart1, offspringPart2 := pickOffspringParts(parts1[0], parts1[1], parts2[0], parts2[1])
	// Example: select parts for offspring between 3th-4th commas and 4th-5th commas
	offspringPart3, offspringPart4 := pickOffspringParts(parts1[2], parts1[3], parts2[2], parts2[3])
	fmt.Printf("Offspring parts 1 & 2: %s, %s\n", offspringPart1, offspringPart2)
	fmt.Printf("Offspring parts 3 & 4: %s, %s\n", offspringPart3, offspringPart4)
}
// readLines reads file lines into a slice
func readLines(filepath string) ([]string, error) {
	f, err := os.Open(filepath)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	var lines []string
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}
Edit it to make func pickOffspringParts more flexible, rather than fixed to two parentparts each from parent1 and parent2.