Honing The Scripting: AdventOfCode-2015[:5]

banner1.png

I spent some time to solve programming puzzles from AdventOfCode-2015 as it checks ones scripting/programming skills by providing numerous programming challenges level wise, it has total 25 days of challenges this paritcular blog has first 5 challengs that i managed to solve.

All Puzzle’s scripts can be found here

Day 1: Not Quite Lisp

Description

day1_desc.png

  1. Initialize a variable to keep track of the current floor, starting at floor 0.
  2. Iterate through each character in the instructions.
  3. If the character is an opening parenthesis ‘(‘, increment the current floor by 1.
  4. If the character is a closing parenthesis ‘)’, decrement the current floor by 1.
  5. After processing all characters, the current floor will be the result.

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class PuzzleSolver:
def __init__(self, file_input):
self.file_input = file_input

def solve(self):
with open(self.file_input, "r") as f:
data = f.read()
data_len = len(data)
flag = 0 + 1 # as loop start from 0
for i in range(data_len):
if data[i] == '(':
flag += 1
else:
flag -= 1
return flag

if __name__ == "__main__":
file_input = "./input.txt"
solver = PuzzleSolver(file_input)
result = solver.solve()
print("\033[1;32mResult:\033[0m",result)

Day 2: I Was Told There Would Be No Math

Description

day2_desc.png

Approach

  1. Read the dimensions (length, width, and height) of each present from the input.
  2. For each present, calculate the surface area of the box using the formula: 2lw+2wh+2hl2lw+2wh+2hl.
  3. Determine the area of the smallest side of the box.
  4. Add the surface area and the area of the smallest side to get the total required wrapping paper for each present.
  5. Sum up the total required wrapping paper for all presents to find the total square feet of wrapping paper needed.

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class PuzzleSolver:
def __init__(self, file_input):
self.file_input = file_input
self.finalSA = 0

def surfaceArea(self,data):
self.data = data
#sa = 2*l*w + 2*w*h + 2*h*l
l,w,h = map(int, self.data.split('x'))
# self.data = str(self.data.replace('x','*'))
sa = (2*l*w + 2*w*h + 2*h*l)
sa = sa + min(l*w,w*h,h*l) # the area of the smallest side(took time).
# sa = math.sqrt(sa) # thought have to convert feet to sfeet, but SA has sfeet value already
print(f"flag: {sa}")
return sa

def solve(self):
with open(self.file_input, "r") as f:
data = f.read().strip().split('\n')
# data_len = len(data)
for index,val in enumerate(data):
self.finalSA += self.surfaceArea(data[index])
# print(f"finalSA: {self.finalSA}")
# exit()
print(self.finalSA)

if __name__ == "__main__":
file_input = "./input.txt"
solver = PuzzleSolver(file_input)
result = solver.solve()
print("\033[1;32mResult:\033[0m",result)

OneLiner

1
print(sum(2 * (l*w + w*h + h*l) + min(l*w, w*h, h*l) for l, w, h in (map(int, line.strip().split('x')) for line in open("./input.txt"))))

Day 3: Perfectly Spherical Houses in a Vacuum

Description

day3_desc.png

In the puzzle, Santa is moving around on a two-dimensional grid. The grid represents the map of houses in which Santa is delivering presents. Each house is identified by its coordinates on the grid. For simplicity, we can consider the grid as a Cartesian coordinate system, where each house is located at a unique pair of x and y coordinates.

When we initialize Santa’s starting position at (0, 0), we’re placing him at the center of the grid. This point serves as the starting point from which Santa begins his delivery route. The (0, 0) point represents the origin of the grid, where the x and y coordinates are both zero.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
		 Y' (North)
^
|
|
| 🏠 (0, 2)
| / \
| / \
| / 🎅 \ (0, 1)
| / \
(West) X'<--------+---🏠---🏠---🏠---> X (East) (-1, 0) (0, 0) (1, 0)
| \ /
| \ 🏠 / (0,-1)
| \ /
| \ /
| 🏠 (0, -2)
|
v
Y (South)

As Santa moves around the grid according to the given directions (north, south, east, west), his position on the grid changes. Each movement in a particular direction (e.g., one step to the north) results in a change of Santa’s coordinates on the grid.

  • Moving one step to the north increases Santa’s y-coordinate by 1.
  • Moving one step to the south decreases Santa’s y-coordinate by 1.
  • Moving one step to the east increases Santa’s x-coordinate by 1.
  • Moving one step to the west decreases Santa’s x-coordinate by 1.

So if:

  • If Santa moves north from (0, 0), he reaches (0, 1).
  • If Santa moves east from (0, 0), he reaches (1, 0).
  • If Santa moves south from (1, 0), he returns to (0, 0).

For Example:

  • for string ^>v<:

  • Santa starts at (0,0) and moves north, delivering a present to (0,1).

  • Then he moves east, delivering a present to (1,1).

  • Next, he moves south, delivering a present to (1,0).

  • Finally, he moves west, delivering a present to (0,0) again (his starting location).

In this case, Santa ends up visiting four houses:

  • (0,0) - visited twice
  • (0,1)
  • (1,0)
  • (1,1)

Even though Santa revisits his starting location, it still counts as a unique house visited. Therefore, in total, four houses receive at least one present.

