{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "54ae86a4", "metadata": {}, "outputs": [], "source": [ "from itertools import product, zip_longest, count\n", "import numpy as np\n", "from dataclasses import dataclass\n", "from matplotlib import pyplot as plt" ] }, { "cell_type": "code", "execution_count": null, "id": "e4756abb", "metadata": {}, "outputs": [], "source": [ "@dataclass\n", "class Rectangle:\n", " x: int\n", " y: int\n", " w: int\n", " h: int\n", "\n", "# Beware, axis 0 is vertical, axis 1 horizontal\n", "\n", "def measure(rectangles):\n", " w, h = 0, 0\n", " for rect in rectangles:\n", " w = max(w, rect.x + rect.w)\n", " h = max(h, rect.y + rect.h)\n", " return w, h\n", "\n", "def check_overlap(rectangles):\n", " w, h = measure(rectangles)\n", " image = np.zeros((h, w), dtype=int)\n", " for i, rect in enumerate(rectangles, start=1):\n", " if rect.x < 0 or rect.y < 0:\n", " raise ValueError(\"Rectangle placed out of bound\", rect)\n", " for x, y in product(range(rect.w), range(rect.h)):\n", " if image[rect.y + y, rect.x + x]:\n", " raise ValueError(f\"Overlap at {rect.x+x}, {rect.y+y}\", rectangles[i - 1], rectangles[image[rect.y + y, rect.x + x] - 1])\n", " image[rect.y + y, rect.x + x] = i\n", "\n", "def show_rectangles(rectangles):\n", " w, h = measure(rectangles)\n", " image = np.zeros((h, w), dtype=int)\n", " for i, rect in enumerate(rectangles, start=1):\n", " for x, y in product(range(rect.w), range(rect.h)):\n", " image[rect.y + y, rect.x + x] = i\n", " plt.imshow(image, aspect='equal')" ] }, { "cell_type": "code", "execution_count": null, "id": "fd8c423e", "metadata": {}, "outputs": [], "source": [ "r1 = Rectangle(0, 0, 10, 10)\n", "r2 = Rectangle(0, 10, 10, 10)\n", "r3 = Rectangle(10, 0, 10, 20)\n", "show_rectangles([r1, r2, r3])" ] }, { "cell_type": "code", "execution_count": null, "id": "1c7bfa44", "metadata": {}, "outputs": [], "source": [ "r1 = Rectangle(0, 0, 10, 10)\n", "r2 = Rectangle(0, 0, 5, 5)\n", "try:\n", " check_overlap([r1, r2])\n", "except ValueError as err:\n", " print(err)" ] }, { "cell_type": "code", "execution_count": null, "id": "ec3d4881", "metadata": {}, "outputs": [], "source": [ "def repack(to_pack):\n", " to_pack.sort(key=lambda r: r.w)\n", " total_height = sum(r.h for r in to_pack)\n", " first_half = []\n", " second_half = []\n", " position = 0\n", " for rect in to_pack:\n", " if position < total_height // 2:\n", " first_half.append(rect)\n", " else:\n", " second_half.append(rect)\n", " position += rect.h\n", " total_width = to_pack[-1].w + to_pack[-2].w\n", " for shift in range(0, 1000):\n", " y = 0\n", " for left in first_half:\n", " left.y = y\n", " left.x = 0\n", " y += left.h\n", " for right in second_half:\n", " right.y = y - right.h\n", " right.x = shift - right.w\n", " y -= right.h\n", " try:\n", " check_overlap(to_pack)\n", " return\n", " except ValueError:\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "id": "90689e9a", "metadata": {}, "outputs": [], "source": [ "to_pack = [\n", " Rectangle(0, 0, 8, 10),\n", " Rectangle(0, 0, 5, 6),\n", " Rectangle(0, 0, 5, 4),\n", " Rectangle(0, 0, 2, 5),\n", "]\n", "repack(to_pack)\n", "show_rectangles(to_pack)\n", "check_overlap(to_pack)\n", "w, h = measure(to_pack)\n", "print(\"score (lower is better)\", w * h)" ] }, { "cell_type": "code", "execution_count": null, "id": "b3778f5b", "metadata": {}, "outputs": [], "source": [ "to_pack = [\n", " Rectangle(0, 0, 8, 10),\n", " Rectangle(0, 0, 5, 6),\n", " Rectangle(0, 0, 5, 4),\n", " Rectangle(0, 0, 2, 5),\n", " Rectangle(0, 0, 8, 16),\n", " Rectangle(0, 0, 5, 5),\n", " Rectangle(0, 0, 5, 2),\n", " Rectangle(0, 0, 2, 3),\n", " Rectangle(0, 0, 12, 10),\n", " Rectangle(0, 0, 4, 6),\n", " Rectangle(0, 0, 4, 4),\n", " Rectangle(0, 0, 1, 5),\n", "]\n", "repack(to_pack)\n", "show_rectangles(to_pack)\n", "check_overlap(to_pack)\n", "w, h = measure(to_pack)\n", "print(\"score (lower is better)\", w * h)" ] } ], "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.9.4" } }, "nbformat": 4, "nbformat_minor": 5 }