import colorsys
import io

import cva
import matplotlib as mpl
import matplotlib.colors as mplc
import matplotlib.figure as mplfigure
import numpy as np
import torch
from matplotlib.backends.backend_agg import FigureCanvasAgg

from utils import img_tensorize


__SCREAMING_SNAKE_CASE						:    Optional[Any]     = 1_0_0_0



class    lowercase_    :



							def __init__(						self      ,				lowercase_      ,				lowercase_=1.2      ,				lowercase_="g"      ,				lowercase_=0.5      ,				lowercase_="-"      ,				lowercase_="test_out.jpg"      ,				lowercase_=True      ,				lowercase_=False      ,				lowercase_=None      ,				lowercase_=None      ,				lowercase_=0.7      ,				):
													if isinstance(lowercase_      ,				torch.Tensor				):
																			_snake_case						:     List[str]				=    img.numpy().astype("np.uint8"				)
													if isinstance(lowercase_      ,				lowercase_				):
																			_snake_case						:     str				=    img_tensorize(lowercase_				)
													assert isinstance(lowercase_      ,				np.ndarray				)

													_snake_case				,_snake_case						:     Optional[int]				=    img.shape[1], img.shape[0]
													_snake_case						:     Any				=    mplfigure.Figure(frameon=lowercase_				)
													_snake_case						:     List[str]				=    fig.get_dpi()
													_snake_case						:     Dict				=    (width * scale + 1e-2) / dpi
													_snake_case						:     Any				=    (height * scale + 1e-2) / dpi
													fig.set_size_inches(lowercase_      ,				lowercase_				)
													_snake_case						:     Any				=    fig.add_axes([0.0, 0.0, 1.0, 1.0]				)
													ax.axis("off"				)
													ax.set_xlim(0.0      ,				lowercase_				)
													ax.set_ylim(lowercase_				)

													_snake_case						:     str				=    saveas
													_snake_case						:     Any				=    rgb
													_snake_case						:     List[Any]				=    pynb
													_snake_case						:     List[str]				=    img
													_snake_case						:     Any				=    edgecolor
													_snake_case						:     Optional[int]				=    0.5
													_snake_case						:     Optional[Any]				=    linestyle
													_snake_case						:     Dict				=    int(np.sqrt(min(lowercase_      ,				lowercase_				)				) * scale // 3				)
													_snake_case						:     Any				=    width
													_snake_case						:     int				=    height
													_snake_case						:     Optional[Any]				=    scale
													_snake_case						:     Optional[int]				=    fig
													_snake_case						:     Tuple				=    ax
													_snake_case						:     Optional[Any]				=    pad
													_snake_case						:     Optional[int]				=    idaobj
													_snake_case						:     List[str]				=    idaattr
													_snake_case						:     List[Any]				=    FigureCanvasAgg(lowercase_				)



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_=None				):
													if color is None:
																			_snake_case						:     Optional[Any]				=    self.edgecolor
													((_snake_case)				,(_snake_case)				,(_snake_case)				,(_snake_case))						:     Any				=    box
													_snake_case						:     List[Any]				=    xa - xa
													_snake_case						:     str				=    ya - ya
													self.ax.add_patch(
													    mpl.patches.Rectangle(
													        (xa, ya)      ,				lowercase_      ,				lowercase_      ,				fill=lowercase_      ,				edgecolor=lowercase_      ,				linewidth=self.font_size // 3      ,				alpha=self.alpha      ,				linestyle=self.linestyle      ,				)				)



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_=None      ,				lowercase_=None      ,				lowercase_=None      ,				lowercase_=None				):
													if len(boxes.shape				) > 2:
																			_snake_case						:     Tuple				=    boxes[0]
													if len(obj_ids.shape				) > 1:
																			_snake_case						:     List[str]				=    obj_ids[0]
													if len(obj_scores.shape				) > 1:
																			_snake_case						:     Optional[Any]				=    obj_scores[0]
													if len(attr_ids.shape				) > 1:
																			_snake_case						:     str				=    attr_ids[0]
													if len(attr_scores.shape				) > 1:
																			_snake_case						:     Optional[int]				=    attr_scores[0]
													if isinstance(lowercase_      ,				torch.Tensor				):
																			_snake_case						:     Optional[Any]				=    boxes.numpy()
													if isinstance(lowercase_      ,				lowercase_				):
																			_snake_case						:     Tuple				=    np.array(lowercase_				)
													assert isinstance(lowercase_      ,				np.ndarray				)
													_snake_case						:     int				=    np.prod(boxes[:, 2:] - boxes[:, :2]      ,				axis=1				)
													_snake_case						:     int				=    np.argsort(-areas				).tolist()
													_snake_case						:     str				=    boxes[sorted_idxs] if boxes is not None else None
													_snake_case						:     Optional[int]				=    obj_ids[sorted_idxs] if obj_ids is not None else None
													_snake_case						:     Any				=    obj_scores[sorted_idxs] if obj_scores is not None else None
													_snake_case						:     str				=    attr_ids[sorted_idxs] if attr_ids is not None else None
													_snake_case						:     List[Any]				=    attr_scores[sorted_idxs] if attr_scores is not None else None

													_snake_case						:     List[Any]				=    [self._random_color(maximum=1				) for _ in range(len(lowercase_				)				)]
													_snake_case						:     List[Any]				=    [assigned_colors[idx] for idx in sorted_idxs]
													if obj_ids is not None:
																			_snake_case						:     Optional[int]				=    self._create_text_labels_attr(lowercase_      ,				lowercase_      ,				lowercase_      ,				lowercase_				)
																			for i in range(len(lowercase_				)				):
																									_snake_case						:     Union[str, Any]				=    assigned_colors[i]
																									self.add_box(boxes[i]      ,				lowercase_				)
																									self.draw_labels(labels[i]      ,				boxes[i]      ,				lowercase_				)



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_      ,				lowercase_				):
													_snake_case				,_snake_case				,_snake_case				,_snake_case						:     Any				=    box
													_snake_case						:     Union[str, Any]				=    (xa, ya)
													_snake_case						:     List[Any]				=    (ya - ya) * (xa - xa)
													_snake_case						:     List[str]				=    _SMALL_OBJ * self.scale
													if instance_area < small or ya - ya < 40 * self.scale:
																			if ya >= self.height - 5:
																									_snake_case						:     Optional[Any]				=    (xa, ya)
																			else:
																									_snake_case						:     Optional[int]				=    (xa, ya)

													_snake_case						:     Union[str, Any]				=    (ya - ya) / np.sqrt(self.height * self.width				)
													_snake_case						:     Union[str, Any]				=    self._change_color_brightness(lowercase_      ,				brightness_factor=0.7				)
													_snake_case						:     Optional[Any]				=    np.clip((height_ratio - 0.02) / 0.08 + 1      ,				1.2      ,				2				)
													font_size *= 0.75 * self.font_size

													self.draw_text(
													    text=lowercase_      ,				position=lowercase_      ,				color=lowercase_      ,				)



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_      ,				lowercase_="g"      ,				lowercase_="left"      ,				):
													_snake_case						:     str				=    0
													_snake_case						:     Tuple				=    self.font_size
													_snake_case						:     int				=    np.maximum(list(mplc.to_rgb(lowercase_				)				)      ,				0.2				)
													_snake_case						:     Optional[Any]				=    max(0.8      ,				np.max(lowercase_				)				)
													_snake_case						:     Optional[int]				=    {
													    "facecolor": "black",
													    "alpha": self.alpha,
													    "pad": self.pad,
													    "edgecolor": "none",
													}
													_snake_case				,_snake_case						:     str				=    position
													self.ax.text(
													    lowercase_      ,				lowercase_      ,				lowercase_      ,				size=font_size * self.scale      ,				family="sans-serif"      ,				bbox=lowercase_      ,				verticalalignment="top"      ,				horizontalalignment=lowercase_      ,				color=lowercase_      ,				zorder=10      ,				rotation=lowercase_      ,				)



							def        UpperCamelCase       (						self      ,				lowercase_=None				):
													if saveas is None:
																			_snake_case						:     int				=    self.saveas
													if saveas.lower().endswith(".jpg"				) or saveas.lower().endswith(".png"				):
																			cva.imwrite(
																			    lowercase_      ,				self._get_buffer()[:, :, ::-1]      ,				)
													else:
																			self.fig.savefig(lowercase_				)



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_      ,				lowercase_      ,				lowercase_				):
													_snake_case						:     List[str]				=    [self.idaobj[i] for i in classes]
													_snake_case						:     List[Any]				=    [self.idaattr[i] for i in attr_classes]
													_snake_case						:     Dict				=    [
													    f"""{label} {score:.2f} {attr} {attr_score:.2f}"""
													    for label, score, attr, attr_score in zip(lowercase_      ,				lowercase_      ,				lowercase_      ,				lowercase_				)
													]
													return labels



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_				):
													_snake_case						:     int				=    [self.idaobj[i] for i in classes]
													if scores is not None:
																			if labels is None:
																									_snake_case						:     str				=    ["{:.0f}%".format(s * 100				) for s in scores]
																			else:
																									_snake_case						:     List[Any]				=    ["{} {:.0f}%".format(lowercase_      ,				s * 100				) for li, s in zip(lowercase_      ,				lowercase_				)]
													return labels



							def        UpperCamelCase       (						self      ,				lowercase_=255				):
													_snake_case						:     str				=    np.random.randint(0      ,				len(_COLORS				)				)
													_snake_case						:     int				=    _COLORS[idx] * maximum
													if not self.rgb:
																			_snake_case						:     int				=    ret[::-1]
													return ret



							def        UpperCamelCase       (						self				):
													if not self.pynb:
																			_snake_case				,_snake_case						:     Optional[Any]				=    self.canvas.print_to_buffer()
																			if (width, height) != (self.width, self.height):
																									_snake_case						:     Optional[int]				=    cva.resize(self.img      ,				(width, height)				)
																			else:
																									_snake_case						:     Dict				=    self.img
													else:
																			_snake_case						:     List[str]				=    io.BytesIO()  # works for cairo backend
																			self.canvas.print_rgba(lowercase_				)
																			_snake_case				,_snake_case						:     Dict				=    self.width, self.height
																			_snake_case						:     str				=    buf.getvalue()
																			_snake_case						:     Any				=    self.img

													_snake_case						:     Tuple				=    np.frombuffer(lowercase_      ,				dtype="uint8"				)
													_snake_case						:     List[Any]				=    buffer.reshape(lowercase_      ,				lowercase_      ,				4				)
													_snake_case				,_snake_case						:     int				=    np.split(lowercase_      ,				[3]      ,				axis=2				)

													try:
																			import numexpr as ne  # fuse them with numexpr

																			_snake_case						:     List[str]				=    ne.evaluate("img * (1 - alpha / 255.0) + rgb * (alpha / 255.0)"				)
													except ImportError:
																			_snake_case						:     str				=    alpha.astype("float32"				) / 255.0
																			_snake_case						:     str				=    img * (1 - alpha) + rgb * alpha

													return visualized_image.astype("uint8"				)



							def        UpperCamelCase       (						self      ,				lowercase_      ,				lowercase_				):
													assert brightness_factor >= -1.0 and brightness_factor <= 1.0
													_snake_case						:     str				=    mplc.to_rgb(lowercase_				)
													_snake_case						:     List[Any]				=    colorsys.rgb_to_hls(*mplc.to_rgb(lowercase_				)				)
													_snake_case						:     List[Any]				=    polygon_color[1] + (brightness_factor * polygon_color[1])
													_snake_case						:     Any				=    0.0 if modified_lightness < 0.0 else modified_lightness
													_snake_case						:     List[str]				=    1.0 if modified_lightness > 1.0 else modified_lightness
													_snake_case						:     Optional[Any]				=    colorsys.hls_to_rgb(polygon_color[0]      ,				lowercase_      ,				polygon_color[2]				)
													return modified_color