To solve this puzzle, you’ll need to simulate Santa’s movements and keep track of the houses he visits. Here’s a high-level guide on how you can proceed:

  1. Initialize Santa’s starting position: Santa starts at the origin (0, 0) on the grid.

  2. Read the input directions: Read the input directions provided in the puzzle.

  3. Iterate over each direction: For each direction (north, south, east, or west), update Santa’s position accordingly.

  4. Keep track of visited houses: Maintain a set or dictionary to keep track of the houses Santa has visited. Add each visited house to the set or dictionary.

  5. Count unique visited houses: After iterating through all directions, count the number of unique houses visited by Santa. This count represents the number of houses that receive at least one present.

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class PuzzleSolver:
def __init__(self, file_input):
self.file_input = file_input
self.flag = set() #visited house, Use a set to keep track of visited houses
self.currentMoves = (0, 0)

def gettingDemensions(self,move):
direction = move
# self.currentMoves = (self.currentMoves[0] +1, self.currentMoves[1] + 1)
if direction == ">":
self.currentMoves = (self.currentMoves[0] + 1, self.currentMoves[1])
elif direction == "<":
self.currentMoves = (self.currentMoves[0] - 1, self.currentMoves[1])
elif direction == "^":
self.currentMoves = (self.currentMoves[0], self.currentMoves[1] + 1)
elif direction == "v":
self.currentMoves = (self.currentMoves[0], self.currentMoves[1] - 1)

def housesReceived(self, move):
# self.move = move
self.gettingDemensions(move)
# print(f"currentMoves: {self.currentMoves, type(self.currentMoves)}")
self.flag.add(self.currentMoves)

def solve(self):
with open(self.file_input, "r") as f:
moves = f.readline()
# print(type(moves[1]))
self.flag.add((0, 0)) # was tricky for me for no reason, adding before as Santa start at his starting location
for move in moves:
self.housesReceived(move)
# exit()
print(f"Houses visited: {self.flag}")

if __name__ == "__main__":
file_input = "./input.txt"
solver = PuzzleSolver(file_input)
result = solver.solve()
print("\033[1;32mHouses Visited by Santa is:\033[0m",len(solver.flag))

Day 4: The Ideal Stocking Stuffer

Description

day4_desc.png

This one is pretty simple we just have to brute force the puzzle input with combining sereies of positive number seuentially and check if its hash converted strings is starting with 00000

Approach

  • Choose libraries or built-in functions for calculating MD5 hashes.
  • Define a function to calculate the MD5 hash of a given string.
  • Create a loop to iterate over increasing numbers starting from 1 (or any other starting value you prefer).
  • Append each number to the secret key.
  • Calculate the MD5 hash of the combined string.
  • Check if the hash starts with at least five zeroes.

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import hashlib

class PuzzleSolver:
def __init__(self, puzzle_input):
self.puzzle_input = puzzle_input
self.flag = '' #positive number

def hashingInp(self,hme):
md5 = hashlib.md5(hme.encode('utf-8'))
return md5.hexdigest()

def miningCoin(self,puzzle_input):
i = 1
while True:
hme = puzzle_input + str(i)
# print(f"hme: {hme}")
hvalue = self.hashingInp(hme)
if hvalue.startswith("00000"):
return i
i += 1

def solve(self):
self.flag = self.miningCoin(self.puzzle_input)
return self.flag

if __name__ == "__main__":
puzzle_input = "yzbqklnj"
solver = PuzzleSolver(puzzle_input)
result = solver.solve()
print("\033[1;32mLowest Positive Number:\033[0m",result)

Day 5: Doesn’t He Have Intern-Elves For This?

Description

day5_desc.png

Approach

  1. Read the strings from the text file.
  2. Define a function to check if a string is “nice” according to the given criteria.
  3. Iterate through each string and use the function to determine if it’s “nice” or “naughty”.
  4. Keep count of the number of “nice” strings found.
  5. Print the total count of “nice” strings.

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import string

class PuzzleSolver:
def __init__(self, file_input):
self.file_input = file_input
self.flag = [] # nice string

def worker(self,santaString):
vowels = 'aeiou'
disallowed = ['ab', 'cd', 'pq', 'xy']

if sum(1 for line in santaString if line in vowels) < 3:
return False
if not any(santaString[i] == santaString[i+1] for i in range(len(santaString) - 1)):
return False
# if all(substring not in variable for substring in disallowed)
if any(substring in santaString for substring in disallowed):
return False
return True

def naughtyOrnice(self,santaString):
if self.worker(santaString):
self.flag.append(santaString)

def solve(self):
with open(self.file_input, "r") as f:
data = f.read().strip().split('\n')
for line in data:
self.naughtyOrnice(line)

if __name__ == "__main__":
file_input = "./input.txt"
solver = PuzzleSolver(file_input)
result = solver.solve()
print("\033[1;32mNumber Of Nice String:\033[0m",len(solver.flag))

Summary

The challenges were a good warm-up, with some tricky parts to keep things interesting specially puzzle 3 that took me more time to solve, i would like to try other puzzle as well and post writeup.

One key takeaway is the importance of efficiency in problem-solving. By implementing wrapper functions, we can save time and avoid redundant code, ultimately enhancing our overall productivity. This approach streamlined the solving process and prepared me to tackle more complex challenges efficiently.