import math
import sys



class    lowercase_    :



							def __init__(						self				):
													_snake_case						:     int				=    0
													_snake_case						:     List[Any]				=    []
													_snake_case						:     Union[str, Any]				=    {}  # To store the pos of node in array



							def        UpperCamelCase       (						self				):
													return self.cur_size == 0



							def        UpperCamelCase       (						self      ,				lowercase_				):
													_snake_case						:     Optional[int]				=    self.left(lowercase_				)
													_snake_case						:     List[str]				=    self.right(lowercase_				)
													if lc < self.cur_size and self.array(lowercase_				)[0] < self.array(lowercase_				)[0]:
																			_snake_case						:     List[Any]				=    lc
													else:
																			_snake_case						:     int				=    idx
													if rc < self.cur_size and self.array(lowercase_				)[0] < self.array(lowercase_				)[0]:
																			_snake_case						:     str				=    rc
													if smallest != idx:
																			self.swap(lowercase_      ,				lowercase_				)
																			self.min_heapify(lowercase_				)



							def        UpperCamelCase       (						self      ,				lowercase_				):
													# Inserts a node into the Priority Queue
													_snake_case						:     List[Any]				=    self.cur_size
													self.cur_size += 1
													self.array.append((sys.maxsize, tup[1])				)
													self.decrease_key((sys.maxsize, tup[1])      ,				tup[0]				)



							def        UpperCamelCase       (						self				):
													# Removes and returns the min element at top of priority queue
													_snake_case						:     List[Any]				=    self.array[0][1]
													_snake_case						:     Tuple				=    self.array[self.cur_size - 1]
													self.cur_size -= 1
													self.min_heapify(1				)
													del self.pos[min_node]
													return min_node



							def        UpperCamelCase       (						self      ,				lowercase_				):
													# returns the index of left child
													return 2 * i + 1



							def        UpperCamelCase       (						self      ,				lowercase_				):
													# returns the index of right child
													return 2 * i + 2



							def        UpperCamelCase       (						self      ,				lowercase_				):
													# returns the index of parent
													return math.floor(i / 2				)



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_				):
													# swaps array elements at indices i and j
													# update the pos{}
													_snake_case						:     Optional[int]				=    j
													_snake_case						:     List[Any]				=    i
													_snake_case						:     str				=    self.array[i]
													_snake_case						:     List[Any]				=    self.array[j]
													_snake_case						:     Dict				=    temp



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_				):
													_snake_case						:     Tuple				=    self.pos[tup[1]]
													# assuming the new_d is atmost old_d
													_snake_case						:     int				=    (new_d, tup[1])
													while idx > 0 and self.array[self.par(lowercase_				)][0] > self.array[idx][0]:
																			self.swap(lowercase_      ,				self.par(lowercase_				)				)
																			_snake_case						:     Optional[Any]				=    self.par(lowercase_				)




class    lowercase_    :



							def __init__(						self      ,				lowercase_				):
													_snake_case						:     List[Any]				=    {}  # To store graph: u -> (v,w)
													_snake_case						:     List[Any]				=    num  # Number of nodes in graph
													# To store the distance from source vertex
													_snake_case						:     Dict				=    [0] * self.num_nodes
													_snake_case						:     Optional[Any]				=    [-1] * self.num_nodes  # To store the path



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_      ,				lowercase_				):
													#  Edge going from node u to v and v to u with weight w
													# u (w)-> v, v (w) -> u
													# Check if u already in graph
													if u in self.adjList:
																			self.adjList[u].append((v, w)				)
													else:
																			_snake_case						:     str				=    [(v, w)]

													# Assuming undirected graph
													if v in self.adjList:
																			self.adjList[v].append((u, w)				)
													else:
																			_snake_case						:     Any				=    [(u, w)]



							def        UpperCamelCase       (						self				):
													# u -> v(w)
													for u in self.adjList:
																			print(lowercase_      ,				"->"      ,				" -> ".join(str(f"""{v}({w})"""				) for v, w in self.adjList[u]				)				)



							def        UpperCamelCase       (						self      ,				lowercase_				):
													# Flush old junk values in par[]
													_snake_case						:     int				=    [-1] * self.num_nodes
													# src is the source node
													_snake_case						:     List[str]				=    0
													_snake_case						:     List[str]				=    PriorityQueue()
													q.insert((0, src)				)  # (dist from src, node)
													for u in self.adjList:
																			if u != src:
																									_snake_case						:     Union[str, Any]				=    sys.maxsize  # Infinity
																									_snake_case						:     Optional[Any]				=    -1

													while not q.is_empty():
																			_snake_case						:     Optional[Any]				=    q.extract_min()  # Returns node with the min dist from source
																			# Update the distance of all the neighbours of u and
																			# if their prev dist was INFINITY then push them in Q
																			for v, w in self.adjList[u]:
																									_snake_case						:     Optional[Any]				=    self.dist[u] + w
																									if self.dist[v] > new_dist:
																															if self.dist[v] == sys.maxsize:
																																					q.insert((new_dist, v)				)
																															else:
																																					q.decrease_key((self.dist[v], v)      ,				lowercase_				)
																															_snake_case						:     str				=    new_dist
																															_snake_case						:     str				=    u

        # Show the shortest distances from src
													self.show_distances(lowercase_				)



							def        UpperCamelCase       (						self      ,				lowercase_				):
													print(f"""Distance from node: {src}"""				)
													for u in range(self.num_nodes				):
																			print(f"""Node {u} has distance: {self.dist[u]}"""				)



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_				):
													# To show the shortest path from src to dest
													# WARNING: Use it *after* calling dijkstra
													_snake_case						:     Optional[Any]				=    []
													_snake_case						:     Optional[Any]				=    0
													_snake_case						:     Optional[int]				=    dest
													# Backtracking from dest to src
													while self.par[temp] != -1:
																			path.append(lowercase_				)
																			if temp != src:
																									for v, w in self.adjList[temp]:
																															if v == self.par[temp]:
																																					cost += w
																																					break
																			_snake_case						:     Optional[Any]				=    self.par[temp]
													path.append(lowercase_				)
													path.reverse()

													print(f"""----Path to reach {dest} from {src}----"""				)
													for u in path:
																			print(f"""{u}"""      ,				end=" "				)
																			if u != dest:
																									print("-> "      ,				end=""				)

													print("\nTotal cost of path: "      ,				lowercase_				)


