diff --git a/docs/img/fill_square.png b/docs/img/fill_square.png
new file mode 100644
index 0000000..6818450
Binary files /dev/null and b/docs/img/fill_square.png differ
diff --git a/docs/img/square.png b/docs/img/square.png
new file mode 100644
index 0000000..380dad9
Binary files /dev/null and b/docs/img/square.png differ
diff --git a/docs/img/square_comparison.png b/docs/img/square_comparison.png
new file mode 100644
index 0000000..9833a39
Binary files /dev/null and b/docs/img/square_comparison.png differ
diff --git a/docs/img/stroke_square.png b/docs/img/stroke_square.png
new file mode 100644
index 0000000..3f72c36
Binary files /dev/null and b/docs/img/stroke_square.png differ
diff --git a/docs/shapes_text.md b/docs/shapes_text.md
index 4a275c7..3900675 100644
--- a/docs/shapes_text.md
+++ b/docs/shapes_text.md
@@ -107,6 +107,108 @@ Results in:
![stroke_rect() example](img/stroke_rect.png)
+### Squares
+
+To create a square there are 3 options:
+
+| Function | Description |
+|------------------------------------------|----------------------------------------------------|
+| [square(x, y, s)](#square) | Draw a square filled with color, and with a stroke |
+| [fill_square(x, y, s)](#fill_square) | Draw an square filled with a color |
+| [stroke_square(x, y, s)](#stroke_square) | Draw the outline of a square (its stroke) |
+
+
+
+ Comparison of 3 functions, note the red color was added for visibility, by default fill is black
+
+
+#### square()
+```python
+square(x, y, s)
+```
+
+**Parameters**
+
+- x: (int or float) The value of the x position of the square
+- y: (int or float) The value of the y position of the square
+- s: (int or float) The width and height of the square
+
+**Example(s):**
+
+*Creating a filled and stroked square at (100, 100) with a width and height of 75*
+
+```python hl_lines="7"
+%%ignite
+
+def setup():
+ size(200, 200)
+
+def draw():
+ square(100, 100, 75)
+```
+
+Results in:
+
+![square() example](img/square.png)
+
+#### fill_square()
+```python
+fill_square(x, y, s)
+```
+
+**Parameters**
+
+- x: (int or float) The value of the x position of the square
+- y: (int or float) The value of the y position of the square
+- s: (int or float) The width and height of the square
+
+**Example(s):**
+
+*Creating a filled square at (100, 100) with a width and height of 75*
+
+```python hl_lines="7"
+%%ignite
+
+def setup():
+ size(200, 200)
+
+def draw():
+ fill_square(100, 100, 75)
+```
+
+Results in:
+
+![fill_square() example](img/fill_square.png)
+
+#### stroke_square()
+```python
+stroke_square(x, y, s)
+```
+
+**Parameters**
+
+- x: (int or float) The value of the x position of the square
+- y: (int or float) The value of the y position of the square
+- s: (int or float) The width and height of the square
+
+**Example(s):**
+
+*Creating a stroked square at (100, 100) with a width and height of 75*
+
+```python hl_lines="7"
+%%ignite
+
+def setup():
+ size(200, 200)
+
+def draw():
+ stroke_square(100, 100, 75)
+```
+
+Results in:
+
+![stroke_square() example](img/stroke_square.png)
+
### Circles
To create a circle there are 3 options:
diff --git a/exercises/snek_game.ipynb b/exercises/snek_game.ipynb
new file mode 100644
index 0000000..8fefb35
--- /dev/null
+++ b/exercises/snek_game.ipynb
@@ -0,0 +1,421 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import spark\n",
+ "%reload_ext spark"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Snek Game\n",
+ "\n",
+ "This is a recreation of snake; basically try to collect the red squares with the white snek (what you control). \n",
+ "\n",
+ "If you collide the head of the snek with any other segments you lose.\n",
+ "\n",
+ "## Controls\n",
+ "\n",
+ "w - Move snek up\n",
+ "\n",
+ "s - Move snek down\n",
+ "\n",
+ "a - Move snek left\n",
+ "\n",
+ "d - Move snek right\n",
+ "\n",
+ "## Notes\n",
+ "\n",
+ "- Make sure you run the first cell **before** the game so the spark library is imported\n",
+ "- Your mouse must be **in** the canvas for the keyboard events to register"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{R}\\PY{err}{u}\\PY{err}{n}\\PY{err}{n}\\PY{err}{i}\\PY{err}{n}\\PY{err}{g}\\PY{err}{.}\\PY{err}{.}\\PY{err}{.}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Running..."
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "b7fbd6e0587e4747872281e83f413676",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Button(description='Stop', style=ButtonStyle())"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "e514713d2a3d45f897d393b1c752733f",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "# Player state\n",
+ "score = 0\n",
+ "speed_y = 0\n",
+ "speed_x = 10\n",
+ "positions = [[150, 100]]\n",
+ "\n",
+ "# Game state\n",
+ "highscore = 0\n",
+ "game_over = False\n",
+ "WIDTH = 300\n",
+ "HEIGHT = 300\n",
+ "\n",
+ "def get_treat_pos() -> tuple: # Needs to be defined here so treat_pos can be initialized\n",
+ " \"\"\"Generates the new treat position\n",
+ " \n",
+ " Returns\n",
+ " -------\n",
+ " list:\n",
+ " The new coordinates in (x, y) order\n",
+ " \"\"\"\n",
+ " global WIDTH, HEIGHT\n",
+ " # Generate x pos\n",
+ " value_x = randint(WIDTH - 30) + 10\n",
+ " while not (value_x % 10 == 0):\n",
+ " value_x = randint(WIDTH - 30) + 10\n",
+ " \n",
+ " # Generate y pos\n",
+ " value_y = randint(HEIGHT - 30) + 10\n",
+ " while not (value_y % 10 == 0):\n",
+ " value_y = randint(HEIGHT - 30) + 10\n",
+ " \n",
+ " return [value_x, value_y]\n",
+ "\n",
+ "# Initialize treat position\n",
+ "treat_pos = get_treat_pos()\n",
+ "\n",
+ "def setup():\n",
+ " size(WIDTH, HEIGHT)\n",
+ " \n",
+ "def draw():\n",
+ " if not game_over:\n",
+ " gameloop()\n",
+ " else:\n",
+ " restart()\n",
+ "\n",
+ "def gameloop():\n",
+ " global highscore, score, game_over, positions, speed_x, speed_y, treat_pos\n",
+ " background(0)\n",
+ "\n",
+ " # Check and draw player treat\n",
+ " fill_style(\"Red\")\n",
+ " square(treat_pos[0], treat_pos[1], 10)\n",
+ " \n",
+ " # Set drawing colors\n",
+ " fill_style(\"White\")\n",
+ " seen = [] # Holds seen chunk positions\n",
+ " \n",
+ " # treat collision\n",
+ " if positions[0] == treat_pos:\n",
+ " score += 1\n",
+ "\n",
+ " # Create new treat\n",
+ " treat_pos = get_treat_pos()\n",
+ "\n",
+ " # Append new segment to snake\n",
+ " positions.append([positions[-1][0], positions[-1][1]])\n",
+ " \n",
+ " # Set new highscore if reached\n",
+ " if highscore < score:\n",
+ " highscore = score\n",
+ "\n",
+ " # Print helpful text at the top \n",
+ " text_size(20)\n",
+ " text(f\"Score: {score}\", 50, 10) \n",
+ " text(f\"Highscore: {highscore}\", 150, 10)\n",
+ "\n",
+ " # Move all snek chunks besides head, starting from the back\n",
+ " for index in range(len(positions)-1, 0, -1): \n",
+ " positions[index][0] = positions[index-1][0]\n",
+ " positions[index][1] = positions[index-1][1]\n",
+ "\n",
+ " # Check for all collisions besides treat collision\n",
+ " for index, position in enumerate(positions):\n",
+ " # Check collision with snek head and other segments\n",
+ " if position in seen:\n",
+ " game_over = True\n",
+ " break\n",
+ " else:\n",
+ " seen.append(position)\n",
+ " \n",
+ " if index == 0: # update First square\n",
+ " # Check keypress in key_pressed\n",
+ " position[0] += speed_x\n",
+ " position[1] += speed_y\n",
+ "\n",
+ " # Segment colisions with outer bounds\n",
+ " if position[0] > WIDTH - 10: # Hit right boundary\n",
+ " position[0] = 0\n",
+ " if position[0] < 0: # Hit left boundary\n",
+ " position[0] = 290\n",
+ " \n",
+ " # Check y colisions\n",
+ " if position[1] < 20: # Hit top boundary\n",
+ " position[1] = 290\n",
+ "\n",
+ " if position[1] > HEIGHT - 10: # Hit bottom boundary\n",
+ " position[1] = 20\n",
+ "\n",
+ " # Update current square to new position\n",
+ " square(position[0], position[1], 10) \n",
+ " \n",
+ "def key_pressed():\n",
+ " \"\"\"Controls all snek movement\"\"\"\n",
+ " global speed_x, speed_y\n",
+ " if key == \"d\": # Right\n",
+ " speed_x = 10\n",
+ " speed_y = 0\n",
+ " if key == \"a\": # Left\n",
+ " speed_x = -10\n",
+ " speed_y = 0\n",
+ " if key == \"s\": # Down\n",
+ " speed_y = 10\n",
+ " speed_x = 0\n",
+ " if key == \"w\": # Up\n",
+ " speed_y = -10\n",
+ " speed_x = 0\n",
+ " \n",
+ "def restart():\n",
+ " \"\"\"Resets game state after colliding with yourself\"\"\"\n",
+ " global score, game_over, positions\n",
+ " score = 0\n",
+ " game_over = False\n",
+ " positions = [[150,100]]\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/setup.py b/setup.py
index dce9035..62b619b 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@
setuptools.setup(
name="schulich-ignite",
- version="0.1.0",
+ version="0.1.1",
author="Schulich Ignite",
author_email="info@shulichignite.com",
description="Spark library for Shulich Ignite sessions",
diff --git a/spark/core.py b/spark/core.py
index ee07ad1..a4f7b08 100644
--- a/spark/core.py
+++ b/spark/core.py
@@ -309,8 +309,10 @@ def key_repeated(self): pass
# From .util.helper_functions.keyboard_functions
@extern
- def keys_held(self, *args):
- pass
+ def keys_held(self, *args): pass
+
+ @extern
+ def key_held(self, *args): pass
# From .util.helper_functions.canvas_functions
@@ -424,6 +426,10 @@ def line_width(self, *args): pass
@extern
def stroke_width(self, *args): pass
+ # From util.helper_functions.image_functions
+ @extern
+ def image(self, *args): pass
+
### Helper Functions ###
# From util.helper_functions.misc_functions
@@ -431,6 +437,9 @@ def stroke_width(self, *args): pass
@extern
def parse_color(self, *args, func_name="parse_color"): pass
+ @extern
+ def color(self, *args): pass
+
@extern
def parse_color_string(self, func_name, s): pass
@@ -442,3 +451,12 @@ def random(self, *args): pass
@extern
def randint(self, *args): pass
+
+ @extern
+ def bounding_box(self, *args): pass
+
+ @extern
+ def collided(self, *args): pass
+
+ @extern
+ def axis_overlapped(self, *args): pass
diff --git a/spark/util/core_methods.py b/spark/util/core_methods.py
index 2679932..ddc251b 100644
--- a/spark/util/core_methods.py
+++ b/spark/util/core_methods.py
@@ -8,6 +8,7 @@
from .helper_functions.square_functions import *
from .helper_functions.text_functions import *
from .helper_functions.triangle_functions import *
+from .helper_functions.image_functions import *
from .helper_functions.keyboard_functions import *
diff --git a/spark/util/helper_functions/image_functions.py b/spark/util/helper_functions/image_functions.py
new file mode 100644
index 0000000..cb46dc9
--- /dev/null
+++ b/spark/util/helper_functions/image_functions.py
@@ -0,0 +1,39 @@
+from __future__ import annotations
+from typing import TYPE_CHECKING, Dict, Tuple
+if TYPE_CHECKING:
+ from ...core import Core
+
+from ..decorators import *
+from numbers import Real
+from ipywidgets import Image
+from ipycanvas import Canvas
+
+
+_loaded_images: Dict[Tuple[str, int, int], Canvas] = {}
+
+
+@validate_args([str, Real, Real, Real, Real])
+@ignite_global
+def helper_image(self: Core, *args):
+ filename: str = args[0]
+ x: int = int(args[1])
+ y: int = int(args[2])
+ w: int = int(args[3])
+ h: int = int(args[4])
+
+ key = (filename, abs(w), abs(h))
+
+ if key not in _loaded_images:
+ _loaded_images[key] = Canvas(width=abs(w), height=abs(h))
+ _loaded_images[key].draw_image(Image.from_file(filename, width=abs(w), height=abs(h)), 0, 0, abs(w), abs(h))
+ self.canvas.translate(x, y)
+ if w < 0:
+ self.canvas.scale(-1, 1)
+ if h < 0:
+ self.canvas.scale(1, -1)
+ self.canvas.draw_image(_loaded_images[key], 0, 0)
+ if h < 0:
+ self.canvas.scale(1, -1)
+ if w < 0:
+ self.canvas.scale(-1, 1)
+ self.canvas.translate(-x, -y)
diff --git a/spark/util/helper_functions/keyboard_functions.py b/spark/util/helper_functions/keyboard_functions.py
index a9f7979..b81a616 100644
--- a/spark/util/helper_functions/keyboard_functions.py
+++ b/spark/util/helper_functions/keyboard_functions.py
@@ -66,3 +66,11 @@ def helper_keys_held(self: Core, *keys, pattern=None):
pattern = [True]*len(keys)
match = [self._keys_held.get(key, False) == want for key, want in zip(keys, pattern)]
return reduce(and_, match)
+
+
+@validate_args([str], [str, bool])
+@ignite_global
+def helper_key_held(self: Core, *args):
+ if len(args) == 1:
+ args.append(True)
+ return self.keys_held(args[0], pattern=[args[1]])
\ No newline at end of file
diff --git a/spark/util/helper_functions/misc_functions.py b/spark/util/helper_functions/misc_functions.py
index 34d36ff..7471af6 100644
--- a/spark/util/helper_functions/misc_functions.py
+++ b/spark/util/helper_functions/misc_functions.py
@@ -50,6 +50,10 @@ def clip(x, lb, ub):
else:
raise ArgumentNumError(func_name, [1, 3, 4], argc)
+@validate_args([str], [Real], [Real, Real, Real], [Real, Real, Real, Real])
+@ignite_global
+def helper_color(self, *args):
+ return self.parse_color(*args)
@validate_args([Real, Real, Real, Real],
[Real, Real, Real, Real, Real],
@@ -83,3 +87,40 @@ def helper_random(self, *args):
@ignite_global
def helper_randint(self, *args):
return random.randint(0, args[0])
+
+
+@validate_args([Real, Real, Real, Real])
+@ignite_global
+def helper_bounding_box(self, *args):
+ x, y, w, h = args
+ left = min(x, x + w)
+ abs_width = abs(w)
+ top = min(y, y + h)
+ abs_height = abs(h)
+
+ return (left, top, abs_width, abs_height)
+
+@validate_args([list, list], [list, list, bool], [tuple, tuple], [tuple, tuple, bool])
+@ignite_global
+def helper_collided(self, *args):
+ x1, y1, width1, height1 = args[0]
+ x2, y2, width2, height2 = args[1]
+
+ sizes = {'bounding_box1 width': width1, 'bounding_box1 height': height1, 'bounding_box2 width': width2, 'bounding_box2 height': height2}
+
+ for size_name, size_val in sizes.items():
+ if size_val < 0:
+ raise ArgumentError("collided expected {} to be greater or equal to 0, got {}".format(size_name, size_val))
+
+ overlap_on_equal = len(args) == 3 and args[2]
+ return self.axis_overlapped(x1, width1, x2, width2, overlap_on_equal) and self.axis_overlapped(y1, height1, y2, height2, overlap_on_equal)
+
+@validate_args([Real, Real, Real, Real], [Real, Real, Real, Real, bool])
+@ignite_global
+def helper_axis_overlapped(self, *args):
+ point1, length1, point2, length2 = args[:4]
+
+ if len(args) == 5 and args[4]:
+ return point1 + length1 >= point2 and point2 + length2 >= point1
+ else:
+ return point1 + length1 > point2 and point2 + length2 > point1
diff --git a/test/CollidedTest.ipynb b/test/CollidedTest.ipynb
new file mode 100644
index 0000000..b67a355
--- /dev/null
+++ b/test/CollidedTest.ipynb
@@ -0,0 +1,1276 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import spark\n",
+ "%reload_ext spark"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{S}\\PY{err}{t}\\PY{err}{o}\\PY{err}{p}\\PY{err}{p}\\PY{err}{e}\\PY{err}{d}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Stopped"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "85c831e38187414ab871d6be64ac4cea",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Button(description='Stop', style=ButtonStyle())"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "81552cdfd3974aeab4e6ae4a654fd5ff",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "# Change the background color if the red square collides with the blue square\n",
+ "\n",
+ "base_back_color = \"rgb(255, 255, 200)\"\n",
+ "back_color = base_back_color\n",
+ "\n",
+ "def setup():\n",
+ " size(500, 500)\n",
+ " \n",
+ "def draw():\n",
+ " global base_back_color, back_color\n",
+ " background(back_color)\n",
+ " \n",
+ " fill_style(\"red\")\n",
+ " square(mouse_x, mouse_y, 100)\n",
+ " b1 = bounding_box(mouse_x, mouse_y, 100, 100)\n",
+ " \n",
+ " fill_style(\"blue\")\n",
+ " square(200, 200, 100)\n",
+ " b2 = bounding_box(200, 200, 100, 100)\n",
+ " \n",
+ " if collided(b1, b2):\n",
+ " back_color = \"green\"\n",
+ " else:\n",
+ " back_color = base_back_color"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{S}\\PY{err}{t}\\PY{err}{o}\\PY{err}{p}\\PY{err}{p}\\PY{err}{e}\\PY{err}{d}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Stopped"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "aac8114247054db5897e96315cdc1cf2",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Button(description='Stop', style=ButtonStyle())"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "7fd9331242324f8c818fcce08644ea03",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "# Collide and stick - Red and blue rects should collide in middle and stop moving\n",
+ "\n",
+ "x1 = 0\n",
+ "y1 = 200\n",
+ "w1 = 50\n",
+ "h1 = 100\n",
+ "speed1 = 1.5\n",
+ "\n",
+ "x2 = 475\n",
+ "y2 = 225\n",
+ "w2 = 25\n",
+ "h2 = 50\n",
+ "speed2 = -1\n",
+ "\n",
+ "def setup():\n",
+ " size(500, 500)\n",
+ " \n",
+ "def draw():\n",
+ " global x1, y1, w1, h1, speed1\n",
+ " global x2, y2, w2, h2, speed2\n",
+ " background(\"pink\")\n",
+ " \n",
+ " if collided(bounding_box(x1 + speed1, y1, w1, h1), bounding_box(x2 + speed2, y2, w2, h2)):\n",
+ " speed1 = 0\n",
+ " speed2 = 0\n",
+ " \n",
+ " x1 += speed1\n",
+ " x2 += speed2\n",
+ " \n",
+ " fill_style(\"red\")\n",
+ " rect(x1, y1, w1, h1)\n",
+ " \n",
+ " fill_style(\"blue\")\n",
+ " rect(x2, y2, w2, h2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{S}\\PY{err}{t}\\PY{err}{o}\\PY{err}{p}\\PY{err}{p}\\PY{err}{e}\\PY{err}{d}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Stopped"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "1d120a4dd447458c970e85fc6ac6bec4",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Button(description='Stop', style=ButtonStyle())"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "e1c76a76971146dab7bae413295b1c28",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "# Collide and bounce - Red and blue rects should collide in middle and bounce in opposire directions\n",
+ "\n",
+ "x1 = 0\n",
+ "y1 = 200\n",
+ "w1 = 50\n",
+ "h1 = 100\n",
+ "speed1 = 3\n",
+ "\n",
+ "x2 = 475\n",
+ "y2 = 225\n",
+ "w2 = 25\n",
+ "h2 = 50\n",
+ "speed2 = -4\n",
+ "\n",
+ "def setup():\n",
+ " size(500, 500)\n",
+ " \n",
+ "def draw():\n",
+ " global x1, y1, w1, h1, speed1\n",
+ " global x2, y2, w2, h2, speed2\n",
+ " background(\"purple\")\n",
+ " \n",
+ " if collided(bounding_box(x1, y1, w1, h1), bounding_box(x2, y2, w2, h2)):\n",
+ " speed1 *= -1\n",
+ " speed2 *= -1\n",
+ " \n",
+ " x1 += speed1\n",
+ " x2 += speed2\n",
+ " \n",
+ " fill_style(\"red\")\n",
+ " rect(x1, y1, w1, h1)\n",
+ " \n",
+ " fill_style(\"blue\")\n",
+ " rect(x2, y2, w2, h2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{S}\\PY{err}{t}\\PY{err}{o}\\PY{err}{p}\\PY{err}{p}\\PY{err}{e}\\PY{err}{d}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Stopped"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "4bcee6c187df454b94b0536705a3baf5",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Button(description='Stop', style=ButtonStyle())"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "66c860ce7aaf42b48b2767463820c9f3",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "# Check that bounding_box always is aligned from the top-left corner with positive width/height\n",
+ "\n",
+ "base_back_color = \"rgb(255, 255, 200)\"\n",
+ "back_color = base_back_color\n",
+ "\n",
+ "def setup():\n",
+ " global b2\n",
+ " size(500, 500)\n",
+ " b2 = bounding_box(300, 400, -100, -50)\n",
+ " if b2[0] != 200:\n",
+ " raise Exception(\"Expected b2 left edge to be 200, got \" + str(b2[0]))\n",
+ " if b2[1] != 350:\n",
+ " raise Exception(\"Expected b2 top edge to be 350, got \" + str(b2[1]))\n",
+ " if b2[2] != 100:\n",
+ " raise Exception(\"Expected b2 absolute width to be 100, got \" + str(b2[2]))\n",
+ " if b2[3] != 50:\n",
+ " raise Exception(\"Expected b2 absolute width to be 50, got \" + str(b2[3]))\n",
+ " \n",
+ "def draw():\n",
+ " global base_back_color, back_color, b2\n",
+ " background(back_color)\n",
+ " \n",
+ " fill_style(\"red\")\n",
+ " square(mouse_x, mouse_y, 100)\n",
+ " b1 = bounding_box(mouse_x, mouse_y, 100, 100)\n",
+ " \n",
+ " fill_style(\"blue\")\n",
+ " rect(*b2)\n",
+ " \n",
+ " if collided(b1, b2):\n",
+ " back_color = \"green\"\n",
+ " else:\n",
+ " back_color = base_back_color"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{D}\\PY{err}{o}\\PY{err}{n}\\PY{err}{e}\\PY{err}{ }\\PY{err}{d}\\PY{err}{r}\\PY{err}{a}\\PY{err}{w}\\PY{err}{i}\\PY{err}{n}\\PY{err}{g}\\PY{err}{.}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Done drawing."
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "0d98ba4834ab4210ac9bd8d5f204bf78",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "collided throws expected exceptions \n",
+ "with_negative_width1 \n",
+ "with_negative_height2 \n",
+ " \n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{c}\\PY{err}{o}\\PY{err}{l}\\PY{err}{l}\\PY{err}{i}\\PY{err}{d}\\PY{err}{e}\\PY{err}{d}\\PY{err}{ }\\PY{err}{t}\\PY{err}{h}\\PY{err}{r}\\PY{err}{o}\\PY{err}{w}\\PY{err}{s}\\PY{err}{ }\\PY{err}{e}\\PY{err}{x}\\PY{err}{p}\\PY{err}{e}\\PY{err}{c}\\PY{err}{t}\\PY{err}{e}\\PY{err}{d}\\PY{err}{ }\\PY{err}{e}\\PY{err}{x}\\PY{err}{c}\\PY{err}{e}\\PY{err}{p}\\PY{err}{t}\\PY{err}{i}\\PY{err}{o}\\PY{err}{n}\\PY{err}{s}\n",
+ "\\PY{err}{w}\\PY{err}{i}\\PY{err}{t}\\PY{err}{h}\\PY{err}{\\PYZus{}}\\PY{err}{n}\\PY{err}{e}\\PY{err}{g}\\PY{err}{a}\\PY{err}{t}\\PY{err}{i}\\PY{err}{v}\\PY{err}{e}\\PY{err}{\\PYZus{}}\\PY{err}{w}\\PY{err}{i}\\PY{err}{d}\\PY{err}{t}\\PY{err}{h}\\PY{err}{1}\n",
+ "\\PY{err}{w}\\PY{err}{i}\\PY{err}{t}\\PY{err}{h}\\PY{err}{\\PYZus{}}\\PY{err}{n}\\PY{err}{e}\\PY{err}{g}\\PY{err}{a}\\PY{err}{t}\\PY{err}{i}\\PY{err}{v}\\PY{err}{e}\\PY{err}{\\PYZus{}}\\PY{err}{h}\\PY{err}{e}\\PY{err}{i}\\PY{err}{g}\\PY{err}{h}\\PY{err}{t}\\PY{err}{2}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "collided throws expected exceptions\n",
+ "with_negative_width1\n",
+ "with_negative_height2"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "# Unhappy path\n",
+ "# Negative inputs are given directly to collided()\n",
+ "\n",
+ "def setup():\n",
+ " print(\"collided throws expected exceptions\")\n",
+ " size(100, 100)\n",
+ " expect_arg_error(with_negative_width1, \"collided expected bounding_box1 width to be greater or equal to 0, got -100\")\n",
+ " expect_arg_error(with_negative_height2, \"collided expected bounding_box2 height to be greater or equal to 0, got -50\")\n",
+ " \n",
+ "def expect_arg_error(func, expected_error):\n",
+ " try:\n",
+ " func()\n",
+ " except Exception as e:\n",
+ " if str(e) != expected_error:\n",
+ " print(\"FAIL:\\n\\tExpected \" + str(func.__name__) + \" to raise error:\\n\\t\\t\" + expected_error)\n",
+ " print(\"\\tbut received:\\n\\t\\t\" + str(e).replace(\"\\n\",\"\\n\\t\\t\"))\n",
+ " else:\n",
+ " print(\"FAIL:\\n\\tExpected \" + str(func.__name__) + \" to raise error:\\n\\t\\t\" + expected_error)\n",
+ " print(\"\\tbut it didn't raise any errors\")\n",
+ " \n",
+ "def with_negative_width1():\n",
+ " print(\"with_negative_width1\")\n",
+ " collided([0, 0, -100, 0], [0, 0, 0, 50])\n",
+ " \n",
+ "def with_negative_height2():\n",
+ " print(\"with_negative_height2\")\n",
+ " collided([0, 0, 100, 0], [0, 0, 0, -50])"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/test/ColorTest.ipynb b/test/ColorTest.ipynb
new file mode 100644
index 0000000..afa5ddb
--- /dev/null
+++ b/test/ColorTest.ipynb
@@ -0,0 +1,675 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import spark\n",
+ "%reload_ext spark"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{D}\\PY{err}{o}\\PY{err}{n}\\PY{err}{e}\\PY{err}{ }\\PY{err}{d}\\PY{err}{r}\\PY{err}{a}\\PY{err}{w}\\PY{err}{i}\\PY{err}{n}\\PY{err}{g}\\PY{err}{.}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Done drawing."
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "83740a812c2545f783b2c4d20e5a3ee7",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "#Expose parse_color as a global function called \"color\" #54\n",
+ "\n",
+ "def setup():\n",
+ " color('red')\n",
+ " color('blue')\n",
+ " color(0, 0, 0)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Error in setup() function: parse_color expected argument to match "Valid HTML format or color names", got notAColor \n",
+ " \n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{E}\\PY{err}{r}\\PY{err}{r}\\PY{err}{o}\\PY{err}{r}\\PY{err}{ }\\PY{err}{i}\\PY{err}{n}\\PY{err}{ }\\PY{err}{s}\\PY{err}{e}\\PY{err}{t}\\PY{err}{u}\\PY{err}{p}\\PY{err}{(}\\PY{err}{)}\\PY{err}{ }\\PY{err}{f}\\PY{err}{u}\\PY{err}{n}\\PY{err}{c}\\PY{err}{t}\\PY{err}{i}\\PY{err}{o}\\PY{err}{n}\\PY{err}{:}\\PY{err}{ }\\PY{err}{p}\\PY{err}{a}\\PY{err}{r}\\PY{err}{s}\\PY{err}{e}\\PY{err}{\\PYZus{}}\\PY{err}{c}\\PY{err}{o}\\PY{err}{l}\\PY{err}{o}\\PY{err}{r}\\PY{err}{ }\\PY{err}{e}\\PY{err}{x}\\PY{err}{p}\\PY{err}{e}\\PY{err}{c}\\PY{err}{t}\\PY{err}{e}\\PY{err}{d}\\PY{err}{ }\\PY{err}{a}\\PY{err}{r}\\PY{err}{g}\\PY{err}{u}\\PY{err}{m}\\PY{err}{e}\\PY{err}{n}\\PY{err}{t}\\PY{err}{ }\\PY{err}{t}\\PY{err}{o}\\PY{err}{ }\\PY{err}{m}\\PY{err}{a}\\PY{err}{t}\\PY{err}{c}\\PY{err}{h}\\PY{err}{ }\\PY{err}{\\PYZdq{}}\\PY{err}{V}\\PY{err}{a}\\PY{err}{l}\\PY{err}{i}\\PY{err}{d}\\PY{err}{ }\\PY{err}{H}\\PY{err}{T}\\PY{err}{M}\\PY{err}{L}\\PY{err}{ }\\PY{err}{f}\\PY{err}{o}\\PY{err}{r}\\PY{err}{m}\\PY{err}{a}\\PY{err}{t}\\PY{err}{ }\\PY{err}{o}\\PY{err}{r}\\PY{err}{ }\\PY{err}{c}\\PY{err}{o}\\PY{err}{l}\\PY{err}{o}\\PY{err}{r}\\PY{err}{ }\\PY{err}{n}\\PY{err}{a}\\PY{err}{m}\\PY{err}{e}\\PY{err}{s}\\PY{err}{\\PYZdq{}}\\PY{err}{,}\\PY{err}{ }\\PY{err}{g}\\PY{err}{o}\\PY{err}{t}\\PY{err}{ }\\PY{err}{n}\\PY{err}{o}\\PY{err}{t}\\PY{err}{A}\\PY{err}{C}\\PY{err}{o}\\PY{err}{l}\\PY{err}{o}\\PY{err}{r}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Error in setup() function: parse_color expected argument to match \"Valid HTML format or color names\", got notAColor"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "d05be34004874205ab7297886359bb7c",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "def setup():\n",
+ " color('notAColor')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{D}\\PY{err}{o}\\PY{err}{n}\\PY{err}{e}\\PY{err}{ }\\PY{err}{d}\\PY{err}{r}\\PY{err}{a}\\PY{err}{w}\\PY{err}{i}\\PY{err}{n}\\PY{err}{g}\\PY{err}{.}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Done drawing."
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "0d56ce0edea24722b8162fd6cc914d36",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "def setup():\n",
+ " size(300, 300)\n",
+ " r = color(\"red\")\n",
+ " g = color(\"green\")\n",
+ " b = color(\"blue\")\n",
+ " col_temps = [r, g, b]\n",
+ " diams = [25*(11-i) for i in range(1, 11)]\n",
+ " cols = [col_temps[i%3] for i in range(1,11)]\n",
+ " for d, c in zip(diams, cols):\n",
+ " fill_style(c)\n",
+ " fill_circle(width/2, height/2, d)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/test/EllipseAndArcTest.ipynb b/test/EllipseAndArcTest.ipynb
index f64e00c..11dbd39 100644
--- a/test/EllipseAndArcTest.ipynb
+++ b/test/EllipseAndArcTest.ipynb
@@ -271,7 +271,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.5"
+ "version": "3.8.6"
}
},
"nbformat": 4,
diff --git a/test/ImageTest.ipynb b/test/ImageTest.ipynb
new file mode 100644
index 0000000..064072c
--- /dev/null
+++ b/test/ImageTest.ipynb
@@ -0,0 +1,494 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import spark\n",
+ "%reload_ext spark"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{S}\\PY{err}{t}\\PY{err}{o}\\PY{err}{p}\\PY{err}{p}\\PY{err}{e}\\PY{err}{d}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Stopped"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "0ddbc8cde8d045f88a6c017718515c44",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Button(description='Stop', style=ButtonStyle())"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "e046aeb247a14f4e8b2d1d56f40eddfb",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "# Renders an image of BugBuster.png\n",
+ "\n",
+ "x = 0\n",
+ "\n",
+ "def setup():\n",
+ " size(500, 500)\n",
+ " \n",
+ "def draw():\n",
+ " global x\n",
+ " background(\"aqua\")\n",
+ " image(\"assets/BugBuster.png\", x, 10, 200, 200)\n",
+ " x += 2\n",
+ " x %= width"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Error in draw() function: [Errno 2] No such file or directory: 'assets/not_an_image' \n",
+ " \n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{E}\\PY{err}{r}\\PY{err}{r}\\PY{err}{o}\\PY{err}{r}\\PY{err}{ }\\PY{err}{i}\\PY{err}{n}\\PY{err}{ }\\PY{err}{d}\\PY{err}{r}\\PY{err}{a}\\PY{err}{w}\\PY{err}{(}\\PY{err}{)}\\PY{err}{ }\\PY{err}{f}\\PY{err}{u}\\PY{err}{n}\\PY{err}{c}\\PY{err}{t}\\PY{err}{i}\\PY{err}{o}\\PY{err}{n}\\PY{err}{:}\\PY{err}{ }\\PY{err}{[}\\PY{err}{E}\\PY{err}{r}\\PY{err}{r}\\PY{err}{n}\\PY{err}{o}\\PY{err}{ }\\PY{err}{2}\\PY{err}{]}\\PY{err}{ }\\PY{err}{N}\\PY{err}{o}\\PY{err}{ }\\PY{err}{s}\\PY{err}{u}\\PY{err}{c}\\PY{err}{h}\\PY{err}{ }\\PY{err}{f}\\PY{err}{i}\\PY{err}{l}\\PY{err}{e}\\PY{err}{ }\\PY{err}{o}\\PY{err}{r}\\PY{err}{ }\\PY{err}{d}\\PY{err}{i}\\PY{err}{r}\\PY{err}{e}\\PY{err}{c}\\PY{err}{t}\\PY{err}{o}\\PY{err}{r}\\PY{err}{y}\\PY{err}{:}\\PY{err}{ }\\PY{err}{\\PYZsq{}}\\PY{err}{a}\\PY{err}{s}\\PY{err}{s}\\PY{err}{e}\\PY{err}{t}\\PY{err}{s}\\PY{err}{/}\\PY{err}{n}\\PY{err}{o}\\PY{err}{t}\\PY{err}{\\PYZus{}}\\PY{err}{a}\\PY{err}{n}\\PY{err}{\\PYZus{}}\\PY{err}{i}\\PY{err}{m}\\PY{err}{a}\\PY{err}{g}\\PY{err}{e}\\PY{err}{\\PYZsq{}}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Error in draw() function: [Errno 2] No such file or directory: 'assets/not_an_image'"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "7450d824fedd4658b65030a7194d8664",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Button(description='Stop', style=ButtonStyle())"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "9e225f45d15e499697fd6b55ff55ab3a",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "# Throws appropriate error when image is not found\n",
+ "\n",
+ "def setup():\n",
+ " size(500, 500)\n",
+ " \n",
+ "def draw():\n",
+ " background(\"aqua\")\n",
+ " image(\"assets/not_an_image\", 10, 10, 200, 200)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/test/RectAndCircleTest.ipynb b/test/RectAndCircleTest.ipynb
index 18d92b3..c4829ef 100644
--- a/test/RectAndCircleTest.ipynb
+++ b/test/RectAndCircleTest.ipynb
@@ -255,7 +255,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.5"
+ "version": "3.8.6"
}
},
"nbformat": 4,
diff --git a/test/SquareTest.ipynb b/test/SquareTest.ipynb
new file mode 100644
index 0000000..c3b4c1e
--- /dev/null
+++ b/test/SquareTest.ipynb
@@ -0,0 +1,255 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import spark\n",
+ "%reload_ext spark"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\\PY{err}{D}\\PY{err}{o}\\PY{err}{n}\\PY{err}{e}\\PY{err}{ }\\PY{err}{d}\\PY{err}{r}\\PY{err}{a}\\PY{err}{w}\\PY{err}{i}\\PY{err}{n}\\PY{err}{g}\\PY{err}{.}\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": [
+ "Done drawing."
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "8fd8f5e012094139bb3f5162c42064a5",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Canvas(height=100, width=100)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n"
+ ],
+ "text/latex": [
+ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n",
+ "\n",
+ "\\end{Verbatim}\n"
+ ],
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%%ignite\n",
+ "\n",
+ "def setup():\n",
+ " size(200, 500)\n",
+ " background(\"default\")\n",
+ " fill_style(\"green\")\n",
+ " stroke_style(\"magenta\")\n",
+ " square(50, 50, 100)\n",
+ " fill_square(50, 200, 100)\n",
+ " stroke_square(50, 350, 100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/test/assets/BugBuster.png b/test/assets/BugBuster.png
new file mode 100644
index 0000000..6480b57
Binary files /dev/null and b/test/assets/BugBuster.png differ