package main
import (
"bufio"
"fmt"
"log"
"math/rand"
"os"
"strconv"
"time"
)
// getCommaPositions returns the slice of indices where commas occur in the line
func getCommaPositions(line string) []int {
var commas []int
for i := 0; i < len(line); i++ {
if line[i] == ',' {
commas = append(commas, i)
}
}
return commas
}
// substringBetweenCommasFast extracts substring between nth and mth commas (1-based), using cached comma positions
// Returns empty string if indices invalid.
func substringBetweenCommasFast(line string, commas []int, nth, mth int) (string, error) {
if nth >= mth {
return "", fmt.Errorf("invalid indices: nth >= mth")
}
if mth > len(commas) {
return "", fmt.Errorf("not enough commas: needed %d got %d", mth, len(commas))
}
start := 0
if nth > 0 {
start = commas[nth-1] + 1
}
end := commas[mth-1]
if start > end || start > len(line) || end > len(line) || start < 0 || end < 0 {
return "", fmt.Errorf("invalid substring indices")
}
return line[start:end], nil
}
// extractPartsFast extracts multiple parts given pairs of (nth, mth) comma indices, using cached comma positions
func extractPartsFast(line string, commas []int, pairs [][2]int) ([]string, error) {
parts := make([]string, len(pairs))
for i, pair := range pairs {
part, err := substringBetweenCommasFast(line, commas, pair[0], pair[1])
if err != nil {
return nil, err
}
parts[i] = part
}
return parts, nil
}
// pickOffspringParts1 picks offspring parts from parents with ensured swapping
func pickOffspringParts1(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
}
// pickOffspringParts2 picks offspring parts by selecting each part from either parent1 or parent2
func pickOffspringParts2(parent1Parts, parent2Parts []string) ([]string, error) {
if len(parent1Parts) != len(parent2Parts) {
return nil, fmt.Errorf("parent parts slices must have the same length")
}
offspringParts := make([]string, len(parent1Parts))
for i := range parent1Parts {
if rand.Intn(2) == 0 {
offspringParts[i] = parent1Parts[i]
} else {
offspringParts[i] = parent2Parts[i]
}
}
return offspringParts, nil
}
// produce offspring parts, 2 parts replaced by random int strings between 1-10 excluding parents' values
func offspringWithRandomExclusion(parent1Parts, parent2Parts []string) ([]string, error) {
if len(parent1Parts) != len(parent2Parts) {
return nil, fmt.Errorf("parent parts slices must have the same length")
}
n := len(parent1Parts)
if n < 2 {
return nil, fmt.Errorf("need at least two parts for replacement")
}
offspring := make([]string, n)
chosenRandomIdx := make(map[int]bool)
// randomly pick 2 distinct indexes to replace with random ints
perm := rand.Perm(n)
chosenRandomIdx[perm[0]] = true
chosenRandomIdx[perm[1]] = true
for i := 0; i < n; i++ {
if chosenRandomIdx[i] {
// parse parent parts to integers
p1v, err1 := strconv.Atoi(parent1Parts[i])
p2v, err2 := strconv.Atoi(parent2Parts[i])
// collect forbidden values (only if both parses succeeded)
forbidden := map[int]bool{}
if err1 == nil {
forbidden[p1v] = true
}
if err2 == nil {
forbidden[p2v] = true
}
var val int
tries := 0
// randomly select int 1-10 excluding forbidden
for {
val = rand.Intn(10) + 1
if !forbidden[val] {
break
}
tries++
if tries > 100 {
return nil, fmt.Errorf("cannot find suitable random integer excluding parents at index %d", i)
}
}
offspring[i] = strconv.Itoa(val)
} else {
// pick randomly parent1 or parent2 part for this index
if rand.Intn(2) == 0 {
offspring[i] = parent1Parts[i]
} else {
offspring[i] = parent2Parts[i]
}
}
}
return offspring, nil
}
// countLines quickly counts lines in file; only scanning once
func countLines(filepath string) (int, error) {
f, err := os.Open(filepath)
if err != nil {
return 0, err
}
defer f.Close()
scanner := bufio.NewScanner(f)
count := 0
for scanner.Scan() {
count++
}
return count, scanner.Err()
}
// getLineAt reads only the specified line (0-based) from the file
func getLineAt(filepath string, lineNum int) (string, error) {
f, err := os.Open(filepath)
if err != nil {
return "", err
}
defer f.Close()
scanner := bufio.NewScanner(f)
current := 0
for scanner.Scan() {
if current == lineNum {
return scanner.Text(), nil
}
current++
}
if err := scanner.Err(); err != nil {
return "", err
}
return "", fmt.Errorf("line %d not found", lineNum)
}
// findParents finds one parent1 line with (1,1) parts and one parent2 line with parts != (1,1)
func findParents(filePath string) (int, string, int, string, error) {
f, err := os.Open(filePath)
if err != nil {
return 0, "", 0, "", err
}
defer f.Close()
scanner := bufio.NewScanner(f)
var parent1Candidates []struct {
index int
line string
}
var parent2Candidates []struct {
index int
line string
}
lineNum := 0
for scanner.Scan() {
line := scanner.Text()
commas := getCommaPositions(line)
part1, err1 := substringBetweenCommasFast(line, commas, 1, 2)
part2, err2 := substringBetweenCommasFast(line, commas, 2, 3)
if err1 != nil || err2 != nil {
// skip malformed line
lineNum++
continue
}
if part1 == "1" && part2 == "1" {
parent1Candidates = append(parent1Candidates, struct {
index int
line string
}{lineNum, line})
} else {
parent2Candidates = append(parent2Candidates, struct {
index int
line string
}{lineNum, line})
}
lineNum++
}
if err := scanner.Err(); err != nil {
return 0, "", 0, "", err
}
if len(parent1Candidates) == 0 {
return 0, "", 0, "", fmt.Errorf("no parent1 line with parts (1,1) found")
}
if len(parent2Candidates) == 0 {
return 0, "", 0, "", fmt.Errorf("no parent2 line with parts != (1,1) found")
}
// pick random candidates from each
p1 := parent1Candidates[rand.Intn(len(parent1Candidates))]
p2 := parent2Candidates[rand.Intn(len(parent2Candidates))]
return p1.index, p1.line, p2.index, p2.line, nil
}
func main() {
rand.Seed(time.Now().UnixNano())
filePath := "CharacterAppearanceData.txt"
// Find parent1 and parent2 lines based on (1,1) condition
i1, line1, i2, line2, err := findParents(filePath)
if err != nil {
log.Fatalf("Error finding suitable parents: %v", err)
}
fmt.Printf("Selected Parent1 Line %d: %s\nSelected Parent2 Line %d: %s\n\n", i1+1, line1, i2+1, line2)
// Cache commas
c1 := getCommaPositions(line1)
c2 := getCommaPositions(line2)
// Comma index pairs to extract for first groups
groups := [][2]int{{1, 2}, {2, 3}, {3, 4}, {4, 5}}
// Example: extract parts between 1th-2th commas and 2th-3th commas
parts1, err := extractPartsFast(line1, c1, 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 := extractPartsFast(line2, c2, 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 := pickOffspringParts1(parts1[0], parts1[1], parts2[0], parts2[1])
// Example: select parts for offspring between 3th-4th commas and 4th-5th commas
offspringPart3, offspringPart4 := pickOffspringParts1(parts1[2], parts1[3], parts2[2], parts2[3])
fmt.Printf("Offspring parts between 1-2 commas, 2-3 commas: %s, %s\n", offspringPart1, offspringPart2)
fmt.Printf("Offspring parts between 3-4 commas, 4-5 commas: %s, %s\n", offspringPart3, offspringPart4)
// Next group: commas 33 to 41 inclusive
groups = [][2]int{{33, 34}, {34, 35}, {35, 36}, {36, 37},{37, 38}, {38, 39}, {39, 40}, {40, 41}}
// Example: extract parts between 33th-34th commas to 40th-41th commas
parts1, err = extractPartsFast(line1, c1, groups)
if err != nil {
log.Fatalf("Error extracting parts from parent1 line: %v", err)
}
parts2, err = extractPartsFast(line2, c2, groups)
if err != nil {
log.Fatalf("Error extracting parts from parent2 line: %v", err)
}
// Generate offspring parts with random exclusion as per your logic
offspringParts, err := offspringWithRandomExclusion(parts1, parts2)
if err != nil {
log.Fatalf("Error generating offspring parts: %v", err)
}
for i, part := range offspringParts {
fmt.Printf("Between commas %d-%d: %s\n", groups[i][0], groups[i][1], part)
}
}
Could you please modify and export the entire code so I can follow the instructions?
First of all, I need you to know that, for parent1, parent2 and their offspring,
the number between 5-6 commas stands for skinColorsR,
the number between 6-7 commas stands for skinColorsG,
the number between 7-8 commas stands for skinColorsB,
the number between 8-9 commas stands for skinColorsA.
The logic of generate offspring's (skinColorsR, skinColorsR, skinColorsB, skinColorsA) is randomly inherenting from parent1 or parent2, for example, if parent1's (skinColorsR, skinColorsR, skinColorsB, skinColorsA)=(0,0,0,0), parent2's (skinColorsR, skinColorsR, skinColorsB, skinColorsA)=(1,1,1,1), offspring's (skinColorsR, skinColorsR, skinColorsB, skinColorsA) should inherent from =(0,0,0,0) or (1,1,1,1). But it's not over yet.
Now, after the inherent from parents, if the offspring's (the number between 1-2 commas, the number between 2-3 commas) = (1,1), it should be adjusted the inherited value to the value that most closely color matches the Morandi color logic; if the offspring's (the number between 1-2 commas, the number between 2-3 commas) != (1,1) it should be adjusted the inherited value to the value that most closely color matches the Macaron color logic (and don't matches the Morandi color logic).
The Morandi color logic is (R,G,B,A)=(between 70 and 200 (inclusive),between 70 and 200 (inclusive),B between 70 and 200 (inclusive),255).
The Macaron color logic is (R,G,B,A)=(between 128 and 255,between 128 and 255,between 128 and 255,255).
After the adjustion, the adujustedR,G,B,A is the offspring's skinColorsR, skinColorsR, skinColorsB, skinColorsA).