if __name__ == "__main__":
				__SCREAMING_SNAKE_CASE						:    List[Any]     = Graph(9)
				graph.add_edge(0, 1, 4)
				graph.add_edge(0, 7, 8)
				graph.add_edge(1, 2, 8)
				graph.add_edge(1, 7, 1_1)
				graph.add_edge(2, 3, 7)
				graph.add_edge(2, 8, 2)
				graph.add_edge(2, 5, 4)
				graph.add_edge(3, 4, 9)
				graph.add_edge(3, 5, 1_4)
				graph.add_edge(4, 5, 1_0)
				graph.add_edge(5, 6, 2)
				graph.add_edge(6, 7, 1)
				graph.add_edge(6, 8, 6)
				graph.add_edge(7, 8, 7)
				graph.show_graph()
				graph.dijkstra(0)
				graph.show_path(0, 4)

# OUTPUT
# 0 -> 1(4) -> 7(8)
# 1 -> 0(4) -> 2(8) -> 7(11)
# 7 -> 0(8) -> 1(11) -> 6(1) -> 8(7)
# 2 -> 1(8) -> 3(7) -> 8(2) -> 5(4)
# 3 -> 2(7) -> 4(9) -> 5(14)
# 8 -> 2(2) -> 6(6) -> 7(7)
# 5 -> 2(4) -> 3(14) -> 4(10) -> 6(2)
# 4 -> 3(9) -> 5(10)
# 6 -> 5(2) -> 7(1) -> 8(6)
# Distance from node: 0
# Node 0 has distance: 0
# Node 1 has distance: 4
# Node 2 has distance: 12
# Node 3 has distance: 19
# Node 4 has distance: 21
# Node 5 has distance: 11
# Node 6 has distance: 9
# Node 7 has distance: 8
# Node 8 has distance: 14
# ----Path to reach 4 from 0----
# 0 -> 7 -> 6 -> 5 -> 4
# Total cost of path:  21
from __future__ import annotations

from PIL import Image

# Define the first generation of cells
# fmt: off
__SCREAMING_SNAKE_CASE						:    Optional[int]     = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
def 					snake_case						(__lowercase						)       ->       list[int]:

						'''simple docstring'''



						return [int(__lowercase						) for c in F"""{ruleset:08}"""[:8]]
def 					snake_case						(__lowercase					,			__lowercase					,			__lowercase						)       ->       list[int]:

						'''simple docstring'''



						_snake_case						:     Any				=    len(cells[0]						)  # 31
						_snake_case						:     str				=    []
						for i in range(__lowercase						):
												# Get the neighbors of each cell
												# Handle neighbours outside bounds by using 0 as their value
												_snake_case						:     Any				=    0 if i == 0 else cells[time][i - 1]
												_snake_case						:     List[str]				=    0 if i == population - 1 else cells[time][i + 1]
												# Define a new cell and add it to the new generation
												_snake_case						:     str				=    7 - int(F"""{left_neighbor}{cells[time][i]}{right_neighbor}"""					,			2						)
												next_generation.append(rule[situation]						)
						return next_generation
def 					snake_case						(__lowercase						)       ->       Image.Image:

						'''simple docstring'''



						_snake_case						:     str				=    Image.new("RGB"					,			(len(cells[0]						), len(__lowercase						))						)
						_snake_case						:     int				=    img.load()
						# Generates image
						for w in range(img.width						):
												for h in range(img.height						):
																		_snake_case						:     List[Any]				=    255 - int(255 * cells[h][w]						)
																		_snake_case						:     Union[str, Any]				=    (color, color, color)
						return img


if __name__ == "__main__":
				__SCREAMING_SNAKE_CASE						:    Any     = bin(int(input('Rule:\n').strip()))[2:]
				__SCREAMING_SNAKE_CASE						:    Tuple     = format_ruleset(int(rule_num))
				for time in range(1_6):
								CELLS.append(new_generation(CELLS, rule, time))
				__SCREAMING_SNAKE_CASE						:    List[Any]     = generate_image(CELLS)
				# Uncomment to save the image
				# img.save(f"rule_{rule_num}.png")
				img.show()