☰
我正在用 Python 编写 2024 年的 Advent of Code – 第四天
2026/10/15 7:38:18 网站建设 项目流程

原文:towardsdatascience.com/im-doing-the-advent-of-code-2024-in-python-day-4-f0dacf4529a6

欢迎来到第四天!

  • 第一天介绍,如何获取你自己的谜题输入,以及第一天的谜题解决方案。

  • 第二天, 第三天

我们将在第四天的谜题中学习以下主题:

  • Python 中的列表推导

  • 如何处理一维和二维 NumPy 数组

  • 如何转置和翻转 NumPy 数组

到我写这篇文章的时候,已经发布了 22 个谜题,每个谜题有两个部分。每个部分都算作一个开始,以下是我的当前进度:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8750a11b9f7abe7d44ab75c5e6fe0f95.png

![作者图片]


第四天 – 第一部分

第四天的谜题输入是一个包含字母 X、M、A 和 S 的长字符串。我的谜题输入的前 10 行看起来像这样:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/907c9c23a9a047a85f5156692b4449a2.png

![作者图片]

第四部分谜题的第一部分是要找到文本中“XMAS”的出现次数。难点在于所有水平、垂直和对角线上的出现都计算在内(包括正向和反向)。

这里有一个示例图,展示了在谜题输入中要寻找的内容:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/033846363e8b70307e84768025c22d19.png

![作者图片]

因此,我们需要在水平、垂直和对角线上计数“XMAS”和“SAMX”。

让我们从获取谜题输入开始。

importrequests session_cookie="your session cookie"# or session_cookie = os.getenv(SESSION_COOKIE)defget_puzzle_input(day,session_cookie,year=2024):url=f"https://adventofcode.com/{year}/day/{day}/input"cookies={"session":session_cookie}response=requests.get(url,cookies=cookies)ifresponse.status_code==200:returnresponse.textelse:returnNonepuzzle_input=get_puzzle_input(4,session_cookie)

为了进行水平计数,我将谜题输入分割成一行行的列表,并在列表推导中使用count方法。

# split at new line to convert the puzzle input into a list of lineslines=puzzle_input.split("n")[:-1]# count the occurrences of XMAS and SAMX for each linehorizontal_counts=[line.count("XMAS")+line.count("SAMX")forlineinlines]

horizontal_counts列表包含每行中 XMAS 和 SAMX 出现的次数。sum(horizontal_counts)给出了总的水平计数。

有不同的方法来找到垂直计数。我想使用 NumPy 数组。第一步是将lines列表转换成二维数组。

importnumpyasnp arr=np.array([list(line)forlineinlines])print(arr.shape)# output(140,140)print(arr)# outputarray([['M','S','M',...,'M','X','S'],['S','A','A',...,'S','A','A'],['X','M','X',...,'M','X','S'],...,['M','A','S',...,'S','S','S'],['S','A','M',...,'A','A','M'],['M','M','S',...,'M','M','M']],dtype='<U1')

谜题输入中有 140 行,每行有 140 个字符。

要计算“XMAS”和“SAMX”的垂直出现次数,我将这个数组转置,这样就将垂直变成了水平。

arr_transpose=arr.transpose()arr_transpose# outputarray([['M','S','X',...,'M','S','M'],['S','A','M',...,'A','A','M'],['M','A','X',...,'S','M','S'],...,['M','S','M',...,'S','A','M'],['X','A','X',...,'S','A','M'],['S','A','S',...,'S','M','M']],dtype='<U1')

然后,我为每一行创建一个字符串,通过连接字母可以使用与水平计数相同的方法。

vertical_lines=["".join(line)forlineinarr_transpose]vertical_lines[0]# output'MSXSSSMSMMMXMXMXSSXMASAMMMMSMXMMSMSXMASMMXMASMMMMMSSSXMASAMXMMXSAMMMXAXSMMMMSXMAMMSAMSAMSASMMMASMSSMMSAMASXMXXXSSMMSAMXXSXSXSMSAMXXXMASASMSM'

然后,我可以使用与水平计数相同的方法。

vertical_counts=sum([line.count("XMAS")+line.count("SAMX")forlineinvertical_lines])

