{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "inputname = \"input\"\n",
    "xdim = 101\n",
    "ydim = 103\n",
    "\n",
    "def read_vectors():\n",
    "    with open(inputname , 'r' ) as infile:\n",
    "        for line in infile.readlines():\n",
    "            p,v = (line.strip().split(\" \"))\n",
    "            _,p = p.split('=')\n",
    "            _,v = v.split('=')\n",
    "            p = np.array(p.split(',')).astype(int)\n",
    "            v = np.array(v.split(',')).astype(int)\n",
    "            yield p,v\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {},
   "outputs": [],
   "source": [
    "def calc_positions(vectors,time,xdim,ydim):\n",
    "    for p,v in vectors:\n",
    "        # new position = Postion plus velocity * time\n",
    "        x,y = p+(time*v)\n",
    "        # wrapping around\n",
    "        x = (x % xdim + xdim) % xdim\n",
    "        y = (y % ydim + ydim) % ydim\n",
    "        yield x,y\n",
    "\n",
    "\n",
    "def count_quadrants(vectors,xdim,ydim):\n",
    "    vectors=np.array(vectors,dtype=int)\n",
    "    xmid=xdim//2\n",
    "    ymid=ydim//2\n",
    "    top_right = (vectors[:,0]>xmid) & (vectors[:,1]>ymid)\n",
    "    top_left = (vectors[:,0]<xmid) & (vectors[:,1]>ymid)\n",
    "    bottom_left = (vectors[:,0]<xmid) & (vectors[:,1]<ymid)\n",
    "    bottom_right = (vectors[:,0]>xmid) & (vectors[:,1]<ymid)\n",
    "    counts = {\n",
    "        \"top_right\": np.sum(top_right),\n",
    "        \"top_left\": np.sum(top_left),\n",
    "        \"bottom_left\": np.sum(bottom_left),\n",
    "        \"bottom_right\": np.sum(bottom_right),\n",
    "    }\n",
    "    \n",
    "    return counts\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {},
   "outputs": [],
   "source": [
    "positions = [ (x,y) for x,y in calc_positions(read_vectors(),100,xdim,ydim)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.int64(231221760)"
      ]
     },
     "execution_count": 119,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import math\n",
    "math.prod(count_quadrants(positions,xdim,ydim).values())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy.ndimage import label\n",
    "\n",
    "def pos_to_binmap(positions,xdim,ydim):\n",
    "    temp_map = np.full((xdim,ydim),False)\n",
    "    for x,y in positions:\n",
    "        temp_map[x,y]=True\n",
    "    return temp_map\n",
    " \n",
    "\n",
    "def biggest_cluster(positions,xdim,ydim):\n",
    "    grid = np.array(positions) # Convert to numpy array if not already\n",
    "    binary_map = pos_to_binmap(grid,xdim,ydim)\n",
    "    labeled_map, num_features = label(binary_map)\n",
    "    maxsize = 0\n",
    "    for cluster_id in range(1, num_features + 1):\n",
    "        cluster_mask = (labeled_map == cluster_id) # Mask for current cluster\n",
    "        size = cluster_mask.sum() # Size of the cluster\n",
    "        if size > maxsize:\n",
    "            maxsize = size\n",
    "    \n",
    "    return maxsize\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 13580 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def draw_bitmap_map(points, xdim, ydim, title=None):\n",
    "    # Initialize a bitmap with all zeros\n",
    "    bitmap = np.zeros((ydim, xdim), dtype=int)\n",
    "    \n",
    "    # Mark positions based on the points\n",
    "    for point in points:\n",
    "        # Ensure the point is within the grid bounds\n",
    "        x, y = point\n",
    "        if 0 <= x < xdim and 0 <= y < ydim:\n",
    "            bitmap[y, x] = 1  # Mark the position with a 1\n",
    "    \n",
    "    # Plot the bitmap as an image\n",
    "    plt.imshow(bitmap, cmap='Greys', interpolation='nearest')\n",
    "    if title:\n",
    "        plt.title(title)\n",
    "    plt.show()\n",
    "\n",
    "positions = [ (x,y) for x,y in calc_positions(read_vectors(),100,xdim,ydim)]\n",
    "draw_bitmap_map(positions, xdim, ydim)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 19508 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 19652 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 19428 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 19728 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 19952 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 19128 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "i=0\n",
    "oldmax=0\n",
    "while oldmax<100:\n",
    "    i+=1\n",
    "    positions = [ (x,y) for x,y in calc_positions(read_vectors(),i,xdim,ydim)]\n",
    "    max=biggest_cluster(positions,xdim,ydim)\n",
    "    if max>oldmax:\n",
    "        draw_bitmap_map(positions,xdim,ydim,f\"cluster of {max} pixels found in step {i}\")\n",
    "        oldmax=max\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pdf",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
