Skip to content

Advent Of Code 2020: Day14 - Part 1

   

Lo sé, han pasado ya varios días desde que finalizó el Advent Of Code 2020 sin embargo yo todavía no termino todos los desafios y no estoy precisamente apurado en resolverlos. Iré avanzando a mi ritmo.

Como una pequeña introducción para los que no saben de que hablo, el Advent Of Code es una serie de desafios que se realizan de manera anual. Corresponde a desafios diarios que se van revelando a aprtir del 1 de diciembre hasta el 25 del mismo mes, como si fuese un calendario de adviento.

Cada desafío se presenta como parte de una fantasía en la que nosotros somos un programador que debe salvar la navidad resolviendo distintos retos. Diariamente se deben resolver dos retos consecutivos.

Junto con el escenario, cada desafio díario entrega un input en forma de archivo, el cual debemos correr en el programa para conseguir la respuesta.

Para este caso procederé a explicar mi solución para el reto 1 del día 14.

La Situación

En esta situación debemos ayudar al capitan de un ferry para poder inicial correctamente los parámetros de anclaje en el programa.

El ejercicio entrega un listado del siguiente tipo:

mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem[8] = 11
mem[7] = 101
mem[8] = 0

Donde mask es una bitmask de 64 bits y cada valor mem es un número al cual se le debe aplicar la mascara previo almacenamiento en la dirección de memoria dada.

Básicamente se compara el número por cada posición en decimal con la máscara que le corresponde. Cada ‘X’ corresponde a un espacio vacío en la mascara y al hacer la comparación nos quedamos con el valor original. Si la contine un número este reemplaza al valor original. Un ejemplo sería el siguiente:

value:  000000000000000000000000000000001011  (decimal 11)
mask:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
result: 000000000000000000000000000001001001  (decimal 73)

El valor inicial era 11, y tras aplicarle la máscara queda en 73.

El resultado final es la suma de cada valor guardado en memoria.

La Solución

Como en muchos otros problemas, me gusta separarlo en problemas más chicos que me permitan orginar de mejor manera el problema.

Con este proposito definí dos funciones. La primera toma como argumento el listado y devuelve la lista con las direcciones de memoria y un zip que contiene la máscara y el número al cual se le debe aplicar.

def readfile(file):
# Definicion de listas usadas dentro del problemas para almacenar los resultasdos.

	with file as instruccions:
		for line in instrucions:
			line = line.rstrip('\n')
			if line[:4] == 'mask':
				mask = line[7:]
			else:
			# Si no es mask entonces es numero
			# Se separa la direccion de memoria y el numero para luego almacenaro en
			# En sus listas correspondientes.
			
	mask_zip = zip(mask_list, num_list) 
	return adress_list, mask_zip

La segunda función simplemente aplica la máscara a un número y retorna el número nuevo.

def mask_apply(mask, number):
	# Se pasa el numero a decimal y se remueve el identificador inicial '0b'
	number = int(number, 2)[2:]
	
	# Se genera un string de 0s faltantes para completar los 36 espacios de 36 bits
	relleno = '0' * (36 - len(number))
	number = relleno + number

	n_num = ''
	# Se recorre el numero y su mascara y se comprueba cada posicion
	# para ver si se aplica la mascara o no
	for x in zip(mask, number):
		if x[0] == 'X':
			char = x[1]
		else:
			char = x[0]
		n_num = n_num = char
	return n_num

Ya con ambas funciones se puede obtener la solución al correrlas en un main.

def main():
	file = open(<direccion del archivo>, 'r')
	address, mask_num = readfile(file)
	
	# Se define un diccionario que tendra como llave la direccion de memoria
	# y como valor el valor numerico post mascara.
	result_dict = dict()
	index = 0

	# Se itera sobre cada par mascara, numero 
	for pair in mask_num:
		n_num = mask_apply(*pair)
		n_num = int('0b' + m_num, 2)
		result_dict[address[index]] = n_num
		index += 1

	# Al finaliza se cuentan los resultados, este es el valor solucion del problema
	result = sum(list(result_dict.values()))

	print('La suma total es {}'.format(result))

Conclusión

Este ejercicio en particular, como muchas primeras partes, no resulta ser muy complicado y se puede resulver de manera bastante directa.

Como posible optimización a esta solución creo que se podría aplicar el tipo de zip que avanza usando la lista más larga y rellena con un valor default lo espacios vacios de la lista más pequeña…por lo menos creo qu existe un zip así no estoy 100% seguro. Esto nos ahorraría el tener que ajustar con ceros el número en binario.