From c1fdc53e46d456d6bfa4f5a416a1e58e8a6468ef Mon Sep 17 00:00:00 2001
From: b-idea <test@test.com>
Date: Thu, 28 Sep 2023 13:25:01 +0200
Subject: added days: 10,11,12,14,16,18

---
 2018/aoc2018-d10.py    |  88 ++++++++++++
 2018/aoc2018-d11-p1.py |  75 +++++++++++
 2018/aoc2018-d11-p2.py | 108 +++++++++++++++
 2018/aoc2018-d12.py    |  68 ++++++++++
 2018/aoc2018-d14.py    |  66 +++++++++
 2018/aoc2018-d16.py    | 359 +++++++++++++++++++++++++++++++++++++++++++++++++
 2018/aoc2018-d18.py    | 131 ++++++++++++++++++
 7 files changed, 895 insertions(+)
 create mode 100755 2018/aoc2018-d10.py
 create mode 100755 2018/aoc2018-d11-p1.py
 create mode 100755 2018/aoc2018-d11-p2.py
 create mode 100644 2018/aoc2018-d12.py
 create mode 100644 2018/aoc2018-d14.py
 create mode 100644 2018/aoc2018-d16.py
 create mode 100644 2018/aoc2018-d18.py

diff --git a/2018/aoc2018-d10.py b/2018/aoc2018-d10.py
new file mode 100755
index 0000000..7bd2ae5
--- /dev/null
+++ b/2018/aoc2018-d10.py
@@ -0,0 +1,88 @@
+#advent of code 2018 
+#day 10
+
+#part 1 & part 2
+
+class light:
+	def __init__(self, x,y,vx,vy):
+		self.Pos = [x,y];
+		self.Vel = [vx,vy];
+	def CalcNextPos(self, t):
+		return [self.Pos[0]+t*self.Vel[0],self.Pos[1]+t*self.Vel[1]];
+	def __str__(self):
+		return f'<{self.Pos[0]},{self.Pos[1]}>';
+		
+def CalcArea(x1,x2,y1,y2):
+	return abs(x1-x2)*abs(y1-y2);
+
+f = open("input.txt",'r');
+Testing = False;
+#Testing = True; 
+if Testing:
+	f.close();
+	f = open("testinput.txt",'r');
+
+lights = [];
+
+for tl in f:
+	tl = tl.replace("position=<", "");
+	tl = tl.replace("velocity=<", "");
+	tl = tl.replace(">", "");
+	tl = tl.replace(",", "");
+	tl=tl.split();
+	lights.append( light(int(tl[0]),int(tl[1]),int(tl[2]),int(tl[3])) );
+f.close();
+
+Xmin = min(lights, key = lambda x: x.Pos[0]).Pos[0];
+Xmax = max(lights, key = lambda x: x.Pos[0]).Pos[0];
+Ymin = min(lights, key = lambda y: y.Pos[1]).Pos[1];
+Ymax = max(lights, key = lambda y: y.Pos[1]).Pos[1];
+#print(Xmin,Xmax,Ymin,Ymax);
+
+PrevArea = CalcArea(Xmin,Xmax,Ymin,Ymax);
+ElapsedTime = 0;
+
+while True:
+	#print(ElapsedTime);
+	ElapsedTime += 1;
+	Xmin = min(lights, key = lambda L: L.CalcNextPos(ElapsedTime)[0]).CalcNextPos(ElapsedTime)[0];
+	Xmax = max(lights, key = lambda L: L.CalcNextPos(ElapsedTime)[0]).CalcNextPos(ElapsedTime)[0];
+	Ymin = min(lights, key = lambda L: L.CalcNextPos(ElapsedTime)[1]).CalcNextPos(ElapsedTime)[1];
+	Ymax = max(lights, key = lambda L: L.CalcNextPos(ElapsedTime)[1]).CalcNextPos(ElapsedTime)[1];
+	
+	CurrArea = CalcArea(Xmin,Xmax,Ymin,Ymax);
+	
+	if (CurrArea > PrevArea):
+		MessageTime = ElapsedTime-1;
+		break;
+		
+	PrevArea = CurrArea;
+
+pointlist = [];
+
+for l in lights:
+	xy = l.CalcNextPos(MessageTime);
+	pointlist.append((xy[0],xy[1]));
+
+Xmin = min(lights, key = lambda L: L.CalcNextPos(ElapsedTime)[0]).CalcNextPos(ElapsedTime)[0];
+Xmax = max(lights, key = lambda L: L.CalcNextPos(ElapsedTime)[0]).CalcNextPos(ElapsedTime)[0];
+Ymin = min(lights, key = lambda L: L.CalcNextPos(ElapsedTime)[1]).CalcNextPos(ElapsedTime)[1];
+Ymax = max(lights, key = lambda L: L.CalcNextPos(ElapsedTime)[1]).CalcNextPos(ElapsedTime)[1];
+
+
+print("###########");
+print("part1:");
+
+for Y in range(Ymin,Ymax+1):
+	for X in range(Xmin,Xmax+1):
+		sign = " ";
+		if ((X,Y) in pointlist):
+			sign = "#";
+		print(sign, end="");
+	#print(end="");
+	print();
+
+part2 = MessageTime;
+
+print("###########");
+print("part2 ,", part2);
diff --git a/2018/aoc2018-d11-p1.py b/2018/aoc2018-d11-p1.py
new file mode 100755
index 0000000..2379c3c
--- /dev/null
+++ b/2018/aoc2018-d11-p1.py
@@ -0,0 +1,75 @@
+#advent of code 2018 
+#day 11
+#part 1
+
+#setup
+GridSize = 300;
+SquareSize = 3;
+fcserialnumber = int(open("input.txt",'r').readline());
+
+testing = False;
+#testing = True;
+if testing:
+	fcserialnumber = 42; #18=>33,45 ; 42 => 21,61;
+
+class fuelcell:
+	def __init__(self, x, y, serialnumber):
+		self.positionX = x;
+		self.positionY = y;
+		self.rackID = self.positionX + 10;
+		self.powerlevel = self.rackID * self.positionY;
+		self.powerlevel += serialnumber;
+		self.powerlevel *= self.rackID;
+		self.powerlevel = self.powerlevel//100;
+		self.powerlevel = self.powerlevel%10;
+		self.powerlevel -= 5;
+	def coords(self):
+		print(f'Fuel Cell coordinates (x,y): {self.positionX},{self.positionY} ');
+	def __str__(self):
+		return f'{self.powerlevel}';
+		
+'''
+testinput = [[3,5,8],[122,79,57],[217,196,39],[101,153,71]];
+
+for t in testinput:
+	dummycell = fuelcell(t[0],t[1],t[2]);
+	print(t, " ->  ",dummycell.powerlevel);
+	dummycell.coords();
+	
+print("#############################");
+print();
+'''
+
+fcgrid = [];
+gridline = [];
+
+for Y in range(GridSize):
+	gridline.clear();
+	for X in range(GridSize):
+		gridline.append(fuelcell(X+1,Y+1,fcserialnumber));
+	fcgrid.append(gridline.copy());
+
+maxpower = -999; #negative power just to start the algorythm
+maxX = 0;
+maxY = 0;
+powernow = 0;
+
+for Y in range(GridSize-SquareSize+1):
+	for X in range(GridSize-SquareSize+1):
+		powernow = 0;
+		for sy in range(SquareSize):
+			for sx in range(SquareSize):
+				powernow += fcgrid[Y+sy][X+sx].powerlevel;
+		if (powernow > maxpower):
+			maxpower = powernow;
+			maxX = X;
+			maxY = Y;
+
+#print(f'maximum found:  {maxX},{maxY} => {maxpower}');
+print("part 1: ");
+fcgrid[maxY][maxX].coords();
+
+#10,300 wrong
+#9,0 wrong
+#0,9 wrong
+#33,45 
diff --git a/2018/aoc2018-d11-p2.py b/2018/aoc2018-d11-p2.py
new file mode 100755
index 0000000..dbfafe7
--- /dev/null
+++ b/2018/aoc2018-d11-p2.py
@@ -0,0 +1,108 @@
+#advent of code 2018 
+#day 11
+#part 2
+#too lazy to clean up the code, might do it later (i.e. never)
+
+#setup
+GridSize = 300;
+SquareSize = 3;
+fcserialnumber = int(open("input.txt",'r').readline());
+
+testing = False;
+#testing = True;
+if testing:
+	fcserialnumber = 42; #18=>90,269,16 ; 42 => 21,61;
+
+class fuelcell:
+	def __init__(self, x, y, serialnumber):
+		self.positionX = x;
+		self.positionY = y;
+		self.rackID = self.positionX + 10;
+		self.powerlevel = self.rackID * self.positionY;
+		self.powerlevel += serialnumber;
+		self.powerlevel *= self.rackID;
+		self.powerlevel = self.powerlevel//100;
+		self.powerlevel = self.powerlevel%10;
+		self.powerlevel -= 5;
+	def coords(self):
+		print(f'Fuel Cell coordinates (x,y): {self.positionX},{self.positionY} ');
+	def __str__(self):
+		return f'{self.powerlevel}';
+		
+'''
+testinput = [[3,5,8],[122,79,57],[217,196,39],[101,153,71]];
+
+for t in testinput:
+	dummycell = fuelcell(t[0],t[1],t[2]);
+	print(t, " ->  ",dummycell.powerlevel);
+	dummycell.coords();
+	
+print("#############################");
+print();
+'''
+
+fcgrid = [];
+gridline = [];
+
+print("#############################");
+print("INITIATE BATTERY ARRAY");
+for Y in range(GridSize):
+	gridline.clear();
+	for X in range(GridSize):
+		gridline.append(fuelcell(X+1,Y+1,fcserialnumber));
+	fcgrid.append(gridline.copy());
+
+print("#############################");
+print("CALCULATE SQUARE SUBSUMS");
+sumtable = [];
+
+gridline.clear();
+gridline.append(fcgrid[0][0].powerlevel);
+
+for X in range(1,GridSize):
+	SubSumFc = fcgrid[0][X].powerlevel + gridline[X-1];
+	gridline.append(SubSumFc);
+sumtable.append(gridline.copy());
+
+currentsubsum = 0;
+
+for Y in range(1,GridSize):
+	gridline.clear();
+	SubSumFc = sumtable[Y-1][0] + fcgrid[Y][0].powerlevel;
+	gridline.append(SubSumFc);
+	currentsubsum = fcgrid[Y][0].powerlevel;
+	for X in range(1,GridSize):
+		currentsubsum += fcgrid[Y][X].powerlevel;
+		gridline.append(sumtable[Y-1][X] + currentsubsum);
+	sumtable.append(gridline.copy());
+
+print("#############################");
+print("SEARCH FOR HIGHEST SUBSUM SQUARE");
+
+maxpower = -999;
+maxX = 0;
+maxY = 0;
+powernow = 0;
+maxsquare = 0;
+
+for Y in range(1,GridSize-3):
+	ssy = GridSize - Y;
+	for X in range(1,GridSize-3):
+		ssx = GridSize - X;
+		SquareSize = (ssx>=ssy)*ssy + ssx*(ssx<ssy);
+		for s in range(SquareSize):
+			powernow = 0;
+			powernow = sumtable[Y+s][X+s] - sumtable[Y-1][X+s] - sumtable[Y+s][X-1] + sumtable[Y-1][X-1];
+			if (powernow > maxpower):
+				maxX = X;
+				maxY = Y;
+				maxpower = powernow;
+				maxsquare = s;
+				#print("new max power: ", maxpower, " // ", powernow);
+
+print("#############################");
+print("Results:");		
+print(maxX, "\t", maxY, "\t", maxsquare, "\t", maxpower);
+fcgrid[maxY][maxX].coords();
+print("winrar part 2:\t", fcgrid[maxY][maxX].positionX,",",fcgrid[maxY][maxX].positionY,",",maxsquare+1,end="");
+
diff --git a/2018/aoc2018-d12.py b/2018/aoc2018-d12.py
new file mode 100644
index 0000000..9922c39
--- /dev/null
+++ b/2018/aoc2018-d12.py
@@ -0,0 +1,68 @@
+#advent of code 2018 
+#day 12
+#part 1 & part 2
+
+generationnumber1 = 20; #part1
+generationnumber2 = 10000; #steady state 
+generationnumber3 = 50000000000; #part2
+
+f = open("input.txt", 'r');
+
+testing = False;
+#testing = True;
+if testing:
+	f.close();
+	f = open("testinput.txt", 'r');
+	
+PlantInitialState = f.readline();
+PlantInitialState = PlantInitialState.replace("initial state: ","");
+PlantInitialState = PlantInitialState.replace("\n","");
+f.readline();
+
+Notes = {};
+
+for l in f:
+	n1 = l[0:5];
+	n2 = l[9];
+	Notes[n1] = n2;
+	print(l, end="");
+
+#append to the beginning and the end an a=4 amount of pots
+#store the amount of appended pots
+
+PlantInitialState = "...." + PlantInitialState + "....";
+a = 4;
+PlantCurrentState = PlantInitialState;
+
+part1 = 0;
+
+for g in range(generationnumber2):
+	substate = PlantCurrentState[0:2];
+	substate += Notes.get(PlantCurrentState[0:5]);
+	for p in range(3,len(PlantCurrentState)-2):
+		substate += Notes.get(PlantCurrentState[p-2:p+3]);
+	substate += PlantCurrentState[-2:];
+	if(substate[2] == '#'):
+		substate = ".." + substate;
+		a += 2;
+	if(substate[-3] == '#'):
+		substate = substate + "..";
+	PlantCurrentState = substate;
+	if (g == generationnumber1 -1):
+		for pot in range(len(PlantCurrentState)):
+			if PlantCurrentState[pot] == '#':
+				part1 += pot - a;
+
+
+SteadyState10k = 0;
+for pot in range(len(PlantCurrentState)):
+	if PlantCurrentState[pot] == '#':
+		SteadyState10k += pot - a;
+
+gendiv = generationnumber3//generationnumber2;
+part2 = SteadyState10k*(gendiv);
+
+print("part1: ", part1);
+print("part2: ", part2);
+
+#2830 too low
diff --git a/2018/aoc2018-d14.py b/2018/aoc2018-d14.py
new file mode 100644
index 0000000..9e042d0
--- /dev/null
+++ b/2018/aoc2018-d14.py
@@ -0,0 +1,66 @@
+#advent of code 2018 
+#day 14
+#part 1 & part 2
+
+#there should be a faster way to compute the results
+#no idea how to do it at the moment
+
+import time
+
+f = open("input.txt",'r');
+myinput = int(f.readline());
+
+Testing = False;
+#Testing = True;
+if Testing:
+	f.close();
+	#f = open("testinput.txt",'r');
+	myinput = 9;
+	myinput = 5;
+	myinput = 18;
+	myinput = 2018;
+	
+recipes = [3,7];
+elf1 = 0;
+elf2 = 1;
+
+StillSearching = True;
+part2 = "";
+
+ElapsedTime = 0;
+starttime = time.time();
+
+while (StillSearching):
+	newrecipes = recipes[elf1] + recipes[elf2];
+	newrecipes = str(newrecipes);
+	for r in newrecipes:
+		recipes.append(int(r));
+	
+	move1 = 1 + recipes[elf1];
+	move2 = 1 + recipes[elf2];
+	elf1 = (move1 + elf1)%len(recipes);
+	elf2 = (move2 + elf2)%len(recipes);
+	
+	recipesstring = "";
+	for n in range(-len(str(myinput))-1,0):
+		recipesstring += str( recipes[n%len(recipes)] );
+		
+	if (recipesstring[:-1] == str(myinput)):
+		part2 = len(recipes) - len(str(myinput)) -1;
+		print("p2 ", part2);	
+	elif (recipesstring[1:] == str(myinput)):
+		part2 = len(recipes) - len(str(myinput));
+		print("p2 ", part2);
+	
+	if (len(recipes)>=myinput+10):
+		if (part2 != ""):
+			StillSearching = False;
+			
+part1 = "";
+for i in range(myinput,myinput+10):
+	part1 += str(recipes[i]);
+
+endtime = time.time() - starttime;
+print("FIN -- ", endtime, "sec");
+print("part 1: ", part1);
+print("part 2: ", part2);
diff --git a/2018/aoc2018-d16.py b/2018/aoc2018-d16.py
new file mode 100644
index 0000000..3bb0dc1
--- /dev/null
+++ b/2018/aoc2018-d16.py
@@ -0,0 +1,359 @@
+#advent of code 2018 
+#day 16
+#part 1 and part 2
+
+#when doing this puzzle I learned that I can make a list of functions and it just works
+#code could use a bit of clean up, 
+#lots of multiple lines because of 16 functions 
+#(I could save ~32 lines just by modifying the functions)
+#lots of work-arounds because I don't know to implement it efficently
+#but still, I got the results
+
+f = open("input.txt",'r');
+Testing = False;
+#Testing = True; 
+if Testing:
+	f.close();
+	f = open("testinput.txt",'r');
+
+input_part1 = [];
+input_part2 = [];
+sublist = [];
+
+for l in f:
+	l = l.replace("\n","");
+	if (len(l) == 0):
+		input_part1.append( sublist.copy() );
+		sublist = [];
+		continue;
+	elif (l == "###"):
+		break;
+	elif (len(l) < 20):
+		sublist.append( [int(x) for x in l.split(" ")] );
+	elif (l[6] == ":"):
+		sublist.append( eval(l[7:]) );
+	elif (l[5] == ":"):
+		sublist.append( eval(l[7:]) );
+'''
+for i in input_part1:
+	print(i[0], "\t", i[1], "\t", i[2], "\t")
+'''
+
+for l in f: 
+	l = l.replace("\n","");
+	input_part2.append( [int(x) for x in l.split(" ")] );
+
+'''
+print();
+print();
+print();
+for i in input_part2:
+	print(i);
+'''
+
+###opcode functions
+def addr(before, op, aft):
+	bef = before.copy();
+	C = bef[op[1]] + bef[op[2]];
+	bef[op[3]] = C;
+	return bef;
+def addi(before, op, aft):
+	bef = before.copy();
+	C = bef[op[1]] + op[2];
+	bef[op[3]] = C;
+	return bef;
+
+def mulr(before, op, aft):
+	bef = before.copy();
+	C = bef[op[1]] * bef[op[2]];
+	bef[op[3]] = C;
+	return bef;
+def muli(before, op, aft):
+	bef = before.copy();
+	C = bef[op[1]] * op[2];
+	bef[op[3]] = C;
+	return bef;
+
+def banr(before, op, aft):
+	bef = before.copy();
+	C = int(bef[op[1]] & bef[op[2]]);
+	bef[op[3]] = C;
+	return bef;
+def bani(before, op, aft):
+	bef = before.copy();
+	C = int(bef[op[1]] & op[2]);
+	bef[op[3]] = C;
+	return bef;
+
+def borr(before, op, aft):
+	bef = before.copy();
+	C = int(bef[op[1]] | bef[op[2]]);
+	bef[op[3]] = C;
+	return bef;
+def bori(before, op, aft):
+	bef = before.copy();
+	C = int(bef[op[1]] | op[2]);
+	bef[op[3]] = C;
+	return bef;
+
+def setr(before, op, aft):
+	bef = before.copy();
+	C = bef[op[1]];
+	bef[op[3]] = C;
+	return bef;
+def seti(before, op, aft):
+	bef = before.copy();
+	C = op[1];
+	bef[op[3]] = C;
+	return bef;
+
+def gtir(before, op, aft):
+	bef = before.copy();
+	C = 0 + int( op[1] > bef[op[2]] );
+	bef[op[3]] = C;
+	return bef;
+def gtri(before, op, aft):
+	bef = before.copy();
+	C = 0 + int( op[2] < bef[op[1]] );
+	bef[op[3]] = C;
+	return bef;
+def gtrr(before, op, aft):
+	bef = before.copy();
+	C = 0 + int( bef[op[1]] > bef[op[2]] );
+	bef[op[3]] = C;
+	return bef;
+
+def eqir(before, op, aft):
+	bef = before.copy();
+	C = 0 + int( op[1] == bef[op[2]] );
+	bef[op[3]] = C;
+	return bef;
+def eqri(before, op, aft):
+	bef = before.copy();
+	C = 0 + int( op[2] == bef[op[1]] );
+	bef[op[3]] = C;
+	return bef;
+def eqrr(before, op, aft):
+	bef = before.copy();
+	C = 0 + int( bef[op[1]] == bef[op[2]] );
+	bef[op[3]] = C;
+	return bef;
+
+
+def threeormore(bef, op, aft):
+	fun = 1;
+	counter = 0;
+	out = aft.copy();
+	counter += int( out == addr(bef,op,aft) );
+	counter += int( out == addi(bef,op,aft) );
+	counter += int( out == mulr(bef,op,aft) );
+	counter += int( out == muli(bef,op,aft) );
+	counter += int( out == banr(bef,op,aft) );
+	counter += int( out == bani(bef,op,aft) );
+	counter += int( out == borr(bef,op,aft) );
+	counter += int( out == bori(bef,op,aft) );
+	counter += int( out == setr(bef,op,aft) );
+	counter += int( out == seti(bef,op,aft) );
+	counter += int( out == gtir(bef,op,aft) );
+	counter += int( out == gtri(bef,op,aft) );
+	counter += int( out == gtrr(bef,op,aft) );
+	counter += int( out == eqir(bef,op,aft) );
+	counter += int( out == eqri(bef,op,aft) );
+	counter += int( out == eqrr(bef,op,aft) );
+	
+	return counter;
+	'''
+	if (counter >= 3):
+		return 1;
+	else:
+		return 0;
+'''
+
+part1 = 0;
+for sample in input_part1:
+	before = sample[0];
+	instruction = sample[1];
+	after = sample[2];
+	part1 += 1*(threeormore(before, instruction, after ) >=3);
+	
+print("part 1 = ", part1);
+	
+#776 yoo high
+#588 correct
+#my mistake - misunderstood bitwise AND and bitwise OR
+#they dont return a boolean, just a normal integer
+#my function was int(bool(value)), which was reducing the correct value to 1
+
+
+
+#identifying single matches
+'''
+singles = [];
+doubles = [];
+triples = [];
+
+for sample in input_part1:
+	before = sample[0];
+	instruction = sample[1];
+	after = sample[2];
+	if (threeormore(before, instruction, after ) == 1):
+		singles.append(instruction[0]);
+	if (threeormore(before, instruction, after ) == 2):
+		doubles.append(instruction[0]);
+	if (threeormore(before, instruction, after ) >= 3):
+		triples.append(instruction[0]);
+	#part1 += 1*(threeormore(before, instruction, after ) >=3);
+
+singles = list(dict.fromkeys(singles));
+doubles = list(dict.fromkeys(doubles));
+triples = list(dict.fromkeys(triples));
+
+print("singles\t",len(singles), "\t", singles);
+print("doubles\t",len(doubles), "\t", doubles);
+print("triples\t",len(triples), "\t", triples);
+'''
+
+
+
+def matchingfunctions(bef, op, aft):
+	functionlist = "";
+	out = aft.copy();
+	functionlist += "addr"*( out == addr(bef,op,aft) );
+	functionlist += "addi"*( out == addi(bef,op,aft) );
+	functionlist += "mulr"*( out == mulr(bef,op,aft) );
+	functionlist += "muli"*( out == muli(bef,op,aft) );
+	functionlist += "banr"*( out == banr(bef,op,aft) );
+	functionlist += "bani"*( out == bani(bef,op,aft) );
+	functionlist += "borr"*( out == borr(bef,op,aft) );
+	functionlist += "bori"*( out == bori(bef,op,aft) );
+	functionlist += "setr"*( out == setr(bef,op,aft) );
+	functionlist += "seti"*( out == seti(bef,op,aft) );
+	functionlist += "gtir"*( out == gtir(bef,op,aft) );
+	functionlist += "gtri"*( out == gtri(bef,op,aft) );
+	functionlist += "gtrr"*( out == gtrr(bef,op,aft) );
+	functionlist += "eqir"*( out == eqir(bef,op,aft) );
+	functionlist += "eqri"*( out == eqri(bef,op,aft) );
+	functionlist += "eqrr"*( out == eqrr(bef,op,aft) );
+	
+	return (op[0],functionlist);
+
+singles = [];
+doubles = [];
+triples = [];
+
+for sample in input_part1:
+	before = sample[0];
+	instruction = sample[1];
+	after = sample[2];
+	if (threeormore(before, instruction, after ) == 1):
+		singles.append(matchingfunctions(before, instruction, after ));
+	if (threeormore(before, instruction, after ) == 2):
+		doubles.append(matchingfunctions(before, instruction, after ));
+	if (threeormore(before, instruction, after ) >= 3):
+		triples.append(matchingfunctions(before, instruction, after ));
+	#part1 += 1*(threeormore(before, instruction, after ) >=3);
+
+'''
+print("singles\t",len(singles), "\t", singles);
+print("doubles\t",len(doubles), "\t", doubles);
+print("triples\t",len(triples), "\t", triples);
+'''
+
+singles = list(dict.fromkeys(singles));
+doubles = list(dict.fromkeys(doubles));
+triples = list(dict.fromkeys(triples));
+
+'''
+for s in singles:
+	print(s);
+print();
+print();
+for s in doubles:
+	print(s);
+print();
+print();
+for s in triples:
+	print(s);
+print();
+print();
+'''
+
+PossibleFunctions = {};
+total = singles + doubles + triples;
+
+for t in total:
+	PossibleFunctions.update({t[0] : t[1]});
+
+'''
+for pf in PossibleFunctions:
+	print(pf,"\t", PossibleFunctions[pf]);
+	'''
+
+IdentifiedFunctions = {};
+
+
+while (len(IdentifiedFunctions) < 16):
+	for found in IdentifiedFunctions:
+		for possible in PossibleFunctions:
+			if (len(PossibleFunctions[possible]) > 4 ):
+				s = PossibleFunctions[possible];
+				s = s.replace(IdentifiedFunctions[found], "");
+				PossibleFunctions.update({possible : s});
+			
+	for pf in PossibleFunctions:
+		if (len(PossibleFunctions[pf]) == 4 ):
+			IdentifiedFunctions.update({pf : PossibleFunctions[pf]});
+			
+	'''
+	for pf in PossibleFunctions:
+		print(pf,"\t", PossibleFunctions[pf]);
+	input();
+	'''
+
+'''
+print();
+print();
+print();
+print("Identified Functions");
+for pf in IdentifiedFunctions:
+	print(pf,"\t", IdentifiedFunctions[pf]);
+'''
+	
+MatchFunctions = {};
+MatchFunctions.update({"addr":addr});
+MatchFunctions.update({"addi":addi});
+MatchFunctions.update({"mulr":mulr});
+MatchFunctions.update({"muli":muli});
+MatchFunctions.update({"banr":banr});
+MatchFunctions.update({"bani":bani});
+MatchFunctions.update({"borr":borr});
+MatchFunctions.update({"bori":bori});
+MatchFunctions.update({"setr":setr});
+MatchFunctions.update({"seti":seti});
+MatchFunctions.update({"gtir":gtir});
+MatchFunctions.update({"gtri":gtri});
+MatchFunctions.update({"gtrr":gtrr});
+MatchFunctions.update({"eqir":eqir});
+MatchFunctions.update({"eqri":eqri});
+MatchFunctions.update({"eqrr":eqrr});
+	
+for i in IdentifiedFunctions:
+	MatchFunctions.update({i:MatchFunctions[IdentifiedFunctions[i]]});
+
+'''
+print();
+print();
+print();
+print("Matched Functions");
+for pf in MatchFunctions:
+	print(pf,"\t", MatchFunctions[pf]);
+'''
+
+reg = [0,0,0,0];
+for i in input_part2:
+	f_i = MatchFunctions[i[0]];
+	reg = f_i(reg, i, [] );
+
+part2 = reg[0];
+#print(reg);
+print("part 2 = ", part2);
diff --git a/2018/aoc2018-d18.py b/2018/aoc2018-d18.py
new file mode 100644
index 0000000..8d85635
--- /dev/null
+++ b/2018/aoc2018-d18.py
@@ -0,0 +1,131 @@
+#advent of code 2018 
+#day 18
+#part 1 and part 2
+
+#at first I thought I can find the loop by simply registering when a value "part2" is repeated once
+#(kind of like in an earlier puzzle for that year)
+#then I had a correct idea how to find the pattern, 
+#but didn't really know how to implement it efficently
+#pattern recognition is an implementation of solution provided by Michael Fogleman
+#adjusted to my current code
+#another issue I had was that I resumed the calculations for part 2 from the state after 10 minutes (part1)
+#I needed to save the initial state and then start over
+#could probably reduce the code to single loop instead of two separate loops for each part
+
+f = open("input.txt",'r');
+Testing = False;
+#Testing = True; 
+if Testing:
+	f.close();
+	f = open("testinput.txt",'r');
+
+size = 50;
+if Testing: size = 10;
+
+#part 1
+
+CurrentState = {};
+
+for r,l in enumerate(f):
+	#print(len(l));
+	for c,a in enumerate(l):
+		CurrentState.update({(r,c):a});
+InitialState = CurrentState.copy();
+f.close();
+
+for x in range(size):
+	for y in range(size):
+		print(CurrentState[(x,y)],end="");
+	print();
+
+#check if each adjacent position is still within grid range
+def GetAdjacent(Cords):
+	Adjacent = [];
+	if (Cords[0] -1 >= 0 and Cords[1]-1 >=0):
+		Adjacent.append( (Cords[0] -1,Cords[1]-1) );
+	if (Cords[0] -1 >= 0):
+		Adjacent.append( (Cords[0] -1,Cords[1]) );
+	if (Cords[0] -1 >= 0 and Cords[1]+1 < size):
+		Adjacent.append( (Cords[0] -1,Cords[1]+1) );
+	if (Cords[1]+1 < size):
+		Adjacent.append( (Cords[0],Cords[1]+1) );
+	if (Cords[1]-1 >= 0):
+		Adjacent.append( (Cords[0],Cords[1]-1) );
+	if (Cords[0] +1 < size and Cords[1]-1 >=0):
+		Adjacent.append( (Cords[0] +1,Cords[1]-1) );
+	if (Cords[0] +1 < size):
+		Adjacent.append( (Cords[0] +1,Cords[1]) );
+	if (Cords[0] +1 < size and Cords[1]+1 < size):
+		Adjacent.append( (Cords[0] +1,Cords[1]+1) );
+	return Adjacent;
+	
+def GetAcres(area, adj):
+	acres = [];
+	for c in adj:
+		acres.append(area[c]);
+	return acres;
+
+def ChangeState(area, Cords):
+	s = area[Cords];
+	adj = GetAdjacent(Cords);
+	Acres = GetAcres(area, adj);
+	if (s == "." and Acres.count("|")>=3):
+		s = "|";
+	elif (s == "|" and Acres.count("#")>=3):
+		s = "#";
+	elif (s == "#" and Acres.count("#")>=1 and Acres.count("|")>=1):
+		s = "#";
+	elif (s == "#"):
+		s = ".";
+	return s;
+
+SimTime = 10; #minutes
+
+InitialState = CurrentState.copy();
+for t in range(SimTime):
+	NextState = {};
+	for x in range(size):
+		for y in range(size):
+			NextState.update({(x,y):ChangeState(CurrentState,(x,y))});
+	CurrentState = NextState.copy();
+	'''
+	print("MINUTE ",t);
+	for x in range(size):
+		for y in range(size):
+			print(CurrentState[(x,y)],end="");
+		print();
+	print();
+	'''
+summary = list(CurrentState.values());
+
+woods = summary.count("|");
+lumbs = summary.count("#");
+part1 = woods*lumbs;
+print("part 1 = ", part1);
+
+#part 2
+
+SimTime2 = 1000000000; #minutes for part2
+values = {};
+prev = 0;
+
+CurrentState = InitialState.copy();
+for t in range(1,SimTime2):
+	NextState = {};
+	for x in range(size):
+		for y in range(size):
+			NextState.update({(x,y):ChangeState(CurrentState,(x,y))});
+	CurrentState = NextState.copy();
+	summary = list(CurrentState.values());
+	woods = summary.count("|");
+	lumbs = summary.count("#");
+	part2 = woods*lumbs;
+	loop = t - values.get(part2,0);
+	if (loop == prev):
+		if SimTime2%loop == t%loop:
+			break;
+	values[part2]=t;
+	prev = loop;
+
+print("part 2 = ", part2);
+
-- 
cgit v1.2.3