From 806576be5f9d34c68415abe9103c33f23401de07 Mon Sep 17 00:00:00 2001 From: andreamah Date: Fri, 24 Jan 2020 16:34:34 -0800 Subject: [PATCH 01/11] shim design example --- gulpfile.js | 271 ++++++++++++++------------- src/microbit/__init__.py | 1 + src/microbit/code_processing_shim.py | 13 ++ src/microbit/display.py | 6 + src/microbit/microbit_model.py | 15 ++ 5 files changed, 171 insertions(+), 135 deletions(-) create mode 100644 src/microbit/__init__.py create mode 100644 src/microbit/code_processing_shim.py create mode 100644 src/microbit/display.py create mode 100644 src/microbit/microbit_model.py diff --git a/gulpfile.js b/gulpfile.js index 3c106798d..c642abfed 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,135 +1,136 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -const gulp = require("gulp"); - -const ts = require("gulp-typescript"); -const sourcemaps = require("gulp-sourcemaps"); -const typescript = require("typescript"); -const del = require("del"); -const es = require("event-stream"); -const vsce = require("vsce"); -const nls = require("vscode-nls-dev"); - -const tsProject = ts.createProject("./tsconfig.json", { typescript }); - -const inlineMap = true; -const inlineSource = false; -const outDest = "out"; - -// A list of all locales supported by VSCode can be found here: https://code.visualstudio.com/docs/getstarted/locales -const languages = [{ folderName: "en", id: "en" }]; - -gulp.task("clean", () => { - return del( - [ - "out/*", - "package.nls.*.json", - "../../dist/*0.0.0-UNTRACKEDVERSION.vsix" - ], - { force: true } - ); -}); - -const pythonToMove = [ - "./src/adafruit_circuitplayground/*.*", - "./src/*.py", - "./src/requirements.txt", -]; - -gulp.task("python-compile", () => { - // the base option sets the relative root for the set of files, - // preserving the folder structure - return gulp.src(pythonToMove, { base: "./src/" }).pipe(gulp.dest("out")); -}); - -gulp.task("internal-compile", () => { - return compile(false); -}); - -gulp.task("internal-nls-compile", () => { - return compile(true); -}); - -gulp.task("add-locales", () => { - return gulp - .src(["package.nls.json"]) - .pipe(nls.createAdditionalLanguageFiles(languages, "locales")) - .pipe(gulp.dest(".")); -}); - -gulp.task("vsce:publish", () => { - return vsce.publish(); -}); - -gulp.task("vsce:package", () => { - return vsce.createVSIX({ - packagePath: "../../dist/deviceSimulatorExpress-0.0.0-UNTRACKEDVERSION.vsix" - }); -}); - -gulp.task( - "compile", - gulp.series("clean", "internal-compile", "python-compile", callback => { - callback(); - }) -); - -gulp.task( - "build", - gulp.series( - "clean", - "internal-nls-compile", - "python-compile", - "add-locales", - callback => { - callback(); - } - ) -); - -gulp.task( - "publish", - gulp.series("compile", "vsce:publish", callback => { - callback(); - }) -); - -gulp.task( - "package", - gulp.series("compile", "vsce:package", callback => { - callback(); - }) -); - -//---- internal - -function compile(buildNls) { - var r = tsProject - .src() - .pipe(sourcemaps.init()) - .pipe(tsProject()) - .js.pipe(buildNls ? nls.rewriteLocalizeCalls() : es.through()) - .pipe( - buildNls - ? nls.createAdditionalLanguageFiles(languages, "locales", "out") - : es.through() - ); - - if (inlineMap && inlineSource) { - r = r.pipe(sourcemaps.write()); - } else { - r = r.pipe( - sourcemaps.write("../out", { - // no inlined source - includeContent: inlineSource, - // Return relative source map root directories per file. - sourceRoot: "../src" - }) - ); - } - - return r.pipe(gulp.dest(outDest)); -} +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const gulp = require("gulp"); + +const ts = require("gulp-typescript"); +const sourcemaps = require("gulp-sourcemaps"); +const typescript = require("typescript"); +const del = require("del"); +const es = require("event-stream"); +const vsce = require("vsce"); +const nls = require("vscode-nls-dev"); + +const tsProject = ts.createProject("./tsconfig.json", { typescript }); + +const inlineMap = true; +const inlineSource = false; +const outDest = "out"; + +// A list of all locales supported by VSCode can be found here: https://code.visualstudio.com/docs/getstarted/locales +const languages = [{ folderName: "en", id: "en" }]; + +gulp.task("clean", () => { + return del( + [ + "out/*", + "package.nls.*.json", + "../../dist/*0.0.0-UNTRACKEDVERSION.vsix" + ], + { force: true } + ); +}); + +const pythonToMove = [ + "./src/adafruit_circuitplayground/*.*", + "./src/microbit/*.*", + "./src/*.py", + "./src/requirements.txt", +]; + +gulp.task("python-compile", () => { + // the base option sets the relative root for the set of files, + // preserving the folder structure + return gulp.src(pythonToMove, { base: "./src/" }).pipe(gulp.dest("out")); +}); + +gulp.task("internal-compile", () => { + return compile(false); +}); + +gulp.task("internal-nls-compile", () => { + return compile(true); +}); + +gulp.task("add-locales", () => { + return gulp + .src(["package.nls.json"]) + .pipe(nls.createAdditionalLanguageFiles(languages, "locales")) + .pipe(gulp.dest(".")); +}); + +gulp.task("vsce:publish", () => { + return vsce.publish(); +}); + +gulp.task("vsce:package", () => { + return vsce.createVSIX({ + packagePath: "../../dist/deviceSimulatorExpress-0.0.0-UNTRACKEDVERSION.vsix" + }); +}); + +gulp.task( + "compile", + gulp.series("clean", "internal-compile", "python-compile", callback => { + callback(); + }) +); + +gulp.task( + "build", + gulp.series( + "clean", + "internal-nls-compile", + "python-compile", + "add-locales", + callback => { + callback(); + } + ) +); + +gulp.task( + "publish", + gulp.series("compile", "vsce:publish", callback => { + callback(); + }) +); + +gulp.task( + "package", + gulp.series("compile", "vsce:package", callback => { + callback(); + }) +); + +//---- internal + +function compile(buildNls) { + var r = tsProject + .src() + .pipe(sourcemaps.init()) + .pipe(tsProject()) + .js.pipe(buildNls ? nls.rewriteLocalizeCalls() : es.through()) + .pipe( + buildNls + ? nls.createAdditionalLanguageFiles(languages, "locales", "out") + : es.through() + ); + + if (inlineMap && inlineSource) { + r = r.pipe(sourcemaps.write()); + } else { + r = r.pipe( + sourcemaps.write("../out", { + // no inlined source + includeContent: inlineSource, + // Return relative source map root directories per file. + sourceRoot: "../src" + }) + ); + } + + return r.pipe(gulp.dest(outDest)); +} diff --git a/src/microbit/__init__.py b/src/microbit/__init__.py new file mode 100644 index 000000000..3f308d8fb --- /dev/null +++ b/src/microbit/__init__.py @@ -0,0 +1 @@ +from .code_processing_shim import * \ No newline at end of file diff --git a/src/microbit/code_processing_shim.py b/src/microbit/code_processing_shim.py new file mode 100644 index 000000000..a3996c21f --- /dev/null +++ b/src/microbit/code_processing_shim.py @@ -0,0 +1,13 @@ +from . import microbit_model + +# EXAMPLE +# can be called simply as "show_message("string")" +def show_message(message): + microbit_model.mb.show_message(message) + +# EXAMPLE +# can be called with display.scroll("string") +class display: + @staticmethod + def scroll(self, message): + microbit_model.mb.display.scroll(self,message) \ No newline at end of file diff --git a/src/microbit/display.py b/src/microbit/display.py new file mode 100644 index 000000000..699c4397b --- /dev/null +++ b/src/microbit/display.py @@ -0,0 +1,6 @@ +# class for microbit led display +class Display: + + # SAMPLE FUNCTION + def scroll(self, message): + print("scroll!! " + message) \ No newline at end of file diff --git a/src/microbit/microbit_model.py b/src/microbit/microbit_model.py new file mode 100644 index 000000000..1d6ebec95 --- /dev/null +++ b/src/microbit/microbit_model.py @@ -0,0 +1,15 @@ +from .display import Display + +class MicrobitModel: + def __init__(self): + # State in the Python process + self.display = Display() + self.__state = { } + self.__debug_mode = False + self.__abs_path_to_code_file = '' + + # SAMPLE FUNCTION + def show_message(self, message): + print("message!! " + message) + +mb = MicrobitModel() \ No newline at end of file From deceeb75debae7df4e92f0e6306ad28273b15bfc Mon Sep 17 00:00:00 2001 From: andreamah Date: Tue, 28 Jan 2020 10:27:16 -0800 Subject: [PATCH 02/11] some effort on image object design --- src/microbit/code_processing_shim.py | 22 ++++++++---- src/microbit/constants.py | 5 +++ src/microbit/display.py | 7 +++- src/microbit/image.py | 52 ++++++++++++++++++++++++++++ src/test_code/code.py | 38 ++++++++++---------- 5 files changed, 98 insertions(+), 26 deletions(-) create mode 100644 src/microbit/constants.py create mode 100644 src/microbit/image.py diff --git a/src/microbit/code_processing_shim.py b/src/microbit/code_processing_shim.py index a3996c21f..c4b5d6146 100644 --- a/src/microbit/code_processing_shim.py +++ b/src/microbit/code_processing_shim.py @@ -1,13 +1,23 @@ from . import microbit_model +from . import image +from . import constants as CONSTANTS # EXAMPLE # can be called simply as "show_message("string")" def show_message(message): microbit_model.mb.show_message(message) -# EXAMPLE -# can be called with display.scroll("string") -class display: - @staticmethod - def scroll(self, message): - microbit_model.mb.display.scroll(self,message) \ No newline at end of file +# def Image(pattern = CONSTANTS.BLANK): +# img = image.Image(pattern) +# assign_constants(img) + +def assign_constants(obj): + obj.BOAT = image.MicrobitImage(CONSTANTS.BOAT) + +display = microbit_model.mb.display +Image = image.Image + + +# define "constants" here +# Image.BOAT = image.Image(CONSTANTS.BOAT) + diff --git a/src/microbit/constants.py b/src/microbit/constants.py new file mode 100644 index 000000000..9ac1e2858 --- /dev/null +++ b/src/microbit/constants.py @@ -0,0 +1,5 @@ +BOAT = ("05050:","05050:","05050:","99999:","09990") + +BLANK= "00000:00000:00000:00000:00000" + +COPY_ERR_MESSAGE = "please copy() first" \ No newline at end of file diff --git a/src/microbit/display.py b/src/microbit/display.py index 699c4397b..6ce2043bd 100644 --- a/src/microbit/display.py +++ b/src/microbit/display.py @@ -1,6 +1,11 @@ # class for microbit led display class Display: + def __init__(self): + # State in the Python process + self.count = 4 + # SAMPLE FUNCTION def scroll(self, message): - print("scroll!! " + message) \ No newline at end of file + print("scroll!! " + str(self.count)) + self.count = self.count + 1 \ No newline at end of file diff --git a/src/microbit/image.py b/src/microbit/image.py new file mode 100644 index 000000000..f9b1d727c --- /dev/null +++ b/src/microbit/image.py @@ -0,0 +1,52 @@ +from . import microbit_model +from . import constants as CONSTANTS +from . import display + + +class Image: + _BOAT = None + def __init__(self, pattern = CONSTANTS.BLANK, width=5,height=5): + # State in the Python process + self.width = width + self.height = height + if type(pattern) is str: + self.LED = self.convert_to_array(pattern) + else: + self.LED = pattern + + + def convert_to_array(self, pattern): + arr = [] + sub_str = "" + for elem in pattern: + sub_str= sub_str + elem + if elem == ":": + arr.append(sub_str) + sub_str = "" + + + arr.append(sub_str) + return arr + + + def set_pixel(self,x,y,value): + + sub_arr = self.LED[y] + + new_list = list(sub_arr) + new_list[x] = value + + self.LED[y] = "".join(new_list) + + + def get_pixel(self,x,y): + return self.LED[y][x] + + def copy(self): + return Image(list(self.LED)) + + def getvalue(self): + self._BOAT = Image(CONSTANTS.BOAT) + return self._BOAT + + BOAT = property(getvalue) diff --git a/src/test_code/code.py b/src/test_code/code.py index 369561cc5..15f94fb04 100644 --- a/src/test_code/code.py +++ b/src/test_code/code.py @@ -1,19 +1,19 @@ -from adafruit_circuitplayground.express import cpx -import time - -cpx.pixels.brightness = 0.3 -cpx.pixels.fill((0, 0, 0)) # Turn off the NeoPixels if they're on! -cpx.pixels.show() - -while True: - if cpx.button_a: - cpx.pixels[2] = (0, 255, 0) - else: - cpx.pixels[2] = (0, 0, 0) - - if cpx.button_b: - cpx.pixels[7] = (0, 0, 255) - else: - cpx.pixels[7] = (0, 0, 0) - cpx.pixels.show() - +# from adafruit_circuitplayground.express import cpx +# import time + +# cpx.pixels.brightness = 0.3 +# cpx.pixels.fill((0, 0, 0)) # Turn off the NeoPixels if they're on! +# cpx.pixels.show() + +# while True: +# if cpx.button_a: +# cpx.pixels[2] = (0, 255, 0) +# else: +# cpx.pixels[2] = (0, 0, 0) + +# if cpx.button_b: +# cpx.pixels[7] = (0, 0, 255) +# else: +# cpx.pixels[7] = (0, 0, 0) +# cpx.pixels.show() + From 8ed9e5b9db4a19e11415ab36c2e506762f2e8a0b Mon Sep 17 00:00:00 2001 From: andreamah Date: Tue, 28 Jan 2020 14:02:42 -0800 Subject: [PATCH 03/11] initial look at image class --- src/microbit/code_processing_shim.py | 11 +---- src/microbit/constants.py | 18 ++++++-- src/microbit/image.py | 61 +++++++++++++++++----------- 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/microbit/code_processing_shim.py b/src/microbit/code_processing_shim.py index c4b5d6146..eb53e10ab 100644 --- a/src/microbit/code_processing_shim.py +++ b/src/microbit/code_processing_shim.py @@ -7,17 +7,10 @@ def show_message(message): microbit_model.mb.show_message(message) -# def Image(pattern = CONSTANTS.BLANK): -# img = image.Image(pattern) -# assign_constants(img) - -def assign_constants(obj): - obj.BOAT = image.MicrobitImage(CONSTANTS.BOAT) display = microbit_model.mb.display -Image = image.Image +microbit = microbit_model.mb +Image = image.Image -# define "constants" here -# Image.BOAT = image.Image(CONSTANTS.BOAT) diff --git a/src/microbit/constants.py b/src/microbit/constants.py index 9ac1e2858..71d5b297b 100644 --- a/src/microbit/constants.py +++ b/src/microbit/constants.py @@ -1,5 +1,17 @@ -BOAT = ("05050:","05050:","05050:","99999:","09990") -BLANK= "00000:00000:00000:00000:00000" +BOAT = ([0, 5, 0, 5, 0], + [0, 5, 0, 5, 0], + [0, 5, 0, 5, 0], + [9, 9, 9, 9, 9], + [0, 9, 9, 9, 0]) -COPY_ERR_MESSAGE = "please copy() first" \ No newline at end of file +BLANK= [[0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]] + + +COPY_ERR_MESSAGE = "please copy() first" + +LED_MAX = 5 \ No newline at end of file diff --git a/src/microbit/image.py b/src/microbit/image.py index f9b1d727c..58a670af7 100644 --- a/src/microbit/image.py +++ b/src/microbit/image.py @@ -2,13 +2,9 @@ from . import constants as CONSTANTS from . import display - class Image: - _BOAT = None - def __init__(self, pattern = CONSTANTS.BLANK, width=5,height=5): + def __init__(self, pattern = CONSTANTS.BLANK): # State in the Python process - self.width = width - self.height = height if type(pattern) is str: self.LED = self.convert_to_array(pattern) else: @@ -17,26 +13,21 @@ def __init__(self, pattern = CONSTANTS.BLANK, width=5,height=5): def convert_to_array(self, pattern): arr = [] - sub_str = "" - for elem in pattern: - sub_str= sub_str + elem + sub_arr = [] + for elem in pattern: + sub_arr.append(elem) if elem == ":": - arr.append(sub_str) - sub_str = "" - - - arr.append(sub_str) + arr.append(sub_arr) + sub_arr = [] + arr.append(sub_arr) return arr def set_pixel(self,x,y,value): - - sub_arr = self.LED[y] - - new_list = list(sub_arr) - new_list[x] = value - - self.LED[y] = "".join(new_list) + try: + self.LED[y][x] = value + except TypeError: + print(CONSTANTS.COPY_ERR_MESSAGE) def get_pixel(self,x,y): @@ -45,8 +36,30 @@ def get_pixel(self,x,y): def copy(self): return Image(list(self.LED)) - def getvalue(self): - self._BOAT = Image(CONSTANTS.BOAT) - return self._BOAT + def fill(self,value): + for y in range(0,self.height): + for x in range(0,self.width): + self.LED[y][x] = value - BOAT = property(getvalue) + @property + def width(self): + if len(self.LED): + return len(self.LED[0]) + else: + return 0 + + @width.setter + def width(self): + # will name exception later + raise Exception + + @property + def height(self): + return len(self.LED) + + @height.setter + def height(self): + # will name exception later + raise Exception + + From 32060ceb9c443613bd8e67ff1207de6983ed3889 Mon Sep 17 00:00:00 2001 From: andreamah Date: Tue, 28 Jan 2020 14:05:14 -0800 Subject: [PATCH 04/11] fixes to image --- src/microbit/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/microbit/image.py b/src/microbit/image.py index 58a670af7..15ad3e6a8 100644 --- a/src/microbit/image.py +++ b/src/microbit/image.py @@ -34,8 +34,8 @@ def get_pixel(self,x,y): return self.LED[y][x] def copy(self): - return Image(list(self.LED)) - + return Image(self.LED) + def fill(self,value): for y in range(0,self.height): for x in range(0,self.width): From ef6498cf02e11eb90cf0f9ab018a9e6bca5af2a0 Mon Sep 17 00:00:00 2001 From: andreamah Date: Tue, 28 Jan 2020 15:56:15 -0800 Subject: [PATCH 05/11] finished first draft of most image methods --- src/microbit/code_processing_shim.py | 8 +++ src/microbit/constants.py | 6 ++ src/microbit/image.py | 101 +++++++++++++++++++++++++-- 3 files changed, 109 insertions(+), 6 deletions(-) diff --git a/src/microbit/code_processing_shim.py b/src/microbit/code_processing_shim.py index eb53e10ab..6ba6366a7 100644 --- a/src/microbit/code_processing_shim.py +++ b/src/microbit/code_processing_shim.py @@ -13,4 +13,12 @@ def show_message(message): microbit = microbit_model.mb Image = image.Image +def repr(image): + + ret_str = "Image(\'" + for index_y in range(0,image.height): + ret_str += image.row_to_str(index_y) + + ret_str = ret_str + "\')" + return ret_str \ No newline at end of file diff --git a/src/microbit/constants.py b/src/microbit/constants.py index 71d5b297b..a156233f0 100644 --- a/src/microbit/constants.py +++ b/src/microbit/constants.py @@ -5,6 +5,12 @@ [9, 9, 9, 9, 9], [0, 9, 9, 9, 0]) +HEART = [[0, 9, 0, 9, 0], + [9, 9, 9, 9, 9], + [9, 9, 9, 9, 9], + [0, 9, 9, 9, 0], + [0, 0, 9, 0, 0]] + BLANK= [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], diff --git a/src/microbit/image.py b/src/microbit/image.py index 15ad3e6a8..95e62fd9f 100644 --- a/src/microbit/image.py +++ b/src/microbit/image.py @@ -3,14 +3,25 @@ from . import display class Image: - def __init__(self, pattern = CONSTANTS.BLANK): + def __init__(self, *args, **kwargs): + print("args") + print(args) # State in the Python process - if type(pattern) is str: - self.LED = self.convert_to_array(pattern) + if (len(args)==0): + self.LED = CONSTANTS.BLANK + elif (len(args)==1): + pattern = args[0] + if type(pattern) is str: + self.LED = self.convert_to_array(pattern) + else: + self.LED = pattern else: - self.LED = pattern + width = args[0] + height = args[1] + self.LED = self.create_leds(width,height) + + - def convert_to_array(self, pattern): arr = [] sub_arr = [] @@ -22,6 +33,17 @@ def convert_to_array(self, pattern): arr.append(sub_arr) return arr + def create_leds(self, w, h): + arr = [] + for _ in range(0,h): + sub_arr = [] + for _ in range(0,w): + sub_arr.append(0) + + arr.append(sub_arr) + + return arr + def set_pixel(self,x,y,value): try: @@ -36,10 +58,16 @@ def get_pixel(self,x,y): def copy(self): return Image(self.LED) + def invert(self,value): + for y in range(0,self.height): + for x in range(0,self.width): + self.set_pixel(x, y, 9-value) + + def fill(self,value): for y in range(0,self.height): for x in range(0,self.width): - self.LED[y][x] = value + self.set_pixel(x, y, value) @property def width(self): @@ -62,4 +90,65 @@ def height(self): # will name exception later raise Exception + def blit(self, src, x, y, w, h, xdest=0, ydest=0): + for count_y in range(0, h): + for count_x in range(0, w): + if (ydest + count_y < self.height and + xdest + count_x < self.width and + y + count_y < src.height and + x + count_x < src.width): + transfer_pixel = src.get_pixel(x + count_x, y + count_y) + self.set_pixel(xdest + count_x, ydest + count_y, transfer_pixel) + + def crop(self, x, y, w, h): + res = Image(w, h) + res.blit(self, x, y, w, h) + return res + + def shift_vertical(self,n): + + res = Image(self.width, self.height) + if n > 0: + # up + res.blit(self, 0, n, self.width, self.height-n, 0, 0) + else: + # down + res.blit(self, 0, 0, self.width, self.height-abs(n), 0, abs(n)) + + return res + + def shift_horizontal(self,n): + res = Image(self.width, self.height) + if n > 0: + # right + res.blit(self, 0, 0, self.width-n, self.height, n, 0) + else: + # left + res.blit(self, n, 0, self.width-n, self.height, 0, 0) + + return res + + + def shift_up(self,n): + return self.shift_vertical(n) + + def shift_down(self,n): + return self.shift_vertical(n*-1) + + def shift_right(self,n): + return self.shift_horizontal(n) + + def shift_left(self,n): + return self.shift_horizontal(n*-1) + + + def row_to_str(self, y): + new_str = "" + for x in range(0,self.width): + new_str = new_str + str(self.get_pixel(x,y)) + + new_str = new_str + ":" + + return new_str + From d2a76721b7b647fb1d13ed1988615279c9350aaf Mon Sep 17 00:00:00 2001 From: andreamah Date: Tue, 28 Jan 2020 16:00:38 -0800 Subject: [PATCH 06/11] width and height modifications --- src/microbit/code_processing_shim.py | 2 +- src/microbit/image.py | 43 ++++++++++------------------ 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/microbit/code_processing_shim.py b/src/microbit/code_processing_shim.py index 6ba6366a7..d4a5c1115 100644 --- a/src/microbit/code_processing_shim.py +++ b/src/microbit/code_processing_shim.py @@ -16,7 +16,7 @@ def show_message(message): def repr(image): ret_str = "Image(\'" - for index_y in range(0,image.height): + for index_y in range(0,image.height()): ret_str += image.row_to_str(index_y) ret_str = ret_str + "\')" diff --git a/src/microbit/image.py b/src/microbit/image.py index 95e62fd9f..f24248b6a 100644 --- a/src/microbit/image.py +++ b/src/microbit/image.py @@ -59,44 +59,32 @@ def copy(self): return Image(self.LED) def invert(self,value): - for y in range(0,self.height): - for x in range(0,self.width): + for y in range(0,self.height()): + for x in range(0,self.width()): self.set_pixel(x, y, 9-value) def fill(self,value): - for y in range(0,self.height): - for x in range(0,self.width): + for y in range(0,self.height()): + for x in range(0,self.width()): self.set_pixel(x, y, value) - @property def width(self): if len(self.LED): return len(self.LED[0]) else: return 0 - @width.setter - def width(self): - # will name exception later - raise Exception - - @property def height(self): return len(self.LED) - - @height.setter - def height(self): - # will name exception later - raise Exception def blit(self, src, x, y, w, h, xdest=0, ydest=0): for count_y in range(0, h): for count_x in range(0, w): - if (ydest + count_y < self.height and - xdest + count_x < self.width and - y + count_y < src.height and - x + count_x < src.width): + if (ydest + count_y < self.height() and + xdest + count_x < self.width() and + y + count_y < src.height() and + x + count_x < src.width()): transfer_pixel = src.get_pixel(x + count_x, y + count_y) self.set_pixel(xdest + count_x, ydest + count_y, transfer_pixel) @@ -107,25 +95,25 @@ def crop(self, x, y, w, h): def shift_vertical(self,n): - res = Image(self.width, self.height) + res = Image(self.width(), self.height()) if n > 0: # up - res.blit(self, 0, n, self.width, self.height-n, 0, 0) + res.blit(self, 0, n, self.width(), self.height()-n, 0, 0) else: # down - res.blit(self, 0, 0, self.width, self.height-abs(n), 0, abs(n)) + res.blit(self, 0, 0, self.width(), self.height()-abs(n), 0, abs(n)) return res def shift_horizontal(self,n): - res = Image(self.width, self.height) + res = Image(self.width(), self.height()) if n > 0: # right - res.blit(self, 0, 0, self.width-n, self.height, n, 0) + res.blit(self, 0, 0, self.width()-n, self.height(), n, 0) else: # left - res.blit(self, n, 0, self.width-n, self.height, 0, 0) + res.blit(self, n, 0, self.width()-n, self.height(), 0, 0) return res @@ -145,10 +133,9 @@ def shift_left(self,n): def row_to_str(self, y): new_str = "" - for x in range(0,self.width): + for x in range(0,self.width()): new_str = new_str + str(self.get_pixel(x,y)) new_str = new_str + ":" return new_str - From 16beee34091b58bf23a1756de1e81d6cc6b40e40 Mon Sep 17 00:00:00 2001 From: andreamah Date: Tue, 28 Jan 2020 17:36:04 -0800 Subject: [PATCH 07/11] more additions to image --- src/microbit/code_processing_shim.py | 16 ++++++- src/microbit/image.py | 66 +++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/microbit/code_processing_shim.py b/src/microbit/code_processing_shim.py index d4a5c1115..231f5e9b3 100644 --- a/src/microbit/code_processing_shim.py +++ b/src/microbit/code_processing_shim.py @@ -21,4 +21,18 @@ def repr(image): ret_str = ret_str + "\')" - return ret_str \ No newline at end of file + return ret_str + + +def str(image): + if type(image) is Image: + ret_str = "Image(\'\n" + for index_y in range(0,image.height()): + ret_str += "\t" + image.row_to_str(index_y) + "\n" + + ret_str = ret_str + "\')" + + return ret_str + else: + # if not image, call regular str class + return image.__str__() \ No newline at end of file diff --git a/src/microbit/image.py b/src/microbit/image.py index f24248b6a..5eee4c3c9 100644 --- a/src/microbit/image.py +++ b/src/microbit/image.py @@ -8,17 +8,22 @@ def __init__(self, *args, **kwargs): print(args) # State in the Python process if (len(args)==0): - self.LED = CONSTANTS.BLANK + self.__LED = CONSTANTS.BLANK elif (len(args)==1): pattern = args[0] if type(pattern) is str: - self.LED = self.convert_to_array(pattern) + self.__LED = self.convert_to_array(pattern) else: - self.LED = pattern + self.__LED = pattern else: + width = args[0] height = args[1] - self.LED = self.create_leds(width,height) + + if (width < 0 or height < 0): + raise Exception + + self.__LED = self.create_leds(width,height) @@ -26,11 +31,11 @@ def convert_to_array(self, pattern): arr = [] sub_arr = [] for elem in pattern: - sub_arr.append(elem) if elem == ":": arr.append(sub_arr) sub_arr = [] - arr.append(sub_arr) + else: + sub_arr.append(int(elem)) return arr def create_leds(self, w, h): @@ -47,16 +52,16 @@ def create_leds(self, w, h): def set_pixel(self,x,y,value): try: - self.LED[y][x] = value + self.__LED[y][x] = value except TypeError: print(CONSTANTS.COPY_ERR_MESSAGE) def get_pixel(self,x,y): - return self.LED[y][x] + return self.__LED[y][x] def copy(self): - return Image(self.LED) + return Image(self.__LED) def invert(self,value): for y in range(0,self.height()): @@ -70,13 +75,13 @@ def fill(self,value): self.set_pixel(x, y, value) def width(self): - if len(self.LED): - return len(self.LED[0]) + if len(self.__LED): + return len(self.__LED[0]) else: return 0 def height(self): - return len(self.LED) + return len(self.__LED) def blit(self, src, x, y, w, h, xdest=0, ydest=0): for count_y in range(0, h): @@ -139,3 +144,40 @@ def row_to_str(self, y): new_str = new_str + ":" return new_str + + + def limit_result(self,limit,result): + if (result > limit): + return limit + else: + return result + + def __add__(self, other): + if not (type(other) is Image): + raise TypeError(f"unsupported types for __add__: '{type(self)}', '{type(other)}'") + elif not (other.height() == self.height() and + other.width() == self.width()): + raise ValueError("images must be the same size") + else: + res = Image(self.width(), self.height()) + + for y in range(0,self.height()): + for x in range(0,self.width()): + sum = other.get_pixel(x,y) + self.get_pixel(x,y) + display_result = self.limit_result(9, sum) + res.set_pixel(x, y, display_result) + + return res + + + def __mul__(self, other): + float_val = float(other) + res = Image(self.width(), self.height()) + + for y in range(0,self.height()): + for x in range(0,self.width()): + product = self.get_pixel(x,y) * float_val + res.set_pixel(x, y, self.limit_result(9, product)) + + return res + \ No newline at end of file From 52ba07ebb21dc650c9bcbbc76ca791f23904d87b Mon Sep 17 00:00:00 2001 From: Vandy Liu Date: Tue, 28 Jan 2020 17:37:38 -0800 Subject: [PATCH 08/11] display microbit library --- src/microbit/constants.py | 15 ++- src/microbit/display.py | 76 +++++++++++++-- src/microbit/image.py | 147 ++++++++++++++++++++++++------ src/microbit/test/__init__.py | 0 src/microbit/test/test_display.py | 76 +++++++++++++++ 5 files changed, 276 insertions(+), 38 deletions(-) create mode 100644 src/microbit/test/__init__.py create mode 100644 src/microbit/test/test_display.py diff --git a/src/microbit/constants.py b/src/microbit/constants.py index 9ac1e2858..c64e085ee 100644 --- a/src/microbit/constants.py +++ b/src/microbit/constants.py @@ -1,5 +1,14 @@ -BOAT = ("05050:","05050:","05050:","99999:","09990") +BOAT = ("05050:", "05050:", "05050:", "99999:", "09990") -BLANK= "00000:00000:00000:00000:00000" +BLANK = "00000:00000:00000:00000:00000" -COPY_ERR_MESSAGE = "please copy() first" \ No newline at end of file +COPY_ERR_MESSAGE = "please copy() first" + +INDEX_ERR = "index out of bounds" + +BRIGHTNESS_ERR = "brightness out of bounds" + +LED_WIDTH = 5 +LED_HEIGHT = 5 + +NOT_IMPLEMENTED_ERROR = "This method is not implemented by the simulator" diff --git a/src/microbit/display.py b/src/microbit/display.py index 6ce2043bd..ec45ee2f1 100644 --- a/src/microbit/display.py +++ b/src/microbit/display.py @@ -1,11 +1,75 @@ -# class for microbit led display -class Display: +from . import constants as CONSTANTS +from .image import Image + +class Display: def __init__(self): # State in the Python process - self.count = 4 + self.__LEDs = [[0] * 5] * 5 + self.__on = True - # SAMPLE FUNCTION def scroll(self, message): - print("scroll!! " + str(self.count)) - self.count = self.count + 1 \ No newline at end of file + raise NotImplementedError(CONSTANTS.NOT_IMPLEMENTED_ERROR) + + def show(self, value, delay=400, wait=True, loop=False, clear=False): + if isinstance(value, Image): + width = ( + value.width() + if value.width() <= CONSTANTS.LED_WIDTH + else CONSTANTS.LED_WIDTH + ) + height = ( + value.height() + if value.height() <= CONSTANTS.LED_HEIGHT + else CONSTANTS.LED_HEIGHT + ) + self.__LEDs = value.LED.copy() + self.__print() + elif isinstance(value, str): + pass + elif isinstance(value, float): + pass + elif isinstance(value, int): + pass + + def get_pixel(self, x, y): + if self.__valid_pos(x, y): + return self.__LEDs[y][x] + else: + raise ValueError(CONSTANTS.INDEX_ERR) + + def set_pixel(self, x, y, value): + if not self.__valid_pos(x, y): + raise ValueError(CONSTANTS.INDEX_ERR) + elif not self.__valid_brightness(value): + raise ValueError(CONSTANTS.BRIGHTNESS_ERR) + else: + self.__LEDs[y][x] = value + + def clear(self): + for y in range(CONSTANTS.LED_WIDTH): + for x in range(CONSTANTS.LED_HEIGHT): + self.__LEDs[y][x] = 0 + + def on(self): + self.__on = True + + def off(self): + self.__on = False + + def is_on(self): + return self.__on + + def read_light_level(self): + raise NotImplementedError(CONSTANTS.NOT_IMPLEMENTED_ERROR) + + # Helpers + def __valid_pos(self, x, y): + return 0 <= x and x <= 4 and 0 <= y and y <= 4 + + def __valid_brightness(self, value): + return 0 <= value and value <= 9 + + def __print(self): + for i in range(5): + print(self.__LEDs[i]) diff --git a/src/microbit/image.py b/src/microbit/image.py index f9b1d727c..e9fcf4e40 100644 --- a/src/microbit/image.py +++ b/src/microbit/image.py @@ -2,51 +2,140 @@ from . import constants as CONSTANTS from . import display - class Image: - _BOAT = None - def __init__(self, pattern = CONSTANTS.BLANK, width=5,height=5): + def __init__(self, *args, **kwargs): + print("args") + print(args) # State in the Python process - self.width = width - self.height = height - if type(pattern) is str: - self.LED = self.convert_to_array(pattern) + if (len(args)==0): + self.LED = CONSTANTS.BLANK + elif (len(args)==1): + pattern = args[0] + if type(pattern) is str: + self.LED = self.convert_to_array(pattern) + else: + self.LED = pattern else: - self.LED = pattern + width = args[0] + height = args[1] + self.LED = self.create_leds(width,height) + + - def convert_to_array(self, pattern): arr = [] - sub_str = "" - for elem in pattern: - sub_str= sub_str + elem + sub_arr = [] + for elem in pattern: + sub_arr.append(elem) if elem == ":": - arr.append(sub_str) - sub_str = "" - - - arr.append(sub_str) + arr.append(sub_arr) + sub_arr = [] + arr.append(sub_arr) return arr + def create_leds(self, w, h): + arr = [] + for _ in range(0,h): + sub_arr = [] + for _ in range(0,w): + sub_arr.append(0) - def set_pixel(self,x,y,value): + arr.append(sub_arr) + + return arr - sub_arr = self.LED[y] - new_list = list(sub_arr) - new_list[x] = value + def set_pixel(self,x,y,value): + try: + self.LED[y][x] = value + except TypeError: + print(CONSTANTS.COPY_ERR_MESSAGE) - self.LED[y] = "".join(new_list) - def get_pixel(self,x,y): return self.LED[y][x] - + def copy(self): - return Image(list(self.LED)) + return Image(self.LED) + + def invert(self,value): + for y in range(0,self.height()): + for x in range(0,self.width()): + self.set_pixel(x, y, 9-value) + + + def fill(self,value): + for y in range(0,self.height()): + for x in range(0,self.width()): + self.set_pixel(x, y, value) + + def width(self): + if len(self.LED): + return len(self.LED[0]) + else: + return 0 + + def height(self): + return len(self.LED) + + def blit(self, src, x, y, w, h, xdest=0, ydest=0): + for count_y in range(0, h): + for count_x in range(0, w): + if (ydest + count_y < self.height() and + xdest + count_x < self.width() and + y + count_y < src.height() and + x + count_x < src.width()): + transfer_pixel = src.get_pixel(x + count_x, y + count_y) + self.set_pixel(xdest + count_x, ydest + count_y, transfer_pixel) + + def crop(self, x, y, w, h): + res = Image(w, h) + res.blit(self, x, y, w, h) + return res + + def shift_vertical(self,n): + + res = Image(self.width(), self.height()) + if n > 0: + # up + res.blit(self, 0, n, self.width(), self.height()-n, 0, 0) + else: + # down + res.blit(self, 0, 0, self.width(), self.height()-abs(n), 0, abs(n)) + + return res + + + def shift_horizontal(self,n): + res = Image(self.width(), self.height()) + if n > 0: + # right + res.blit(self, 0, 0, self.width()-n, self.height(), n, 0) + else: + # left + res.blit(self, n, 0, self.width()-n, self.height(), 0, 0) + + return res + + + def shift_up(self,n): + return self.shift_vertical(n) + + def shift_down(self,n): + return self.shift_vertical(n*-1) + + def shift_right(self,n): + return self.shift_horizontal(n) + + def shift_left(self,n): + return self.shift_horizontal(n*-1) + + + def row_to_str(self, y): + new_str = "" + for x in range(0,self.width()): + new_str = new_str + str(self.get_pixel(x,y)) - def getvalue(self): - self._BOAT = Image(CONSTANTS.BOAT) - return self._BOAT + new_str = new_str + ":" - BOAT = property(getvalue) + return new_str \ No newline at end of file diff --git a/src/microbit/test/__init__.py b/src/microbit/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/microbit/test/test_display.py b/src/microbit/test/test_display.py new file mode 100644 index 000000000..582347bf0 --- /dev/null +++ b/src/microbit/test/test_display.py @@ -0,0 +1,76 @@ +import pytest + +from .. import constants as CONSTANTS +from ..display import Display +from ..image import Image + + +class TestDisplay(object): + def setup_method(self): + self.display = Display() + + @pytest.mark.parametrize("x, y, brightness", [(1, 1, 4), (2, 3, 6), (4, 4, 9)]) + def test_get_pixel(self, x, y, brightness): + self.display._Display__LEDs[y][x] = brightness + assert brightness == self.display.get_pixel(x, y) + + @pytest.mark.parametrize("x, y", [(5, 0), (0, -1), (0, 5)]) + def test_get_pixel_error(self, x, y): + with pytest.raises(ValueError, match=CONSTANTS.INDEX_ERR): + self.display.get_pixel(x, y) + + @pytest.mark.parametrize("x, y, brightness", [(1, 1, 4), (2, 3, 6), (4, 4, 9)]) + def test_set_pixel(self, x, y, brightness): + self.display.set_pixel(x, y, brightness) + assert brightness == self.display._Display__LEDs[y][x] + + @pytest.mark.parametrize( + "x, y, brightness, err_msg", + [ + (5, 0, 0, CONSTANTS.INDEX_ERR), + (0, -1, 0, CONSTANTS.INDEX_ERR), + (0, 0, -1, CONSTANTS.BRIGHTNESS_ERR), + ], + ) + def test_set_pixel_error(self, x, y, brightness, err_msg): + with pytest.raises(ValueError, match=err_msg): + self.display.set_pixel(x, y, brightness) + + def test_clear(self): + self.display._Display__LEDs[0][0] = 7 + self.display._Display__LEDs[3][4] = 6 + self.display._Display__LEDs[4][4] = 9 + assert not self.__is_clear() + self.display.clear() + assert self.__is_clear() + + def test_on(self): + self.display._Display__on = False + self.display.on() + assert self.display._Display__on + + def test_off(self): + self.display._Display__on = True + self.display.off() + assert False == self.display._Display__on + + @pytest.mark.parametrize("on", [True, False]) + def test_is_on(self, on): + self.display._Display__on = on + assert on == self.display.is_on() + + # Helpers + def __is_clear(self): + for y in range(CONSTANTS.LED_WIDTH): + for x in range(CONSTANTS.LED_HEIGHT): + if 0 != self.display._Display__LEDs[y][x]: + return False + return True + + def test_use_me(self): + img = Image(5, 5) + img.set_pixel(0, 0, 8) + img.set_pixel(0, 1, 9) + img.set_pixel(0, 2, 7) + img.set_pixel(2, 2, 6) + self.display.show(img) From cc0ac13660bff7e1556fa311db36bfe3060e1303 Mon Sep 17 00:00:00 2001 From: Vandy Liu Date: Tue, 28 Jan 2020 17:41:44 -0800 Subject: [PATCH 09/11] update dusplay --- src/microbit/display.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/microbit/display.py b/src/microbit/display.py index ec45ee2f1..85bfd437e 100644 --- a/src/microbit/display.py +++ b/src/microbit/display.py @@ -23,7 +23,6 @@ def show(self, value, delay=400, wait=True, loop=False, clear=False): if value.height() <= CONSTANTS.LED_HEIGHT else CONSTANTS.LED_HEIGHT ) - self.__LEDs = value.LED.copy() self.__print() elif isinstance(value, str): pass From c761e8b209c3f6a6626c4a91c365d0c1028e72e9 Mon Sep 17 00:00:00 2001 From: andreamah Date: Wed, 29 Jan 2020 10:29:49 -0800 Subject: [PATCH 10/11] integrated image into display class --- src/microbit/constants.py | 1 - src/microbit/display.py | 17 +++-------------- src/microbit/image.py | 34 +++++++++++++++++++++------------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/microbit/constants.py b/src/microbit/constants.py index f3a1f20bb..ba0bd789f 100644 --- a/src/microbit/constants.py +++ b/src/microbit/constants.py @@ -1,5 +1,4 @@ INDEX_ERR = "index out of bounds" - BRIGHTNESS_ERR = "brightness out of bounds" LED_WIDTH = 5 diff --git a/src/microbit/display.py b/src/microbit/display.py index 85bfd437e..250e4de50 100644 --- a/src/microbit/display.py +++ b/src/microbit/display.py @@ -5,7 +5,7 @@ class Display: def __init__(self): # State in the Python process - self.__LEDs = [[0] * 5] * 5 + self.__image = Image() self.__on = True def scroll(self, message): @@ -32,18 +32,10 @@ def show(self, value, delay=400, wait=True, loop=False, clear=False): pass def get_pixel(self, x, y): - if self.__valid_pos(x, y): - return self.__LEDs[y][x] - else: - raise ValueError(CONSTANTS.INDEX_ERR) + return self.__image.get_pixel(x,y) def set_pixel(self, x, y, value): - if not self.__valid_pos(x, y): - raise ValueError(CONSTANTS.INDEX_ERR) - elif not self.__valid_brightness(value): - raise ValueError(CONSTANTS.BRIGHTNESS_ERR) - else: - self.__LEDs[y][x] = value + self.__image.set_pixel(x, y, value) def clear(self): for y in range(CONSTANTS.LED_WIDTH): @@ -66,9 +58,6 @@ def read_light_level(self): def __valid_pos(self, x, y): return 0 <= x and x <= 4 and 0 <= y and y <= 4 - def __valid_brightness(self, value): - return 0 <= value and value <= 9 - def __print(self): for i in range(5): print(self.__LEDs[i]) diff --git a/src/microbit/image.py b/src/microbit/image.py index dd99f2198..cc906ace3 100644 --- a/src/microbit/image.py +++ b/src/microbit/image.py @@ -24,7 +24,7 @@ def __init__(self, *args, **kwargs): if width < 0 or height < 0: raise Exception - self.__LED = self.create_leds(width, height) + self.__LED = [[0] * width] * height def convert_to_array(self, pattern): arr = [] @@ -37,25 +37,24 @@ def convert_to_array(self, pattern): sub_arr.append(int(elem)) return arr - def create_leds(self, w, h): - arr = [] - for _ in range(0, h): - sub_arr = [] - for _ in range(0, w): - sub_arr.append(0) - - arr.append(sub_arr) - - return arr def set_pixel(self, x, y, value): try: - self.__LED[y][x] = value + if not self.__valid_pos(x, y): + raise ValueError(CONSTANTS.INDEX_ERR) + elif not self.__valid_brightness(value): + raise ValueError(CONSTANTS.BRIGHTNESS_ERR) + else: + self.__LED[y][x] = value except TypeError: print(CONSTANTS.COPY_ERR_MESSAGE) def get_pixel(self, x, y): - return self.__LED[y][x] + if self.__valid_pos(x,y): + return self.__LED[y][x] + else: + raise ValueError(CONSTANTS.INDEX_ERR) + def copy(self): return Image(self.__LED) @@ -96,6 +95,10 @@ def crop(self, x, y, w, h): res.blit(self, x, y, w, h) return res + + def __valid_pos(self, x, y): + return 0 <= x and x < self.width() and 0 <= y and y < self.height() + def shift_vertical(self, n): res = Image(self.width(), self.height()) @@ -174,3 +177,8 @@ def __mul__(self, other): res.set_pixel(x, y, self.limit_result(9, product)) return res + + def __valid_brightness(self, value): + return 0 <= value and value <= 9 + + \ No newline at end of file From 4cbda2bded2becb9b58de91d36a19034c40b9760 Mon Sep 17 00:00:00 2001 From: andreamah Date: Wed, 29 Jan 2020 11:01:49 -0800 Subject: [PATCH 11/11] fixed LED array reference issue --- src/microbit/code_processing_shim.py | 18 ++- src/microbit/constants.py | 3 +- src/microbit/image.py | 184 +++++++++++++-------------- 3 files changed, 106 insertions(+), 99 deletions(-) diff --git a/src/microbit/code_processing_shim.py b/src/microbit/code_processing_shim.py index 231f5e9b3..8479d5a18 100644 --- a/src/microbit/code_processing_shim.py +++ b/src/microbit/code_processing_shim.py @@ -17,7 +17,7 @@ def repr(image): ret_str = "Image(\'" for index_y in range(0,image.height()): - ret_str += image.row_to_str(index_y) + ret_str += row_to_str(image, index_y) ret_str = ret_str + "\')" @@ -28,11 +28,23 @@ def str(image): if type(image) is Image: ret_str = "Image(\'\n" for index_y in range(0,image.height()): - ret_str += "\t" + image.row_to_str(index_y) + "\n" + ret_str += "\t" + row_to_str(image,index_y) + "\n" ret_str = ret_str + "\')" return ret_str else: # if not image, call regular str class - return image.__str__() \ No newline at end of file + return image.__str__() + + + +# method to help with string formation +def row_to_str(image, y): + new_str = "" + for x in range(0, image.width()): + new_str = new_str + str(image.get_pixel(x, y)) + + new_str = new_str + ":" + + return new_str \ No newline at end of file diff --git a/src/microbit/constants.py b/src/microbit/constants.py index ba0bd789f..61705fbef 100644 --- a/src/microbit/constants.py +++ b/src/microbit/constants.py @@ -1,6 +1,7 @@ INDEX_ERR = "index out of bounds" BRIGHTNESS_ERR = "brightness out of bounds" - +SAME_SIZE_ERR = "images must be the same size" +UNSUPPORTED_ADD_TYPE = "unsupported types for __add__:" LED_WIDTH = 5 LED_HEIGHT = 5 diff --git a/src/microbit/image.py b/src/microbit/image.py index cc906ace3..3788ecc5b 100644 --- a/src/microbit/image.py +++ b/src/microbit/image.py @@ -5,15 +5,12 @@ class Image: def __init__(self, *args, **kwargs): - print("args") - print(args) - # State in the Python process if len(args) == 0: self.__LED = CONSTANTS.BLANK elif len(args) == 1: pattern = args[0] if type(pattern) is str: - self.__LED = self.convert_to_array(pattern) + self.__LED = self.__string_to_array(pattern) else: self.__LED = pattern else: @@ -22,21 +19,20 @@ def __init__(self, *args, **kwargs): height = args[1] if width < 0 or height < 0: - raise Exception + # not in original, but ideally, + # image should fail non-silently + raise ValueError(CONSTANTS.INDEX_ERR) - self.__LED = [[0] * width] * height + self.__LED = self.__create_leds(width,height) - def convert_to_array(self, pattern): - arr = [] - sub_arr = [] - for elem in pattern: - if elem == ":": - arr.append(sub_arr) - sub_arr = [] - else: - sub_arr.append(int(elem)) - return arr + def width(self): + if len(self.__LED): + return len(self.__LED[0]) + else: + return 0 + def height(self): + return len(self.__LED) def set_pixel(self, x, y, value): try: @@ -55,6 +51,22 @@ def get_pixel(self, x, y): else: raise ValueError(CONSTANTS.INDEX_ERR) + def shift_up(self, n): + return self.__shift_vertical(n) + + def shift_down(self, n): + return self.__shift_vertical(n * -1) + + def shift_right(self, n): + return self.__shift_horizontal(n) + + def shift_left(self, n): + return self.__shift_horizontal(n * -1) + + def crop(self, x, y, w, h): + res = Image(w, h) + res.blit(self, x, y, w, h) + return res def copy(self): return Image(self.__LED) @@ -69,100 +81,29 @@ def fill(self, value): for x in range(0, self.width()): self.set_pixel(x, y, value) - def width(self): - if len(self.__LED): - return len(self.__LED[0]) - else: - return 0 - - def height(self): - return len(self.__LED) def blit(self, src, x, y, w, h, xdest=0, ydest=0): for count_y in range(0, h): for count_x in range(0, w): - if ( - ydest + count_y < self.height() - and xdest + count_x < self.width() - and y + count_y < src.height() - and x + count_x < src.width() - ): + if (self.__valid_pos(xdest + count_x, ydest + count_y) and + src.__valid_pos(x + count_x, y + count_y)): transfer_pixel = src.get_pixel(x + count_x, y + count_y) self.set_pixel(xdest + count_x, ydest + count_y, transfer_pixel) - def crop(self, x, y, w, h): - res = Image(w, h) - res.blit(self, x, y, w, h) - return res - - - def __valid_pos(self, x, y): - return 0 <= x and x < self.width() and 0 <= y and y < self.height() - - def shift_vertical(self, n): - - res = Image(self.width(), self.height()) - if n > 0: - # up - res.blit(self, 0, n, self.width(), self.height() - n, 0, 0) - else: - # down - res.blit(self, 0, 0, self.width(), self.height() - abs(n), 0, abs(n)) - - return res - - def shift_horizontal(self, n): - res = Image(self.width(), self.height()) - if n > 0: - # right - res.blit(self, 0, 0, self.width() - n, self.height(), n, 0) - else: - # left - res.blit(self, n, 0, self.width() - n, self.height(), 0, 0) - - return res - - def shift_up(self, n): - return self.shift_vertical(n) - - def shift_down(self, n): - return self.shift_vertical(n * -1) - - def shift_right(self, n): - return self.shift_horizontal(n) - - def shift_left(self, n): - return self.shift_horizontal(n * -1) - - def row_to_str(self, y): - new_str = "" - for x in range(0, self.width()): - new_str = new_str + str(self.get_pixel(x, y)) - - new_str = new_str + ":" - - return new_str - - def limit_result(self, limit, result): - if result > limit: - return limit - else: - return result - def __add__(self, other): if not (type(other) is Image): raise TypeError( - f"unsupported types for __add__: '{type(self)}', '{type(other)}'" + CONSTANTS.UNSUPPORTED_ADD_TYPE + f"'{type(self)}', '{type(other)}'" ) elif not (other.height() == self.height() and other.width() == self.width()): - raise ValueError("images must be the same size") + raise ValueError(CONSTANTS.SAME_SIZE_ERR) else: res = Image(self.width(), self.height()) - + for y in range(0, self.height()): for x in range(0, self.width()): sum = other.get_pixel(x, y) + self.get_pixel(x, y) - display_result = self.limit_result(9, sum) + display_result = self.__limit_result(9, sum) res.set_pixel(x, y, display_result) return res @@ -174,11 +115,64 @@ def __mul__(self, other): for y in range(0, self.height()): for x in range(0, self.width()): product = self.get_pixel(x, y) * float_val - res.set_pixel(x, y, self.limit_result(9, product)) + res.set_pixel(x, y, self.__limit_result(9, product)) return res + # helpers! + + def __create_leds(self, w, h): + arr = [] + for _ in range(0,h): + sub_arr = [] + for _ in range(0,w): + sub_arr.append(0) + arr.append(sub_arr) + return arr + + def __string_to_array(self, pattern): + arr = [] + sub_arr = [] + for elem in pattern: + if elem == ":": + arr.append(sub_arr) + sub_arr = [] + else: + sub_arr.append(int(elem)) + return arr + + def __limit_result(self, limit, result): + if result > limit: + return limit + else: + return result + def __valid_brightness(self, value): return 0 <= value and value <= 9 - \ No newline at end of file + + def __valid_pos(self, x, y): + return 0 <= x and x < self.width() and 0 <= y and y < self.height() + + def __shift_vertical(self, n): + + res = Image(self.width(), self.height()) + if n > 0: + # up + res.blit(self, 0, n, self.width(), self.height() - n, 0, 0) + else: + # down + res.blit(self, 0, 0, self.width(), self.height() - abs(n), 0, abs(n)) + + return res + + def __shift_horizontal(self, n): + res = Image(self.width(), self.height()) + if n > 0: + # right + res.blit(self, 0, 0, self.width() - n, self.height(), n, 0) + else: + # left + res.blit(self, n, 0, self.width() - n, self.height(), 0, 0) + + return res \ No newline at end of file