现在我们有了水平和垂直计数。最后一个是对角线上的出现次数。我们可以使用 NumPy 数组的diagonal方法创建对角线列表。np.diagonal(arr, 0)给出了主对角线。通过将 0 替换为正整数和负整数,我们可以获得所有对角线。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/dcfe48bd0a66ae6b9c96d2caf029ed2d.png

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4f558e22349a1fb7bfaf8d85a98ed0ac.png

让我们写一个 for 循环来创建所有对角线的列表。

diagonals=[]foriinrange(-len(arr)+1,len(arr)-1):line="".join(np.diagonal(arr,i))diagonals.append(line)# check the first 10 diagonalsdiagonals[:10]# output['M','SM','MAS','SAMA','AXSMM','SXMASX','AMMASAS','MXMASXMM','XSAMMASAM','XMXMMAXSAM']

我们处理了从左上角到右下角的对角线,但我们还需要检查从右上角到左下角的对角线。

我们可以使用相同的循环来完成,但我们只需要翻转二维数组,这可以通过fliplr方法完成。

diagonals_flipped=[]foriinrange(-len(arr)+1,len(arr)-1):line="".join(np.diagonal(np.fliplr(arr),i))diagonals_flipped.append(line)

我们现在可以计算两个对角线和翻转对角线上的“XMAS”和“SAMX”出现的次数。

diagonal_counts=sum([line.count("XMAS")+line.count("SAMX")forlineindiagonals])diagonal_counts_flipped=sum([line.count("XMAS")+line.count("SAMX")forlineindiagonals_flipped])# final answerhorizontal_counts+vertical_counts+diagonal_counts+diagonal_counts_flipped

当我们将我们计算的所有计数相加时,我们得到第一部分的最终答案。


第四天 – 第二部分

在这个谜题的第二部分,我们要找到“X-MAS”的出现次数,这意味着有两个 MAS 值以 X 的形状出现。

下面是我们将在谜题输入中寻找的内容("."代表任何字符)。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4f558e22349a1fb7bfaf8d85a98ed0ac.png

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4f558e22349a1fb7bfaf8d85a98ed0ac.png

我解决这个谜题的方法是创建一个从左上角开始的 3×3 窗口,并向下移动一个位置。在每次移动中,我都会检查 3×3 窗口是否等于我们想要的任何 X-MAS 形状。

一旦我到达底部,我就回到顶部并向右移动一个步骤。我重复同样的过程,直到我到达右下角。

我试图在下面的图中展示这个过程:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d3c5ef3a7254833a8f8b243c7f7cfa88.png

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4f558e22349a1fb7bfaf8d85a98ed0ac.png

要在代码中执行此操作,我使用了两个 for 循环。让我们首先定义我们将要寻找的 X-MAS 形状。

xmas1=[['M','.','M'],['.','A','.'],['S','.','S']]xmas2=[['S','.','S'],['.','A','.'],['M','.','M']]xmas3=[['M','.','S'],['.','A','.'],['M','.','S']]xmas4=[['S','.','M'],['.','A','.'],['S','.','M']]

我们现在可以创建嵌套的 for 循环来遍历第一部分创建的二维数组。

xmas_cnt=0foriinrange(len(arr)-2):forjinrange(len(arr)-2):res=arr[j:j+3,i:i+3].copy()# very important to use copy hereres[0][1]="."res[1][0]="."res[1][2]="."res[2][1]="."if(res==xmas1).sum()==9:xmas_cnt+=1if(res==xmas2).sum()==9:xmas_cnt+=1if(res==xmas3).sum()==9:xmas_cnt+=1if(res==xmas4).sum()==9:xmas_cnt+=1

我们创建了一个变量(xmas_cnt)来跟踪我们检测到的 X-MAS 形状。如果 3×3 数组等于我们想要的 X-MAS 形状之一,我们就将这个变量的值增加一。xmas_cnt的最终值就是第二部分的答案。

我们将无关位置上的字母替换为"."。否则,我们需要将 3×3 数组与更多的组合进行比较。

非常重要的是要注意,在每一步中,我们需要创建 3×3 数组的副本。否则,当我们用"."替换字母时,我们会修改原始数组,最终会错过一些匹配项。


第四天的谜题是关于列表推导和 NumPy 数组操作的良好实践。我们还学习了嵌套循环结构,如何转置和翻转二维数组。

如果你计划在数据科学生态系统中找工作,所有这些都是在你需要时相当常用的基本操作。

感谢您的阅读。请期待第五天。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询