__SCREAMING_SNAKE_CASE						:    List[str]     = (
    np.array(
        [
            0.0_00,
            0.4_47,
            0.7_41,
            0.8_50,
            0.3_25,
            0.0_98,
            0.9_29,
            0.6_94,
            0.1_25,
            0.4_94,
            0.1_84,
            0.5_56,
            0.4_66,
            0.6_74,
            0.1_88,
            0.3_01,
            0.7_45,
            0.9_33,
            0.6_35,
            0.0_78,
            0.1_84,
            0.3_00,
            0.3_00,
            0.3_00,
            0.6_00,
            0.6_00,
            0.6_00,
            1.0_00,
            0.0_00,
            0.0_00,
            1.0_00,
            0.5_00,
            0.0_00,
            0.7_49,
            0.7_49,
            0.0_00,
            0.0_00,
            1.0_00,
            0.0_00,
            0.0_00,
            0.0_00,
            1.0_00,
            0.6_67,
            0.0_00,
            1.0_00,
            0.3_33,
            0.3_33,
            0.0_00,
            0.3_33,
            0.6_67,
            0.0_00,
            0.3_33,
            1.0_00,
            0.0_00,
            0.6_67,
            0.3_33,
            0.0_00,
            0.6_67,
            0.6_67,
            0.0_00,
            0.6_67,
            1.0_00,
            0.0_00,
            1.0_00,
            0.3_33,
            0.0_00,
            1.0_00,
            0.6_67,
            0.0_00,
            1.0_00,
            1.0_00,
            0.0_00,
            0.0_00,
            0.3_33,
            0.5_00,
            0.0_00,
            0.6_67,
            0.5_00,
            0.0_00,
            1.0_00,
            0.5_00,
            0.3_33,
            0.0_00,
            0.5_00,
            0.3_33,
            0.3_33,
            0.5_00,
            0.3_33,
            0.6_67,
            0.5_00,
            0.3_33,
            1.0_00,
            0.5_00,
            0.6_67,
            0.0_00,
            0.5_00,
            0.6_67,
            0.3_33,
            0.5_00,
            0.6_67,
            0.6_67,
            0.5_00,
            0.6_67,
            1.0_00,
            0.5_00,
            1.0_00,
            0.0_00,
            0.5_00,
            1.0_00,
            0.3_33,
            0.5_00,
            1.0_00,
            0.6_67,
            0.5_00,
            1.0_00,
            1.0_00,
            0.5_00,
            0.0_00,
            0.3_33,
            1.0_00,
            0.0_00,
            0.6_67,
            1.0_00,
            0.0_00,
            1.0_00,
            1.0_00,
            0.3_33,
            0.0_00,
            1.0_00,
            0.3_33,
            0.3_33,
            1.0_00,
            0.3_33,
            0.6_67,
            1.0_00,
            0.3_33,
            1.0_00,
            1.0_00,
            0.6_67,
            0.0_00,
            1.0_00,
            0.6_67,
            0.3_33,
            1.0_00,
            0.6_67,
            0.6_67,
            1.0_00,
            0.6_67,
            1.0_00,
            1.0_00,
            1.0_00,
            0.0_00,
            1.0_00,
            1.0_00,
            0.3_33,
            1.0_00,
            1.0_00,
            0.6_67,
            1.0_00,
            0.3_33,
            0.0_00,
            0.0_00,
            0.5_00,
            0.0_00,
            0.0_00,
            0.6_67,
            0.0_00,
            0.0_00,
            0.8_33,
            0.0_00,
            0.0_00,
            1.0_00,
            0.0_00,
            0.0_00,
            0.0_00,
            0.1_67,
            0.0_00,
            0.0_00,
            0.3_33,
            0.0_00,
            0.0_00,
            0.5_00,
            0.0_00,
            0.0_00,
            0.6_67,
            0.0_00,
            0.0_00,
            0.8_33,
            0.0_00,
            0.0_00,
            1.0_00,
            0.0_00,
            0.0_00,
            0.0_00,
            0.1_67,
            0.0_00,
            0.0_00,
            0.3_33,
            0.0_00,
            0.0_00,
            0.5_00,
            0.0_00,
            0.0_00,
            0.6_67,
            0.0_00,
            0.0_00,
            0.8_33,
            0.0_00,
            0.0_00,
            1.0_00,
            0.0_00,
            0.0_00,
            0.0_00,
            0.1_43,
            0.1_43,
            0.1_43,
            0.8_57,
            0.8_57,
            0.8_57,
            1.0_00,
            1.0_00,
            1.0_00,
        ]
    )
    .astype(np.floataa)
    .reshape(-1, 3)
)
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()