package parser import ( "autobrew/action" "autobrew/ingredient" "autobrew/recipe" "autobrew/utils" "bufio" "io/fs" "log" "regexp" "strconv" "strings" ) var add_to_cauldron = regexp.MustCompile(`(?mi)^Add (\d+ .+)+? to the cauldron\.$`) var add_to_mortar = regexp.MustCompile(`(?mi)^Add (\d+ .+)+? to the mortar, grind, and pour into the cauldron\.$`) var boil = regexp.MustCompile(`(?mi)^Boil for (\d+) turn[s]*\.$`) var boil_bellows = regexp.MustCompile(`(?mi)^Boil for (\d+) turn[s]* using bellows\.$`) var extract_amount = regexp.MustCompile(`(?mi)^(\d+) (.*)$`) func transformStep(lines []string) (name string, steps []recipe.Step, err error) { name, lines = lines[0], lines[1:] var ingredients []ingredient.Ingredient for index, line := range lines { if strings.HasPrefix(line, "Liquid Base:") { i, err := ingredient.IngredientFromString(strings.TrimSpace(strings.Split(line, ": ")[1])) utils.Check(err) ingredients = append(ingredients, i) } if strings.HasPrefix(line, "Ingredients:") { parts := strings.TrimSpace(strings.Split(line, ":")[1]) for _, i := range strings.Split(parts, ",") { a := strings.Split(strings.TrimSpace(i), " x") i, err := ingredient.IngredientFromString(strings.TrimSpace(a[0])) utils.Check(err) amount, err := strconv.Atoi(a[1]) utils.Check(err) for range amount { ingredients = append(ingredients, i) } } } if strings.HasPrefix(line, "Recipe") { lines = lines[index+1:] } } steps = append(steps, recipe.Step{ Action: action.Prepare, Ingredients: ingredients, }) for _, line := range lines { line = strings.TrimSpace(line) if match := add_to_cauldron.FindStringSubmatch(line); match != nil { parts := strings.Split(match[1], " and ") var ingredients []ingredient.Ingredient for _, part := range parts { if match := extract_amount.FindStringSubmatch(part); match != nil { i, err := strconv.Atoi(match[1]) utils.Check(err) for range i { i, err := ingredient.IngredientFromString(strings.TrimSpace(match[2])) utils.Check(err) ingredients = append(ingredients, i) } } } steps = append(steps, recipe.Step{ Action: action.AddToCauldron, Ingredients: ingredients, }) } if match := add_to_mortar.FindStringSubmatch(line); match != nil { parts := strings.Split(match[1], " and ") var ingredients []ingredient.Ingredient for _, part := range parts { if match := extract_amount.FindStringSubmatch(part); match != nil { i, err := strconv.Atoi(match[1]) utils.Check(err) for range i { i, err := ingredient.IngredientFromString(strings.TrimSpace(match[2])) utils.Check(err) ingredients = append(ingredients, i) } } } steps = append(steps, recipe.Step{ Action: action.GrindIngredients, Ingredients: ingredients, }) } if match := boil.FindStringSubmatch(line); match != nil { i, err := strconv.Atoi(match[1]) utils.Check(err) steps = append(steps, recipe.Step{ Action: action.Boil, Turns: i, }) } if match := boil_bellows.FindStringSubmatch(line); match != nil { i, err := strconv.Atoi(match[1]) utils.Check(err) steps = append(steps, recipe.Step{ Action: action.BoilBellows, Turns: i, }) } if strings.HasPrefix(line, "Pour into phial.") { steps = append(steps, recipe.Step{ Action: action.PourPhial, }) } if strings.HasPrefix(line, "Prepare phial and distill.") { steps = append(steps, recipe.Step{ Action: action.Distill, }) } if strings.HasPrefix(line, "Pour into a mortar and grind.") { steps = append(steps, recipe.Step{ Action: action.GrindPotion, }) } } return } func FromText(file fs.File) map[string][]recipe.Step { scanner := bufio.NewScanner(file) // optionally, resize scanner's capacity for lines over 64K, see next example recipes := make(map[string][]recipe.Step, 0) lines := make([]string, 0) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if len(line) == 0 { continue } if line == "--" { name, recipe, err := transformStep(lines) utils.Check(err) recipes[name] = recipe lines = make([]string, 0) continue } lines = append(lines, line) } if len(lines) > 0 { name, recipe, err := transformStep(lines) utils.Check(err) recipes[name] = recipe } if err := scanner.Err(); err != nil { log.Fatal(err) } return recipes }