I have been attempting Problem 11 from Project Euler (https://projecteuler.net/problem=11) in Python, and have come across an error that confuses me. Basically, the 20x20 grid of numbers is a list that contains sublists of every line (or, every 20 number):
number_grid = [
[8, 2, 22, 97, 38, 15, 00, 40, 00, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8],
[49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 00],
[81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13, 36, 65],
[52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36, 91],
[22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80],
[24, 47, 32, 60, 99, 3, 45, 2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50],
[32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70],
[67, 26, 20, 68, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94, 21],
[24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72],
[21, 36, 23, 9, 75, 00, 76, 44, 20, 45, 35, 14, 00, 61, 33, 97, 34, 31, 33, 95],
[78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56, 92],
[16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 00, 17, 54, 24, 36, 29, 85, 57],
[86, 56, 00, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58],
[19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55, 40],
[4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66],
[88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69],
[4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 46, 29, 32, 40, 62, 76, 36],
[20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 4, 36, 16],
[20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5, 54],
[1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67, 48]
]
The problem asks me to find "the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally)," meaning I have to loop through every number and find those combinations.
To loop through each number I create nested for loops to first loop through the multiple lists, and then to loop through the numbers in those lists.
My for loops look like this:
for list in range(0,20):
for num in range(0,20):
print(list, num, number_grid[list][num])
I also make pre-set combinations in the form of a list based on the variables list and num:
left_side = [number_grid[list][num], number_grid[list][num-1], number_grid[list][num-2], number_grid[list][num-3]]
right_side = [number_grid[list][num], number_grid[list][num 1], number_grid[list][num 2], number_grid[list][num 3]]
up_side = [number_grid[list][num], number_grid[list-1][num], number_grid[list-2][num], number_grid[list-3][num]]
down_side = [number_grid[list][num], number_grid[list 1][num], number_grid[list 2][num], number_grid[list 3][num]]
diag_down_left = [[number_grid[list][num]], number_grid[list 1][num-1], number_grid[list 2][num-2], number_grid[list 3][num-3]]
diag_down_right = [[number_grid[list][num]], number_grid[list 1][num 1], number_grid[list 2][num 2], number_grid[list 3][num 3]]
diag_up_left = [[number_grid[list][num]], number_grid[list-1][num-1], number_grid[list-2][num-2], number_grid[list-3][num-3]]
diag_up_right = [[number_grid[list][num]], number_grid[list-1][num 1], number_grid[list-2][num 2], number_grid[list-3][num 3]]
The hard part of this problem (the way I see it), is that I can't have all 8 combinations (listed above) for every number. For example, for numbers that are less than 4 spaces away from the left side and less than 4 spaces below the first list cannot have a horizontally left, diagonally down left, diagonally up left and vertically up combination of number as there simply isn't enough space. This is expressed with the if statement looking like:
if num < 3 and list < 3:
print("Top Left")
combinations.append(right_side)
combinations.append(down_side)
combinations.append(diag_down_right)
This piece of code works, with the output in my console being:
0 0 8
Top Left
0 1 2
Top Left
0 2 22
Top Left
The numbers, such as "0 0 8" are from me printing which list it is, and which number place it is. So, "0 0" means the first number of the first list, and "1 1" would be the 2nd number of the 2nd list.
However, a problem occurs when the code loops to the top right part of the grid. The code I implement is:
elif list < 3 and num > 16:
print("Top Right")
combinations.append(left_side)
combinations.append(down_side)
combinations.append(diag_down_left)
Yet this doesn't seem to register. In fact, the full console log looks like this:
0 0 8
Top Left
0 1 2
Top Left
0 2 22
Top Left
0 3 97
0 4 38
0 5 15
0 6 0
0 7 40
0 8 0
0 9 75
0 10 4
0 11 5
0 12 7
0 13 78
0 14 52
0 15 12
0 16 50
0 17 77
Traceback (most recent call last):
File "11.py", line 30, in <module>
right_side = [number_grid[list][num], number_grid[list][num 1], number_grid[list][num 2], number_grid[list][num 3]]
IndexError: list index out of range
I'm confused, because list value is under 3, and the number index is above 16. I've done some troubleshooting, and the if statement works without the "and num > 16 for some reason, but I still need that part.
My full code looks like this, if there appear to be any errors in the structuring and such:
number_grid = [
[8, 2, 22, 97, 38, 15, 00, 40, 00, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8],
[49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 00],
[81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13, 36, 65],
[52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36, 91],
[22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80],
[24, 47, 32, 60, 99, 3, 45, 2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50],
[32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70],
[67, 26, 20, 68, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94, 21],
[24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72],
[21, 36, 23, 9, 75, 00, 76, 44, 20, 45, 35, 14, 00, 61, 33, 97, 34, 31, 33, 95],
[78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56, 92],
[16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 00, 17, 54, 24, 36, 29, 85, 57],
[86, 56, 00, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58],
[19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55, 40],
[4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66],
[88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69],
[4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 46, 29, 32, 40, 62, 76, 36],
[20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 4, 36, 16],
[20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5, 54],
[1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67, 48]
]
combinations = []
for list in range(0,20):
for num in range(0,20):
print(list, num, number_grid[list][num])
left_side = [number_grid[list][num], number_grid[list][num-1], number_grid[list][num-2], number_grid[list][num-3]]
right_side = [number_grid[list][num], number_grid[list][num 1], number_grid[list][num 2], number_grid[list][num 3]]
up_side = [number_grid[list][num], number_grid[list-1][num], number_grid[list-2][num], number_grid[list-3][num]]
down_side = [number_grid[list][num], number_grid[list 1][num], number_grid[list 2][num], number_grid[list 3][num]]
diag_down_left = [[number_grid[list][num]], number_grid[list 1][num-1], number_grid[list 2][num-2], number_grid[list 3][num-3]]
diag_down_right = [[number_grid[list][num]], number_grid[list 1][num 1], number_grid[list 2][num 2], number_grid[list 3][num 3]]
diag_up_left = [[number_grid[list][num]], number_grid[list-1][num-1], number_grid[list-2][num-2], number_grid[list-3][num-3]]
diag_up_right = [[number_grid[list][num]], number_grid[list-1][num 1], number_grid[list-2][num 2], number_grid[list-3][num 3]]
if num < 3 and list < 3:
print("Top Left")
combinations.append(right_side)
combinations.append(down_side)
combinations.append(diag_down_right)
elif num < 3 and list > 16:
print("Bottom Left")
combinations.append(right_side)
combinations.append(up_side)
combinations.append(diag_up_right)
elif list < 3 and num > 16:
print("Top Right")
combinations.append(left_side)
combinations.append(down_side)
combinations.append(diag_down_left)
elif num > 16 and list > 16:
print("Bottom Right")
combinations.append(left_side)
combinations.append(up_side)
combinations.append(diag_up_left)
elif num < 3:
print("Left")
combinations.append(right_side)
combinations.append(up_side)
combinations.append(down_side)
combinations.append(diag_up_right)
combinations.append(diag_down_right)
elif num > 16:
print("Right")
combinations.append(left_side)
combinations.append(up_side)
combinations.append(down_side)
combinations.append(diag_up_left)
combinations.append(diag_down_left)
if list < 3:
print("Top")
combinations.append(right_side)
combinations.append(left_side)
combinations.append(down_side)
combinations.append(diag_down_left)
combinations.append(diag_down_right)
elif list > 16:
print("Bottom")
combinations.append(right_side)
combinations.append(left_side)
combinations.append(up_side)
combinations.append(diag_up_left)
combinations.append(diag_up_right)
print(combinations)
CodePudding user response:
In your inner loop (for num in range(0, 20):
), you begin by making dangerous accesses and only afterwards start checking for indices that will end up going out of range. You want the pattern to be
- check for and handle bad indices
- access using the indices
- increment index
as opposed to
- access using the indices
- check for and handle bad indices
- increment index
because in the latter, we increment the index directly before accessing the indices when the loop iterates - where we really wanted to check the indices after modifying them.
In your particular case, you will crash when num
becomes 17
. Because the first thing you do with num
after it becoming 17
is try to use it as an index, and num 3
is 20
making number_grid[list][num 3]
result in an exception being thrown. Only after making that access, do you check to see if num
is greater than 16
.
CodePudding user response:
Although Python let's you get away with looking at index -1, it doesn't let you get away with looking at indices larger than the size of the array. When list
and num
are large, you look at indices list 3
and num 3
, even though they are larger than the size of the array.
You can only look at number_grid[list][num 3]
after you have determined that num 3
is a valid index.
By the way, don't name a variable list
in Python. This is bad practice. list
is the name of a commonly used predefined function. For this code, I'd use row
and col
or something like that.