{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import re\n",
    "\n",
    "pattern= re.compile(r'''[XY][+=](\\d+)''')   #Pattern to Extract Values\n",
    "\n",
    "def readfile(infilename='testinput',offset=0):\n",
    "    with open(infilename,'r') as infile:\n",
    "        for idx,line in enumerate(infile.readlines()):\n",
    "            line = line.strip()\n",
    "            # on empty line yield result and reset\n",
    "            if line =='':\n",
    "                continue\n",
    "            # grep X/Y Values from Line\n",
    "            matches = pattern.findall(line)\n",
    "            if \"Button A\" in line:  #A Button Presses are X in my equation > first column of A\n",
    "                A=np.zeros((2,2),dtype=int)\n",
    "                A[:,0]=matches\n",
    "            if \"Button B\" in line:  #B Button Presses are Y in my equation > second column of A\n",
    "                A[:,1]=matches\n",
    "            if \"Prize:\" in line:    #Prize Position is the result of solving the equation > B\n",
    "                B=np.array(matches,dtype=int)+np.array([offset,offset]) #offset added for part 2\n",
    "                solution = np.linalg.solve(A.astype(int),B.astype(int))\n",
    "                # remove non integer Solutions by rounding and checking validity of solution\n",
    "                reverse = np.dot(A,np.round(solution))\n",
    "                validation = np.all(np.equal(reverse,B.astype(int)))\n",
    "                solution = solution.round().astype(int) if validation else None\n",
    "                yield solution\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Part 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.int64(28753)"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum((np.sum(x*[3,1]) for x in readfile('input') if x is not None ))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Part 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.int64(102718967795500)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum((np.sum(x*[3,1]) for x in readfile('input',offset=10000000000000) if x is not None ))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "advent",
   "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.13.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
