{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a9683468",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Defaulting to user installation because normal site-packages is not writeable\n",
      "Requirement already satisfied: flask in /home/student/.local/lib/python3.10/site-packages (2.3.2)\n",
      "Requirement already satisfied: Jinja2>=3.1.2 in /home/student/.local/lib/python3.10/site-packages (from flask) (3.1.4)\n",
      "Requirement already satisfied: itsdangerous>=2.1.2 in /home/student/.local/lib/python3.10/site-packages (from flask) (2.2.0)\n",
      "Requirement already satisfied: Werkzeug>=2.3.3 in /home/student/.local/lib/python3.10/site-packages (from flask) (3.0.3)\n",
      "Requirement already satisfied: click>=8.1.3 in /home/student/.local/lib/python3.10/site-packages (from flask) (8.1.7)\n",
      "Requirement already satisfied: blinker>=1.6.2 in /home/student/.local/lib/python3.10/site-packages (from flask) (1.8.2)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /home/student/.local/lib/python3.10/site-packages (from Jinja2>=3.1.2->flask) (2.1.5)\n"
     ]
    }
   ],
   "source": [
    "!pip install flask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aeee415d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "import os\n",
    "import typing\n",
    "import flask\n",
    "\n",
    "from flask import Flask\n",
    "from flask import request\n",
    "\n",
    "print(\"Starting Battlesnake Server...\")\n",
    "\n",
    "def run_server(handlers: typing.Dict):\n",
    "    app = Flask(__name__)\n",
    "\n",
    "    @app.get(\"/\")\n",
    "    def on_info():\n",
    "        print(\"info\")\n",
    "        return handlers[\"info\"]()\n",
    "\n",
    "    @app.post(\"/start\")\n",
    "    def on_start():\n",
    "        print(\"go!\")\n",
    "        game_state = request.get_json()\n",
    "        handlers[\"start\"](game_state)\n",
    "        return \"ok\"\n",
    "\n",
    "    @app.post(\"/move\")\n",
    "    def on_move():\n",
    "        game_state = request.get_json()\n",
    "        return handlers[\"move\"](game_state)\n",
    "\n",
    "    @app.post(\"/end\")\n",
    "    def on_end():\n",
    "# This isn't being called by the CLI atm\n",
    "#        print(request.get_json())\n",
    "#        end_game = request.get_json()\n",
    "#        print(end_game[\"death\"])\n",
    "        handlers[\"end\"](end_game)\n",
    "        return \"ok\"\n",
    "\n",
    "    @app.after_request\n",
    "    def identify_server(response):\n",
    "        response.headers.set(\n",
    "            \"server\", \"battlesnake/github/starter-snake-python\"\n",
    "        )\n",
    "        return response\n",
    "\n",
    "\n",
    "    host = \"::\"\n",
    "    port = int(os.environ.get(\"PORT\", \"8000\"))\n",
    "\n",
    "    logging.getLogger(\"werkzeug\").setLevel(logging.ERROR)\n",
    "\n",
    "    print(f\"\\nRunning Battlesnake at http://{host}:{port}\")\n",
    "    app.run(host=host, port=port)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11a8ff03",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Welcome to\n",
    "# __________         __    __  .__                               __\n",
    "# \\______   \\_____ _/  |__/  |_|  |   ____   ______ ____ _____  |  | __ ____\n",
    "#  |    |  _/\\__  \\\\   __\\   __\\  | _/ __ \\ /  ___//    \\\\__  \\ |  |/ // __ \\\n",
    "#  |    |   \\ / __ \\|  |  |  | |  |_\\  ___/ \\___ \\|   |  \\/ __ \\|    <\\  ___/\n",
    "#  |________/(______/__|  |__| |____/\\_____>______>___|__(______/__|__\\\\_____>\n",
    "#\n",
    "# This file can be a nice home for your Battlesnake logic and helper functions.\n",
    "#\n",
    "# To get you started we've included code to prevent your Battlesnake from moving backwards.\n",
    "# For more info see docs.battlesnake.com\n",
    "\n",
    "import random\n",
    "import typing\n",
    "\n",
    "# info is called when you create your Battlesnake on play.battlesnake.com\n",
    "# and controls your Battlesnake's appearance\n",
    "# TIP: If you open your Battlesnake URL in a browser you should see this data\n",
    "def info() -> typing.Dict:\n",
    "    print(\"INFO\")\n",
    "#MMMM   CUSTOMIZATIONS\n",
    "    return {\n",
    "        \"apiversion\": \"1\",\n",
    "        \"author\": \"MaybeMadelyn\",  # TODO: Your Battlesnake Username\n",
    "        \"color\": \"#d5dbdb\",  # TODO: Choose color\n",
    "        \"head\": \"default\",  # TODO: Choose head\n",
    "        \"tail\": \"default\",  # TODO: Choose tail\n",
    "    }\n",
    "\n",
    "\n",
    "# start is called when your Battlesnake begins a game\n",
    "def start(game_state: typing.Dict):\n",
    "    global start_snake_count\n",
    "    start_snake_count = len(game_state['board']['snakes'])\n",
    "    print(\"GAME START with \", start_snake_count,\" snakes\")\n",
    "\n",
    "\n",
    "# end is called when your Battlesnake finishes a game\n",
    "# this is not happening right now :/\n",
    "def end(end_game: typing.Dict):\n",
    "#    ending = end_game['death']\n",
    "    print(\"GAME OVER. You died by: \",ending)    \n",
    "\n",
    "    \n",
    "def search(targets, my_head, move_points, points):\n",
    "    if targets:\n",
    "        closest = targets[0]\n",
    "        distance = 100\n",
    "        \n",
    "        for target in targets:\n",
    "            x_distance = abs(my_head[\"x\"] - target[\"x\"])\n",
    "            y_distance = abs(my_head[\"y\"] - target[\"y\"])\n",
    "            \n",
    "            if x_distance + y_distance < distance:\n",
    "                closest = target\n",
    "                distance = x_distance + y_distance\n",
    "                \n",
    "        if closest[\"x\"] < my_head[\"x\"]:\n",
    "            move_points[\"left\"] += points\n",
    "        if closest[\"x\"] > my_head[\"x\"]:\n",
    "            move_points[\"right\"] += points\n",
    "        if closest[\"y\"] < my_head[\"y\"]:\n",
    "            move_points[\"down\"] += points\n",
    "        if closest[\"y\"] > my_head[\"y\"]:\n",
    "            move_points[\"up\"] += points\n",
    "            \n",
    "            \n",
    "def search_head(targets, my_head, move_points, points):\n",
    "    if targets:\n",
    "        closest = targets[0]\n",
    "        distance = 100\n",
    "        \n",
    "        for target in targets:\n",
    "            x_distance = abs(my_head[\"x\"] - target[\"x\"])\n",
    "            y_distance = abs(my_head[\"y\"] - target[\"y\"])\n",
    "            \n",
    "            if x_distance + y_distance < distance:\n",
    "                closest = target\n",
    "                distance = x_distance + y_distance\n",
    "                \n",
    "        if closest[\"x\"] < my_head[\"x\"]:\n",
    "            move_points[\"left\"] += points\n",
    "        if closest[\"x\"] > my_head[\"x\"]:\n",
    "            move_points[\"right\"] += points\n",
    "        if closest[\"y\"] < my_head[\"y\"]:\n",
    "            move_points[\"down\"] += points\n",
    "        if closest[\"y\"] > my_head[\"y\"]:\n",
    "            move_points[\"up\"] += points\n",
    "            \n",
    "\n",
    "    search(game_state[\"board\"][\"food\"], my_head, move_points, 20)\n",
    "    search(game_state[\"board\"][\"snakes\"], my_head, move_points, 20)         \n",
    "#mmmm FLOODFILL FUNCTION\n",
    "def floodfill(snakes,start):\n",
    "    empty_spaces = 0\n",
    "    visited = []\n",
    "    to_visit = [start]                         \n",
    "    unsafe = []\n",
    "    for snake in snakes:\n",
    "        for body_part in snake[\"body\"]:\n",
    "            unsafe.append(body_part) #mmmm APPEND means adding something to the list\n",
    "    in_bounds = True\n",
    "    while to_visit:   \n",
    "        in_bounds = not(to_visit[0][\"y\"] < 0 or to_visit[0][\"y\"] > 10 or to_visit[0][\"x\"] < 0 or to_visit[0][\"x\"] > 10)\n",
    "        if to_visit[0] not in unsafe and in_bounds and to_visit[0] not in visited:\n",
    "            empty_spaces += 1\n",
    "            to_visit.append({\"x\": to_visit[0][\"x\"] +1, \"y\": to_visit[0][\"y\"]})\n",
    "            to_visit.append({\"x\": to_visit[0][\"x\"] -1, \"y\": to_visit[0][\"y\"]})\n",
    "            to_visit.append({\"x\": to_visit[0][\"x\"], \"y\": to_visit[0][\"y\"] +1})\n",
    "            to_visit.append({\"x\": to_visit[0][\"x\"], \"y\": to_visit[0][\"y\"] -1})\n",
    "            \n",
    "        visited.append(to_visit[0])\n",
    "        to_visit.pop(0)\n",
    "        \n",
    "    return empty_spaces\n",
    "\n",
    "            \n",
    "# move is called on every turn and returns your next move\n",
    "# Valid moves are \"up\", \"down\", \"left\", or \"right\"\n",
    "# See https://docs.battlesnake.com/api/example-move for available data\n",
    "def move(game_state: typing.Dict) -> typing.Dict:\n",
    "\n",
    "    move_points = {\"up\": 10, \"down\": 10, \"left\": 10, \"right\": 10}\n",
    "    moves = [\"up\", \"down\", \"left\", \"right\"]\n",
    "\n",
    "    # We've included code to prevent your Battlesnake from moving backwards\n",
    "    my_head = game_state[\"you\"][\"body\"][0]  # Coordinates of your head\n",
    "    my_neck = game_state[\"you\"][\"body\"][1]  # Coordinates of your \"neck\"\n",
    "    my_body = game_state['you']['body']\n",
    "\n",
    "    if my_neck[\"x\"] < my_head[\"x\"]:  # Neck is left of head, don't move left\n",
    "        move_points[\"left\"] = 0\n",
    "\n",
    "    elif my_neck[\"x\"] > my_head[\"x\"]:  # Neck is right of head, don't move right\n",
    "        move_points[\"right\"] = 0\n",
    "\n",
    "    elif my_neck[\"y\"] < my_head[\"y\"]:  # Neck is below head, don't move down\n",
    "        move_points[\"down\"] = 0\n",
    "\n",
    "    elif my_neck[\"y\"] > my_head[\"y\"]:  # Neck is above head, don't move up\n",
    "        move_points[\"up\"] = 0\n",
    "\n",
    "   #MMMM MAKE SURE YOU DONT HIT THE WALL\n",
    "\n",
    "    game_height = game_state[\"board\"][\"height\"]\n",
    "    game_width = game_state[\"board\"][\"width\"]\n",
    "    \n",
    "    \n",
    "    if my_head[\"y\"] == game_height - 1:\n",
    "        move_points[\"up\"] -= 1000\n",
    "    \n",
    "    if my_head[\"y\"] == 0:\n",
    "        move_points[\"down\"] -= 1000\n",
    "        \n",
    "    if my_head[\"x\"] == game_width - 1:\n",
    "        move_points[\"right\"] -= 1000\n",
    "        print(\"DONT GO RIGHT!\")\n",
    "        print(f\"Right points: {move_points['right']}\")\n",
    "\n",
    "    if my_head[\"x\"] == 0:\n",
    "        move_points[\"left\"] -= 1000\n",
    "        \n",
    "        \n",
    "    #MMMM DONT RUN INTO YOURSELF\n",
    "    \n",
    "    for body_part in my_body:\n",
    "        if body_part[\"y\"] == my_head[\"y\"]+1 and body_part[\"x\"] == my_head[\"x\"]:\n",
    "            move_points[\"up\"] -= 1000\n",
    "            \n",
    "        if body_part[\"y\"] == my_head[\"y\"]-1 and body_part[\"x\"] == my_head[\"x\"]:\n",
    "            move_points[\"down\"] -= 1000\n",
    "            \n",
    "        if body_part[\"x\"] == my_head[\"x\"]+1 and body_part[\"y\"] == my_head[\"y\"]:\n",
    "            move_points[\"right\"] -= 1000\n",
    "            \n",
    "        if body_part[\"x\"] == my_head[\"x\"]-1 and body_part[\"y\"] == my_head[\"y\"]:\n",
    "            move_points[\"left\"] -= 1000\n",
    "            \n",
    "    #MMMM DONT RUN INTO OTHER SNAKES\n",
    "    \n",
    "    all_snakes = game_state[\"board\"][\"snakes\"]\n",
    "    for snakes in all_snakes:\n",
    "        for body_part in snakes[\"body\"]:\n",
    "            if body_part[\"y\"] == my_head[\"y\"]+1 and body_part[\"x\"] == my_head[\"x\"]:\n",
    "                move_points[\"up\"] -= 1000\n",
    "\n",
    "            if body_part[\"y\"] == my_head[\"y\"]-1 and body_part[\"x\"] == my_head[\"x\"]:\n",
    "                move_points[\"down\"] -= 1000\n",
    "\n",
    "            if body_part[\"x\"] == my_head[\"x\"]+1 and body_part[\"y\"] == my_head[\"y\"]:\n",
    "                move_points[\"right\"] -= 1000\n",
    "\n",
    "            if body_part[\"x\"] == my_head[\"x\"]-1 and body_part[\"y\"] == my_head[\"y\"]:\n",
    "                move_points[\"left\"] -= 1000\n",
    "                \n",
    "    move_points[\"right\"] += floodfill(all_snakes, {\"x\": my_head[\"x\"] +1, \"y\": my_head[\"y\"]})\n",
    "    move_points[\"left\"] += floodfill(all_snakes, {\"x\": my_head[\"x\"] -1, \"y\": my_head[\"y\"]})\n",
    "    move_points[\"up\"] += floodfill(all_snakes, {\"x\": my_head[\"x\"] , \"y\": my_head[\"y\"] +1})\n",
    "    move_points[\"down\"] += floodfill(all_snakes, {\"x\": my_head[\"x\"] , \"y\": my_head[\"y\"] -1})\n",
    "\n",
    "    \n",
    "    #mmmm EAT SOME FOOD         \n",
    "    #bfs\n",
    "                \n",
    "    # Compare all of the moves to create a list of all moves with the highest score\n",
    "    print(f\"Right points: {move_points['right']}\")\n",
    "    best_moves = []\n",
    "    for move, points in move_points.items():\n",
    "        if len(best_moves) == 0:\n",
    "            best_moves.append(move)\n",
    "        else:\n",
    "            for good_move in best_moves:\n",
    "                if points > move_points[good_move]:\n",
    "                    best_moves.clear()\n",
    "                    best_moves.append(move)\n",
    "                elif points == move_points[good_move]:\n",
    "                    best_moves.append(move)\n",
    "                    break\n",
    "                    \n",
    "    # Choose a random move from the best choices\n",
    "    print(f\"Right points: {move_points['right']}\")\n",
    "    next_move = random.choice(best_moves)\n",
    "    # TODO: Step 4 - Move towards food instead of random, to regain health and survive longer\n",
    "    # food = game_state['board']['food']\n",
    "\n",
    "    print(f\"MOVE {game_state['turn']}: {next_move}\")\n",
    "    print(f\"MOVE {game_state['turn']} POINTS: UP - {move_points['up']}, DOWN - {move_points['down']}, LEFT - {move_points['left']}, RIGHT - {move_points['right']}\")\n",
    "    return {\"move\": next_move}\n",
    "\n",
    "run_server({\"info\": info, \"start\": start, \"move\": move, \"end\": end})\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "845e510c",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
