AOC第3天 - 背包重组
#编程 #教程 #go #adventofcode

背包重组

Question
我们要进入丛林!我们让Legolas负责打包我们的旅程,但他的包装能力似乎不像他的弓箭技巧,他有点痛苦地包装...
但是,我们确实有每个背包中项目的清单,列表看起来如下

vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

每行代表一个背包,该行的每一半代表背包中的一个隔间。
物品可以通过其字符来识别,是的,“ a”和“ a”不是相同的项目。
例如
第一个背包包含vJrwpWtwJgWrhcsFMMfFFhFp的项目,这意味着其第一个隔间包含vJrwpWtwJgWr的项目,而第二个隔间包含hcsFMMfFFhFp的项目。两个隔间中出现的唯一项目类型是小写p。

为了帮助优先考虑项目重排,每个项目类型都可以转换为优先级:

小写的项目A类型A到Z具有优先级1至26。
大写项目A类型A至Z具有优先级27至52。

在上面的示例中,每个背包的两个隔室中出现的项目类型的优先级为16(p),38(l),42(p),22(v),20(t)和19(s);这些的总和是157。

第1部分

在第一部分中,我们的任务是总结两个隔间中出现的项目的优先级

让我们从分析我们的输入

开始

解析

理想情况下,我们想拥有一个包含元组的阵列,每个套件都有一个半

例如vJrwpWtwJgWrhcsFMMfFFhFp -> [ [set(vJrwpWtwJgWr), set(hcsFMMfFFhFp)]... ]
我们在这里选择一个ds,以便能够轻松回答“集合y中的字母x?”后来

// go doesn't have a built in Set DS so we need to roll our own here
func makeSet(chars string) map[rune]bool {
    set := map[rune]bool{}
    for _, c := range chars {
        set[c] = true
    }
    return set
}

func parse() [][]map[rune]bool {
    data, _ := os.ReadFile("./input.txt")
    lines := strings.Split(string(data), "\n")

    rucksacks := [][]map[rune]bool{}
    for _, line := range lines {
        c1 := makeSet(line[:len(line)/2])
        c2 := makeSet(line[len(line)/2:])
        w := []map[rune]bool{c1, c2}
        rucksacks = append(rucksacks, w)
    }

    return rucksacks
}

有趣的是,我们将每个字符作为rune,这是所述char的ASCII值

我们使用:将线切成两个部分,line[x:]表示从x切成薄片直至结束,而lines[:x]表示从数组的开头开始直到x

解决方案

现在我们已经完成了数据,我们可以编写以下代码来计算每个char的优先级

func calcPriority(c rune) int {
    if c >= 'a' && c <= 'z' {
        return int(c) - 'a' + 1
    } else {
        return int(c) - 'A' + 27
    }
}

基本上,我们正在乘符文,扣除基本值,例如'a'或'a',并添加了从1到26的问题,含义从1到26,大写从27到52

如果我在比较中使用双引号,则此代码将无法使用


好吧,我们都准备好现在,让我们解决第1部分
我们将在所有背包上进行迭代,并且每个人都会找到第一个隔间和第二个隔间中的字母。
当我们找到一个时,我们将其传递给我们的钙化函数并积累其值

func pt1() int {
    groups := parse()
    sum := 0
    for _, group := range groups {
        s1 := group[0] // first compartment 
        s2 := group[1] // second compartment 
        for k, _ := range s1 {
            if s2[k] {
                sum += calcPriority(k)
            }
        }
    }

    return sum
}

酷酷酷,我们都完成了第1部分的完成,让我们看看第2部分为我们提供了什么

第2部分

我们不是要找到组徽章的优先级的任务,而是将徽章定义为连续3个Rucksacks中包含的item

从上面的示例输入中,我们可以绘制以下示例

vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg

,第二组的背包是接下来的三行:

wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

在第一组中,所有三个背包中出现的唯一项目类型是小写kude11;这一定是他们的徽章。在第二组中,他们的徽章项目类型必须为Z

仍然必须找到这些项目的优先级来组织贴纸的依恋工作:在这里,第一组为18(r),第二组为52(z)。这些总和是70。

我们需要对我们的解析代码进行一些调整以一次创建3行的集合,这看起来像

func chunkInto(s []string, size int) [][]string {
    results := [][]string{}
    for i := 0; i < len(s); i += size {
        results = append(results, s[i:i+size])
    }
    return results
}


func parse2() [][]map[rune]bool {
    data, _ := os.ReadFile("./input.txt")
    rows := strings.Split(string(data), "\n")
    groups := chunkInto(rows, 3)
    rucksacks := [][]map[rune]bool{}
    for _, chunk := range groups {
        w := []map[rune]bool{}
        for _, c := range chunk {
            w = append(w, makeSet(c))
        }
        rucksacks = append(rucksacks, w)
    }
    return rucksacks
}

我们现在可以与第1部分相似地解决第2部分

func pt2() int {
    groups := parse2()

    sum := 0
    for _, group := range groups {
        s1 := group[0]
        s2 := group[1]
        s3 := group[2]
        for k, _ := range s1 {
            if s2[k] && s3[k] {
                sum += calcPriority(k)
            }
        }
    }

    return sum
}

就是这样,今天男孩和女孩,我希望您能像我到目前为止一样享受AOC


您可以找到完整的代码here
感谢您的阅读!