├── docs
└── .keep
├── libs
├── blocksprj
│ ├── README.md
│ ├── main.ts
│ ├── main.blocks
│ └── pxt.json
├── tsconfig.json
└── core
│ ├── pxt.json
│ ├── enums.d.ts
│ ├── ns.ts
│ ├── _locales
│ └── de
│ │ ├── core-jsdoc-strings.json
│ │ └── core-strings.json
│ └── sims.d.ts
├── targetconfig.json
├── examples
├── koch.png
├── tree.png
├── hilbert.png
├── quadrats.png
├── simple.gif
├── quadrats_blocks.png
├── quadrats.js
├── simple.js
├── primes.js
├── hilbert.js
├── koch.js
├── tree.js
├── bounce.js
├── mandelbrot.js
└── clock.js
├── .gitattributes
├── .gitignore
├── .editorconfig
├── sim
├── tsconfig.json
├── public
│ ├── sim.css
│ ├── simulator.html
│ ├── turtle2.svg
│ ├── turtle1.svg
│ └── turtle3.svg
├── sprites.ts
├── api.ts
└── simulator.ts
├── .vscode
└── settings.json
├── tslint.json
├── package.json
├── LICENSE
├── pxtarget.json
└── README.md
/docs/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/libs/blocksprj/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/targetconfig.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/libs/blocksprj/main.ts:
--------------------------------------------------------------------------------
1 | //
2 |
--------------------------------------------------------------------------------
/examples/koch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwestphal/pxt-turtle/HEAD/examples/koch.png
--------------------------------------------------------------------------------
/examples/tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwestphal/pxt-turtle/HEAD/examples/tree.png
--------------------------------------------------------------------------------
/examples/hilbert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwestphal/pxt-turtle/HEAD/examples/hilbert.png
--------------------------------------------------------------------------------
/examples/quadrats.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwestphal/pxt-turtle/HEAD/examples/quadrats.png
--------------------------------------------------------------------------------
/examples/simple.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwestphal/pxt-turtle/HEAD/examples/simple.gif
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | /libs/core/sims.d.ts eol=lf
2 | /sim/api.ts eol=lf
3 | /.vscode/settings.json eol=lf
4 |
--------------------------------------------------------------------------------
/examples/quadrats_blocks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwestphal/pxt-turtle/HEAD/examples/quadrats_blocks.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | built/
3 | /libs/core/_locales/*
4 | !/libs/core/_locales/de/
5 | /projects/
6 | *.log
7 | /gh-pages/
8 | /temp/
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | trim_trailing_whitespace = true
6 | insert_final_newline = true
7 | indent_style = space
8 | indent_size = 4
9 |
--------------------------------------------------------------------------------
/libs/blocksprj/main.blocks:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/libs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "strict": true,
5 | "outDir": "../built",
6 | "rootDir": "."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sim/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "strict": true,
5 | "declaration": true,
6 | "out": "../built/sim.js",
7 | "rootDir": "."
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/libs/blocksprj/pxt.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{0}",
3 | "dependencies": {
4 | "core": "file:../core"
5 | },
6 | "files": [
7 | "main.blocks",
8 | "main.ts",
9 | "README.md"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/sim/public/sim.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin-top: 3px;
3 | margin-right: 4px;
4 | margin-bottom: 3px;
5 | margin-left: 3px;
6 | overflow: hidden;
7 | }
8 |
9 | #area {
10 | width: 100%;
11 | border: 2px solid black;
12 | }
13 |
--------------------------------------------------------------------------------
/examples/quadrats.js:
--------------------------------------------------------------------------------
1 | function Quadrat() {
2 | for (let i = 0; i < 4; i++) {
3 | turtle.forward(100)
4 | turtle.turnRight(90)
5 | }
6 | }
7 | for (let i = 0; i < 12; i++) {
8 | Quadrat()
9 | turtle.turnRight(30)
10 | }
11 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.detectIndentation": false,
3 | "telemetry.enableCrashReporter": false,
4 | "telemetry.enableTelemetry": false,
5 | "typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
6 | "typescript.tsdk": "node_modules/typescript/lib"
7 | }
8 |
--------------------------------------------------------------------------------
/libs/core/pxt.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "core",
3 | "files": [
4 | "pxt-core.d.ts",
5 | "pxt-helpers.ts",
6 | "enums.d.ts",
7 | "sims.d.ts",
8 | "ns.ts",
9 | "_locales/de/core-strings.json",
10 | "_locales/de/core-jsdoc-strings.json"
11 | ],
12 | "testFiles": [],
13 | "dependencies": {}
14 | }
15 |
--------------------------------------------------------------------------------
/libs/core/enums.d.ts:
--------------------------------------------------------------------------------
1 | declare const enum Speed {
2 | //% block=slow
3 | Slow,
4 | //% block=normal
5 | Normal,
6 | //% block=fast
7 | Fast,
8 | //% block=fastest
9 | Fastest,
10 | }
11 |
12 | declare interface Sprite {
13 | //% shim=.getWidth
14 | readonly width: number;
15 | //% shim=.getHeight
16 | readonly height: number;
17 | }
18 |
--------------------------------------------------------------------------------
/examples/simple.js:
--------------------------------------------------------------------------------
1 | turtle.turnLeft(30)
2 | turtle.forward(100)
3 | turtle.turnRight(120)
4 | turtle.penUp()
5 | turtle.forward(100)
6 | turtle.turnRight(120)
7 | turtle.penDown()
8 | turtle.setPenColor(0x007fff)
9 | turtle.setPenSize(4)
10 | turtle.forward(200)
11 | turtle.turnLeft(120)
12 | turtle.setPenColor(0x000000)
13 | turtle.setPenSize(8)
14 | turtle.forward(100)
15 | turtle.home()
16 |
--------------------------------------------------------------------------------
/examples/primes.js:
--------------------------------------------------------------------------------
1 | let a = 0
2 | let ps: number[] = []
3 | turtle.penUp()
4 | ps = [2, 3, 5, 7]
5 | a = 1
6 | while (a < 100) {
7 | turtle.setPenSize(a * 0.1)
8 | turtle.setPenColor(0xff0000)
9 | for (let p of ps) {
10 | if (a % p == 0 && a != p || a == 1) {
11 | turtle.setPenColor(0x000000)
12 | }
13 | }
14 | turtle.print("" + a)
15 | turtle.forward(a)
16 | turtle.turnRight(30)
17 | a += 1
18 | }
19 |
--------------------------------------------------------------------------------
/sim/public/simulator.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint:recommended"
5 | ],
6 | "rules": {
7 | "comment-format": false,
8 | "max-classes-per-file": false,
9 | "max-line-length": [
10 | true,
11 | 170
12 | ],
13 | "member-access": [
14 | true,
15 | "no-public"
16 | ],
17 | "no-bitwise": false,
18 | "no-empty": false,
19 | "no-namespace": false
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/examples/hilbert.js:
--------------------------------------------------------------------------------
1 | function h (d: number, s: number, a: number) {
2 | if (d > 0) {
3 | turtle.turnLeft(a)
4 | h(d - 1, s, 0 - a)
5 | turtle.forward(s)
6 | turtle.turnRight(a)
7 | h(d - 1, s, a)
8 | turtle.forward(s)
9 | h(d - 1, s, a)
10 | turtle.turnRight(a)
11 | turtle.forward(s)
12 | h(d - 1, s, 0 - a)
13 | turtle.turnLeft(a)
14 | }
15 | }
16 | turtle.hide()
17 | turtle.setSpeed(Speed.Fastest)
18 | turtle.goto(108, -108)
19 | h(5, 7, 90)
20 |
--------------------------------------------------------------------------------
/examples/koch.js:
--------------------------------------------------------------------------------
1 | function k (d: number, s: number) {
2 | if (d > 0) {
3 | k(d - 1, s)
4 | turtle.turnLeft(60)
5 | k(d - 1, s)
6 | turtle.turnRight(120)
7 | k(d - 1, s)
8 | turtle.turnLeft(60)
9 | k(d - 1, s)
10 | } else {
11 | turtle.forward(s)
12 | }
13 | }
14 | turtle.hide()
15 | turtle.setSpeed(Speed.Fastest)
16 | turtle.setPenSize(1)
17 | turtle.goto(-120, 70)
18 | turtle.turnLeft(30)
19 | for (let index = 0; index < 3; index++) {
20 | turtle.turnRight(120)
21 | k(5, 1)
22 | }
23 |
--------------------------------------------------------------------------------
/examples/tree.js:
--------------------------------------------------------------------------------
1 | function tree (d: number) {
2 | if (d > 0) {
3 | turtle.setPenSize(d)
4 | turtle.setPenColor((10 - d) * 6400)
5 | turtle.forward(4 * d)
6 | turtle.turnLeft(20)
7 | tree(d - 1)
8 | turtle.turnRight(40)
9 | tree(d - 1)
10 | turtle.turnLeft(20)
11 | turtle.penUp()
12 | turtle.backward(4 * d)
13 | turtle.penDown()
14 | }
15 | }
16 | turtle.hide()
17 | turtle.setSpeed(Speed.Fastest)
18 | turtle.penUp()
19 | turtle.backward(100)
20 | turtle.penDown()
21 | tree(10)
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "version": "1.0.1",
4 | "scripts": {
5 | "build": "rm -rf built/ libs/core/built && pxt staticpkg",
6 | "start": "rm -rf built/ libs/core/built projects/ && pxt serve",
7 | "start:static": "http-server -s -c-1 built/packaged"
8 | },
9 | "devDependencies": {
10 | "@types/bluebird": "^2.0.33",
11 | "@types/easeljs": "^1.0.0",
12 | "@types/preloadjs": "^0.6.32",
13 | "@types/soundjs": "^0.6.27",
14 | "@types/tweenjs": "^1.0.0",
15 | "http-server": "^0.12.0",
16 | "pxt": "^0.5.1",
17 | "pxt-core": "5.24.11",
18 | "tslint": "^5.10.0",
19 | "typescript": "2.6"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/libs/core/ns.ts:
--------------------------------------------------------------------------------
1 | //% color=#00bcd4 weight=100 icon="\uf044"
2 | namespace turtle {
3 |
4 | //% blockId=spriteEditor block="%sprite"
5 | //% sprite.fieldEditor="sprite"
6 | //% sprite.fieldOptions.sizes="32,32;16,16;8,8"
7 | //% shim=TD_ID
8 | //% weight=4
9 | export function __sprite(sprite: Sprite) {
10 | return sprite;
11 | }
12 |
13 | }
14 |
15 | //% shim=@f4
16 | //% blockIdentity="turtle.__sprite"
17 | //% helper=toSprite
18 | //% groups=["0.","1#","2","3","4","5","6","7","8","9","aA","bB","cC","dD","eE","fF"]
19 | declare function img(lits: string[], ...values: any[]): Sprite;
20 |
21 | //% color=#ff8000 weight=50 icon="\uf017" advanced=true
22 | namespace time {
23 | }
24 |
25 | declare namespace console {
26 | /**
27 | * Print out message in browser console
28 | */
29 | //% shim=log
30 | function log(msg: string): void;
31 | }
32 |
--------------------------------------------------------------------------------
/examples/bounce.js:
--------------------------------------------------------------------------------
1 | turtle.turnRight(Math.randomRange(-180, 180))
2 | for (let i = 0; i < 2000; i++) {
3 | turtle.forward(10)
4 | if (turtle.y() < -145 || turtle.y() > 144) {
5 | if (turtle.heading() > 180) {
6 | turtle.turnLeft(180 + 2 * (turtle.heading() - 360))
7 | } else {
8 | turtle.turnRight(180 - 2 * turtle.heading())
9 | }
10 | } else if (turtle.x() < -145 || turtle.x() > 144) {
11 | if (turtle.heading() >= 0 && turtle.heading() < 90) {
12 | turtle.turnLeft(2 * turtle.heading())
13 | } else if (turtle.heading() >= 90 && turtle.heading() < 180) {
14 | turtle.turnRight(360 - 2 * turtle.heading())
15 | } else if (turtle.heading() >= 180 && turtle.heading() < 270) {
16 | turtle.turnLeft(2 * turtle.heading() - 360)
17 | } else {
18 | turtle.turnRight(2 * (360 - turtle.heading()))
19 | }
20 | }
21 | }
22 | turtle.home()
23 |
--------------------------------------------------------------------------------
/examples/mandelbrot.js:
--------------------------------------------------------------------------------
1 | function mand (r: number, i: number) {
2 | c = 0
3 | zr = 0
4 | zi = 0
5 | while (Math.sqrt(zr * zr + zi * zi) <= 2 && c < 100) {
6 | t = zr
7 | zr = zr * zr - zi * zi + r
8 | zi = 2 * t * zi + i
9 | c += 1
10 | }
11 | c = c / 100
12 | }
13 | let t = 0
14 | let zi = 0
15 | let zr = 0
16 | let c = 0
17 | turtle.hide()
18 | turtle.setSpeed(Speed.Fastest)
19 | turtle.goto(-125, 125)
20 | turtle.turnRight(90)
21 | turtle.setPenSize(5)
22 | for (let y = 0; y <= 49; y++) {
23 | for (let index = 0; index < 50; index++) {
24 | mand(-2 + (turtle.x() + 125) / 250 * 3, -1 + (turtle.y() + 125) / 250 * 2)
25 | turtle.setPenColor(65793 * (255 - Math.floor(c * 255)))
26 | turtle.forward(5)
27 | }
28 | turtle.penUp()
29 | if (y % 2 == 0) {
30 | turtle.turnRight(90)
31 | turtle.forward(5)
32 | turtle.turnRight(90)
33 | } else {
34 | turtle.turnLeft(90)
35 | turtle.forward(5)
36 | turtle.turnLeft(90)
37 | }
38 | turtle.penDown()
39 | }
40 |
--------------------------------------------------------------------------------
/examples/clock.js:
--------------------------------------------------------------------------------
1 | let minutes = 0
2 | let seconds = 0
3 | let hours = 0
4 | let ts = 0
5 | function drawHands() {
6 | turtle.setPenColor(0x000000)
7 | turtle.turnRight((hours + minutes / 60 + seconds / 3600) * 30)
8 | turtle.forward(45)
9 | turtle.home()
10 | turtle.turnRight((minutes + seconds / 60) * 6)
11 | turtle.forward(60)
12 | turtle.home()
13 | turtle.turnRight(seconds * 6)
14 | turtle.forward(75)
15 | turtle.home()
16 | }
17 | function drawDial() {
18 | turtle.setPenColor(0xff0000)
19 | for (let i = 0; i <= 11; i++) {
20 | turtle.turnRight(i * 30)
21 | turtle.penUp()
22 | turtle.forward(100)
23 | turtle.penDown()
24 | if (i == 0) {
25 | turtle.backward(20)
26 | } else {
27 | turtle.backward(10)
28 | }
29 | turtle.home()
30 | }
31 | }
32 | turtle.hide()
33 | turtle.setSpeed(Speed.Fastest)
34 | while (true) {
35 | turtle.clear()
36 | drawDial()
37 | ts = time.now()
38 | hours = time.hours(ts)
39 | minutes = time.minutes(ts)
40 | seconds = time.seconds(ts)
41 | drawHands()
42 | time.wait(1)
43 | }
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Harald Westphal
4 | Copyright (c) Yutaka Catch (for turtle icons)
5 |
6 | All rights reserved.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 |
--------------------------------------------------------------------------------
/pxtarget.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "turtle",
3 | "name": "Turtle",
4 | "corepkg": "core",
5 | "bundleddirs": [
6 | "libs/core"
7 | ],
8 | "runtime": {
9 | "loopsBlocks": true,
10 | "logicBlocks": true,
11 | "variablesBlocks": true,
12 | "mathBlocks": true,
13 | "functionBlocks": true,
14 | "listsBlocks": true,
15 | "textBlocks": true,
16 | "onStartColor": "#f48942",
17 | "onStartUnDeletable": true,
18 | "palette": [
19 | "#ffffff",
20 | "#000000",
21 | "#ff0000",
22 | "#ff8000",
23 | "#ffff00",
24 | "#ff9da5",
25 | "#00ff00",
26 | "#b09eff",
27 | "#00ffff",
28 | "#007fff",
29 | "#65471f",
30 | "#0000ff",
31 | "#7f00ff",
32 | "#ff0080",
33 | "#ff00ff",
34 | "#999999"
35 | ]
36 | },
37 | "simulator": {
38 | "autoRun": true,
39 | "stopOnChange": true,
40 | "hideFullscreen": true,
41 | "aspectRatio": 1
42 | },
43 | "appTheme": {
44 | "availableLocales": [
45 | "en",
46 | "de"
47 | ],
48 | "selectLanguage": true,
49 | "docMenu": [],
50 | "monacoToolbox": true,
51 | "githubUrl": "https://github.com/hwestphal/pxt-turtle"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/sim/sprites.ts:
--------------------------------------------------------------------------------
1 | namespace pxsim {
2 |
3 | export async function createTurtleSprite() {
4 | return new createjs.Sprite(await turtleSpriteSheet(), "default");
5 | }
6 |
7 | async function turtleSpriteSheet() {
8 | if (turtleSpriteSheet.cached) {
9 | return turtleSpriteSheet.cached;
10 | }
11 | const ssb = new createjs.SpriteSheetBuilder();
12 | (await loadImages("turtle1.svg", "turtle2.svg", "turtle3.svg")).map((i) => {
13 | i.regX = 218;
14 | i.regY = 265;
15 | ssb.addFrame(i, undefined, 0.06);
16 | });
17 | ssb.addAnimation("default", [0, 1, 0, 2], undefined, 0.4);
18 | turtleSpriteSheet.cached = ssb.build();
19 | return turtleSpriteSheet.cached;
20 | }
21 |
22 | namespace turtleSpriteSheet {
23 | export let cached: createjs.SpriteSheet;
24 | }
25 |
26 | function loadImages(...sources: string[]) {
27 | return new Promise((resolve, reject) => {
28 | const queue = new createjs.LoadQueue();
29 | for (const src of sources) {
30 | queue.loadFile({ src, type: createjs.LoadQueue.IMAGE });
31 | }
32 | queue.addEventListener("error", (e) => {
33 | queue.removeAllEventListeners("complete");
34 | reject(e);
35 | });
36 | queue.addEventListener("complete", () => {
37 | resolve(queue.getItems(true).map((i) => new createjs.Bitmap((i as any).result)));
38 | });
39 | });
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/libs/core/_locales/de/core-jsdoc-strings.json:
--------------------------------------------------------------------------------
1 | {
2 | "time.day": "Liefere den Tag des Zeitstempels zurück",
3 | "time.hours": "Liefere die Stunden des Zeitstempels zurück",
4 | "time.minutes": "Liefere die Minuten des Zeitstempels zurück",
5 | "time.month": "Liefere den Monat des Zeitstempels zurück",
6 | "time.now": "Liefere den aktuellen Zeitstempel zurück (in Sekunden seit Epoch)",
7 | "time.seconds": "Liefere die Sekunden des Zeitstempels zurück",
8 | "time.wait": "Warte für eine gewisse Zeit",
9 | "time.year": "Liefere das Jahr des Zeitstempels zurück",
10 | "turtle.backward": "Bewege die Turtle rückwärts",
11 | "turtle.clear": "Lösche die Zeichenfläche",
12 | "turtle.drawSprite": "Zeichne Sprite",
13 | "turtle.forward": "Bewege die Turtle vorwärts",
14 | "turtle.goto": "Bewege die Turtle zu der angegebenen Position",
15 | "turtle.heading": "Richtung der Turtle",
16 | "turtle.hide": "Verstecke die Turtle",
17 | "turtle.home": "Bewege die Turtle zum Ursprung und setze die Richtung auf 0",
18 | "turtle.penDown": "Nehme den Stift nach unten",
19 | "turtle.penUp": "Nehme den Stift nach oben",
20 | "turtle.print": "Drucke einen Text und bleibe auf der Stelle stehen",
21 | "turtle.printAndMove": "Drucke einen Text und bewege die Turtle vorwärts",
22 | "turtle.setPenColor": "Setze die Stiftfarbe",
23 | "turtle.setPenSize": "Setze die Stiftgröße",
24 | "turtle.setSpeed": "Setze die Geschwindigkeit der Turtle",
25 | "turtle.show": "Zeige die Turtle",
26 | "turtle.turnLeft": "Drehe die Turtle nach links",
27 | "turtle.turnRight": "Drehe die Turtle nach rechts",
28 | "turtle.x": "X-Position der Turtle",
29 | "turtle.y": "Y-Position der Turtle"
30 | }
31 |
--------------------------------------------------------------------------------
/libs/core/_locales/de/core-strings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Speed.Fastest|block": "am schnellsten",
3 | "Speed.Fast|block": "schnell",
4 | "Speed.Normal|block": "normal",
5 | "Speed.Slow|block": "langsam",
6 | "time.day|block": "Tag von %ts",
7 | "time.hours|block": "Stunden von %ts",
8 | "time.minutes|block": "Minuten von %ts",
9 | "time.month|block": "Monat von %ts",
10 | "time.now|block": "aktuelles Datum und Uhrzeit",
11 | "time.seconds|block": "Sekunden von %ts",
12 | "time.wait|block": "warte für %delay Sekunden",
13 | "time.year|block": "Jahr von %ts",
14 | "turtle.backward|block": "rückwärts %distance Schritte",
15 | "turtle.clear|block": "lösche die Zeichenfläche",
16 | "turtle.drawSprite|block": "zeichne %sprite=spriteEditor",
17 | "turtle.forward|block": "vorwärts %distance Schritte",
18 | "turtle.goto|block": "gehe zu x=%xpos und y=%ypos",
19 | "turtle.heading|block": "Richtung",
20 | "turtle.hide|block": "verstecke Turtle",
21 | "turtle.home|block": "zurück nach Hause",
22 | "turtle.penDown|block": "Stift nach unten",
23 | "turtle.penUp|block": "Stift nach oben",
24 | "turtle.printAndMove|block": "drucke %text und gehe vorwärts",
25 | "turtle.print|block": "drucke %text",
26 | "turtle.setPenColor|block": "Stiftfarbe auf %color=colorNumberPicker setzen",
27 | "turtle.setPenSize|block": "Stiftgröße auf %size setzen",
28 | "turtle.setSpeed|block": "Geschwindigkeit auf %speed setzen",
29 | "turtle.show|block": "zeige Turtle",
30 | "turtle.turnLeft|block": "nach links drehen um %angle Grad",
31 | "turtle.turnRight|block": "nach rechts drehen um %angle Grad",
32 | "turtle.x|block": "X-Position",
33 | "turtle.y|block": "Y-Position",
34 | "{id:category}Time": "Zeit"
35 | }
36 |
--------------------------------------------------------------------------------
/sim/public/turtle2.svg:
--------------------------------------------------------------------------------
1 |
2 |
34 |
--------------------------------------------------------------------------------
/sim/public/turtle1.svg:
--------------------------------------------------------------------------------
1 |
2 |
34 |
--------------------------------------------------------------------------------
/sim/public/turtle3.svg:
--------------------------------------------------------------------------------
1 |
2 |
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Turtle Editor #
2 |
3 | *pxt-turtle* is a programming environment fur [turtle graphics](https://en.wikipedia.org/wiki/Turtle_graphics), based on [Microsoft MakeCode](https://github.com/Microsoft/pxt). It's meant for teaching beginners in programming fundamentals.
4 |
5 | ## Features ##
6 |
7 | ### Animated turtle graphics ###
8 | 
9 |
10 | (Turtle design taken from https://github.com/ycatch/p5.turtle.js, [CreateJS](https://createjs.com/) used as animation framework)
11 |
12 | ### Visual programming ###
13 |  
14 |
15 | ## Further examples ##
16 |
17 | ### [Tree](examples/tree.js) ###
18 | 
19 |
20 | ### [Hilbert](examples/hilbert.js) and [Koch](examples/koch.js) curves ###
21 |  
22 |
23 | ## API ##
24 |
25 | declare namespace turtle {
26 | function forward(distance: number): void;
27 | function backward(distance: number): void;
28 | function turnRight(angle: number): void;
29 | function turnLeft(angle: number): void;
30 | function penUp(): void;
31 | function penDown(): void;
32 | function home(): void;
33 | function x(): number;
34 | function y(): number;
35 | function heading(): number;
36 | function setSpeed(speed: Speed): void;
37 | function setPenColor(color: number): void;
38 | function setPenSize(size: number): void;
39 | function show(): void;
40 | function hide(): void;
41 | function goto(xpos: number, ypos: number): void;
42 | function printAndMove(text: string): void;
43 | function print(text: string): void;
44 | function clear(): void;
45 | function drawSprite(sprite: Sprite): void;
46 | }
47 |
48 | declare const enum Speed {
49 | Slow, Normal, Fast, Fastest
50 | }
51 |
52 | declare interface Sprite {
53 | readonly width: number;
54 | readonly height: number;
55 | }
56 |
57 | declare namespace time {
58 | function wait(delay: number): void;
59 | function now(): number;
60 | function year(ts: number): number;
61 | function month(ts: number): number;
62 | function day(ts: number): number;
63 | function hours(ts: number): number;
64 | function minutes(ts: number): number;
65 | function seconds(ts: number): number;
66 | }
67 |
68 | declare namespace console {
69 | function log(msg: string): void;
70 | }
71 |
72 | ## How to build ##
73 | *pxt-turtle* uses [Yarn](https://yarnpkg.com/) for dependency management. To install the needed packages, simply execute `yarn` in the project root folder.
74 |
75 | ### Start in development mode ###
76 |
77 | yarn start
78 |
79 | ### Publish as GitHub pages ###
80 |
81 | yarn build --githubpages
82 |
--------------------------------------------------------------------------------
/libs/core/sims.d.ts:
--------------------------------------------------------------------------------
1 | // Auto-generated from simulator. Do not edit.
2 | declare namespace turtle {
3 | /**
4 | * Move the turtle forward
5 | * @param distance distance to move, eg: 50
6 | */
7 | //% weight=90
8 | //% blockId=turtleForward block="forward %distance steps"
9 | //% shim=turtle::forwardAsync promise
10 | function forward(distance: number): void;
11 |
12 | /**
13 | * Move the turtle backward
14 | * @param distance distance to move, eg: 50
15 | */
16 | //% weight=85
17 | //% blockId=turtleBackward block="backward %distance steps"
18 | //% shim=turtle::backwardAsync promise
19 | function backward(distance: number): void;
20 |
21 | /**
22 | * Turn the turtle to the right
23 | * @param angle degrees to turn, eg: 90
24 | */
25 | //% weight=80
26 | //% blockId=turtleTurnRight block="turn right by %angle degrees"
27 | //% angle.min=0 angle.max=360
28 | //% shim=turtle::turnRightAsync promise
29 | function turnRight(angle: number): void;
30 |
31 | /**
32 | * Turn the turtle to the left
33 | * @param angle degrees to turn, eg: 90
34 | */
35 | //% weight=75
36 | //% blockId=turtleTurnLeft block="turn left by %angle degrees"
37 | //% angle.min=0 angle.max=360
38 | //% shim=turtle::turnLeftAsync promise
39 | function turnLeft(angle: number): void;
40 |
41 | /**
42 | * Pull the pen up
43 | */
44 | //% weight=70
45 | //% blockId=turtlePenUp block="pull the pen up"
46 | //% shim=turtle::penUp
47 | function penUp(): void;
48 |
49 | /**
50 | * Pull the pen down
51 | */
52 | //% weight=65
53 | //% blockId=turtlePenDown block="pull the pen down"
54 | //% shim=turtle::penDown
55 | function penDown(): void;
56 |
57 | /**
58 | * Move the turtle to the origin and set heading to 0
59 | */
60 | //% weight=60
61 | //% blockId=turtleHome block="back to home"
62 | //% shim=turtle::homeAsync promise
63 | function home(): void;
64 |
65 | /**
66 | * X position of the turtle
67 | */
68 | //% weight=55
69 | //% blockId=turtleX block="x position"
70 | //% shim=turtle::x
71 | function x(): number;
72 |
73 | /**
74 | * Y position of the turtle
75 | */
76 | //% weight=54
77 | //% blockId=turtleY block="y position"
78 | //% shim=turtle::y
79 | function y(): number;
80 |
81 | /**
82 | * Heading of the turtle
83 | */
84 | //% weight=53
85 | //% blockId=turtleHeading block="heading"
86 | //% shim=turtle::heading
87 | function heading(): number;
88 |
89 | /**
90 | * Set the speed of the turtle
91 | * @param speed turtle speed, eg: Speed.Fast
92 | */
93 | //% weight=40
94 | //% blockId=turtleSpeed block="set speed to %speed"
95 | //% shim=turtle::setSpeed
96 | function setSpeed(speed: Speed): void;
97 |
98 | /**
99 | * Set the pen color
100 | * @param color pen color, eg: 0x007fff
101 | */
102 | //% weight=50
103 | //% blockId="turtlePenColor" block="set pen color to %color=colorNumberPicker"
104 | //% shim=turtle::setPenColor
105 | function setPenColor(color: number): void;
106 |
107 | /**
108 | * Set the pen size
109 | * @param size pen size, eg: 3
110 | */
111 | //% weight=45
112 | //% blockId="turtlePenSize" block="set pen size to %size"
113 | //% size.min=1 size.max=10
114 | //% shim=turtle::setPenSize
115 | function setPenSize(size: number): void;
116 |
117 | /**
118 | * Show the turtle
119 | */
120 | //% weight=30
121 | //% blockId=turtleShow block="show turtle"
122 | //% shim=turtle::show
123 | function show(): void;
124 |
125 | /**
126 | * Hide the turtle
127 | */
128 | //% weight=35
129 | //% blockId=turtleHide block="hide turtle"
130 | //% shim=turtle::hide
131 | function hide(): void;
132 |
133 | /**
134 | * Move the turtle to the given position
135 | * @param xpos x position
136 | * @param ypos y position
137 | */
138 | //% weight=29
139 | //% blockId=turtleGoto block="goto x=%xpos and y=%ypos"
140 | //% shim=turtle::gotoAsync promise
141 | function goto(xpos: number, ypos: number): void;
142 |
143 | /**
144 | * Print a text and move forward
145 | * @param text text to print, eg: "Hello World"
146 | */
147 | //% weight=20
148 | //% blockId=turtlePrintAndMove block="print %text and move forward"
149 | //% shim=turtle::printAndMoveAsync promise
150 | function printAndMove(text: string): void;
151 |
152 | /**
153 | * Print a text and stand still
154 | * @param text text to print, eg: "Hello World"
155 | */
156 | //% weight=25
157 | //% blockId=turtlePrint block="print %text"
158 | //% shim=turtle::printAsync promise
159 | function print(text: string): void;
160 |
161 | /**
162 | * Clear the canvas
163 | */
164 | //% weight=15
165 | //% blockId=turtleClear block="clear the canvas"
166 | //% shim=turtle::clear
167 | function clear(): void;
168 |
169 | /**
170 | * Draw sprite
171 | * @param sprite sprite to draw, eg: img``
172 | */
173 | //% weight=5
174 | //% blockId=turtleDrawSprite block="draw %sprite=spriteEditor"
175 | //% shim=turtle::drawSprite
176 | function drawSprite(sprite: Sprite): void;
177 |
178 | }
179 | declare namespace time {
180 | /**
181 | * Wait for some time
182 | * @param delay time to wait in seconds, eg: 5
183 | */
184 | //% weight=90
185 | //% blockId=timeWait block="wait for %delay seconds"
186 | //% shim=time::waitAsync promise
187 | function wait(delay: number): void;
188 |
189 | /**
190 | * Return the current date and time as seconds since epoch
191 | */
192 | //% weight=80
193 | //% blockId=timeNow block="current date and time"
194 | //% shim=time::now
195 | function now(): number;
196 |
197 | /**
198 | * Return the year of the given timestamp
199 | * @param ts timestamp
200 | */
201 | //% weight=78
202 | //% blockId=timeYear block="year of %ts"
203 | //% shim=time::year
204 | function year(ts: number): number;
205 |
206 | /**
207 | * Return the month of the given timestamp
208 | * @param ts timestamp
209 | */
210 | //% weight=77
211 | //% blockId=timeMonth block="month of %ts"
212 | //% shim=time::month
213 | function month(ts: number): number;
214 |
215 | /**
216 | * Return the day of the given timestamp
217 | * @param ts timestamp
218 | */
219 | //% weight=76
220 | //% blockId=timeDay block="day of %ts"
221 | //% shim=time::day
222 | function day(ts: number): number;
223 |
224 | /**
225 | * Return the hours of the given timestamp
226 | * @param ts timestamp
227 | */
228 | //% weight=75
229 | //% blockId=timeHours block="hours of %ts"
230 | //% shim=time::hours
231 | function hours(ts: number): number;
232 |
233 | /**
234 | * Return the minutes of the given timestamp
235 | * @param ts timestamp
236 | */
237 | //% weight=74
238 | //% blockId=timeMinutes block="minutes of %ts"
239 | //% shim=time::minutes
240 | function minutes(ts: number): number;
241 |
242 | /**
243 | * Return the seconds of the given timestamp
244 | * @param ts timestamp
245 | */
246 | //% weight=73
247 | //% blockId=timeSeconds block="seconds of %ts"
248 | //% shim=time::seconds
249 | function seconds(ts: number): number;
250 |
251 | }
252 |
253 | // Auto-generated. Do not edit. Really.
254 |
--------------------------------------------------------------------------------
/sim/api.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | namespace pxsim.turtle {
4 | /**
5 | * Move the turtle forward
6 | * @param distance distance to move, eg: 50
7 | */
8 | //% weight=90
9 | //% blockId=turtleForward block="forward %distance steps"
10 | export async function forwardAsync(distance: number) {
11 | await board().move(distance);
12 | }
13 |
14 | /**
15 | * Move the turtle backward
16 | * @param distance distance to move, eg: 50
17 | */
18 | //% weight=85
19 | //% blockId=turtleBackward block="backward %distance steps"
20 | export async function backwardAsync(distance: number) {
21 | await board().move(-distance);
22 | }
23 |
24 | /**
25 | * Turn the turtle to the right
26 | * @param angle degrees to turn, eg: 90
27 | */
28 | //% weight=80
29 | //% blockId=turtleTurnRight block="turn right by %angle degrees"
30 | //% angle.min=0 angle.max=360
31 | export async function turnRightAsync(angle: number) {
32 | await board().turn(angle);
33 | }
34 |
35 | /**
36 | * Turn the turtle to the left
37 | * @param angle degrees to turn, eg: 90
38 | */
39 | //% weight=75
40 | //% blockId=turtleTurnLeft block="turn left by %angle degrees"
41 | //% angle.min=0 angle.max=360
42 | export async function turnLeftAsync(angle: number) {
43 | await board().turn(-angle);
44 | }
45 |
46 | /**
47 | * Pull the pen up
48 | */
49 | //% weight=70
50 | //% blockId=turtlePenUp block="pull the pen up"
51 | export function penUp() {
52 | board().pen = false;
53 | }
54 |
55 | /**
56 | * Pull the pen down
57 | */
58 | //% weight=65
59 | //% blockId=turtlePenDown block="pull the pen down"
60 | export function penDown() {
61 | board().pen = true;
62 | }
63 |
64 | /**
65 | * Move the turtle to the origin and set heading to 0
66 | */
67 | //% weight=60
68 | //% blockId=turtleHome block="back to home"
69 | export async function homeAsync() {
70 | await board().moveTo(0, 0, 0);
71 | }
72 |
73 | /**
74 | * X position of the turtle
75 | */
76 | //% weight=55
77 | //% blockId=turtleX block="x position"
78 | export function x() {
79 | return board().x;
80 | }
81 |
82 | /**
83 | * Y position of the turtle
84 | */
85 | //% weight=54
86 | //% blockId=turtleY block="y position"
87 | export function y() {
88 | return board().y;
89 | }
90 |
91 | /**
92 | * Heading of the turtle
93 | */
94 | //% weight=53
95 | //% blockId=turtleHeading block="heading"
96 | export function heading() {
97 | return board().heading;
98 | }
99 |
100 | /**
101 | * Set the speed of the turtle
102 | * @param speed turtle speed, eg: Speed.Fast
103 | */
104 | //% weight=40
105 | //% blockId=turtleSpeed block="set speed to %speed"
106 | export function setSpeed(speed: Speed) {
107 | board().speed = speed;
108 | }
109 |
110 | /**
111 | * Set the pen color
112 | * @param color pen color, eg: 0x007fff
113 | */
114 | //% weight=50
115 | //% blockId="turtlePenColor" block="set pen color to %color=colorNumberPicker"
116 | export function setPenColor(color: number) {
117 | board().penColor = color;
118 | }
119 |
120 | /**
121 | * Set the pen size
122 | * @param size pen size, eg: 3
123 | */
124 | //% weight=45
125 | //% blockId="turtlePenSize" block="set pen size to %size"
126 | //% size.min=1 size.max=10
127 | export function setPenSize(size: number) {
128 | board().penSize = size;
129 | }
130 |
131 | /**
132 | * Show the turtle
133 | */
134 | //% weight=30
135 | //% blockId=turtleShow block="show turtle"
136 | export function show() {
137 | board().turtle = true;
138 | }
139 |
140 | /**
141 | * Hide the turtle
142 | */
143 | //% weight=35
144 | //% blockId=turtleHide block="hide turtle"
145 | export function hide() {
146 | board().turtle = false;
147 | }
148 |
149 | /**
150 | * Move the turtle to the given position
151 | * @param xpos x position
152 | * @param ypos y position
153 | */
154 | //% weight=29
155 | //% blockId=turtleGoto block="goto x=%xpos and y=%ypos"
156 | export async function gotoAsync(xpos: number, ypos: number) {
157 | await board().moveTo(xpos, ypos, board().heading);
158 | }
159 |
160 | /**
161 | * Print a text and move forward
162 | * @param text text to print, eg: "Hello World"
163 | */
164 | //% weight=20
165 | //% blockId=turtlePrintAndMove block="print %text and move forward"
166 | export async function printAndMoveAsync(text: string) {
167 | await board().print(text, true);
168 | }
169 |
170 | /**
171 | * Print a text and stand still
172 | * @param text text to print, eg: "Hello World"
173 | */
174 | //% weight=25
175 | //% blockId=turtlePrint block="print %text"
176 | export async function printAsync(text: string) {
177 | await board().print(text, false);
178 | }
179 |
180 | /**
181 | * Clear the canvas
182 | */
183 | //% weight=15
184 | //% blockId=turtleClear block="clear the canvas"
185 | export function clear() {
186 | board().clear();
187 | }
188 |
189 | /**
190 | * Draw sprite
191 | * @param sprite sprite to draw, eg: img``
192 | */
193 | //% weight=5
194 | //% blockId=turtleDrawSprite block="draw %sprite=spriteEditor"
195 | export function drawSprite(sprite: Sprite) {
196 | board().drawSprite(sprite as SpriteImpl);
197 | }
198 |
199 | }
200 |
201 | namespace pxsim.time {
202 | /**
203 | * Wait for some time
204 | * @param delay time to wait in seconds, eg: 5
205 | */
206 | //% weight=90
207 | //% blockId=timeWait block="wait for %delay seconds"
208 | export async function waitAsync(delay: number) {
209 | await Promise.delay(delay * 1000);
210 | }
211 |
212 | /**
213 | * Return the current date and time as seconds since epoch
214 | */
215 | //% weight=80
216 | //% blockId=timeNow block="current date and time"
217 | export function now() {
218 | return Math.floor(Date.now() / 1000);
219 | }
220 |
221 | /**
222 | * Return the year of the given timestamp
223 | * @param ts timestamp
224 | */
225 | //% weight=78
226 | //% blockId=timeYear block="year of %ts"
227 | export function year(ts: number) {
228 | return asDate(ts).getFullYear();
229 | }
230 |
231 | /**
232 | * Return the month of the given timestamp
233 | * @param ts timestamp
234 | */
235 | //% weight=77
236 | //% blockId=timeMonth block="month of %ts"
237 | export function month(ts: number) {
238 | return asDate(ts).getMonth() + 1;
239 | }
240 |
241 | /**
242 | * Return the day of the given timestamp
243 | * @param ts timestamp
244 | */
245 | //% weight=76
246 | //% blockId=timeDay block="day of %ts"
247 | export function day(ts: number) {
248 | return asDate(ts).getDate();
249 | }
250 |
251 | /**
252 | * Return the hours of the given timestamp
253 | * @param ts timestamp
254 | */
255 | //% weight=75
256 | //% blockId=timeHours block="hours of %ts"
257 | export function hours(ts: number) {
258 | return asDate(ts).getHours();
259 | }
260 |
261 | /**
262 | * Return the minutes of the given timestamp
263 | * @param ts timestamp
264 | */
265 | //% weight=74
266 | //% blockId=timeMinutes block="minutes of %ts"
267 | export function minutes(ts: number) {
268 | return asDate(ts).getMinutes();
269 | }
270 |
271 | /**
272 | * Return the seconds of the given timestamp
273 | * @param ts timestamp
274 | */
275 | //% weight=73
276 | //% blockId=timeSeconds block="seconds of %ts"
277 | export function seconds(ts: number) {
278 | return asDate(ts).getSeconds();
279 | }
280 |
281 | function asDate(ts: number) {
282 | const d = new Date();
283 | d.setTime(ts * 1000);
284 | return d;
285 | }
286 |
287 | }
288 |
--------------------------------------------------------------------------------
/sim/simulator.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | namespace pxsim {
4 |
5 | initCurrentRuntime = () => {
6 | runtime.board = new TurtleBoard();
7 | };
8 |
9 | export function board() {
10 | return runtime.board as TurtleBoard;
11 | }
12 |
13 | export class TurtleBoard extends BaseBoard {
14 | x = 0;
15 | y = 0;
16 | heading = 0;
17 | pen = true;
18 | penSize = 2;
19 |
20 | private readonly stage: createjs.Stage;
21 | private readonly xOffset: number;
22 | private readonly yOffset: number;
23 | private delay = delays[Speed.Normal];
24 | private color = "#ff0000";
25 | private turtleSprite?: createjs.Sprite;
26 |
27 | constructor() {
28 | super();
29 | this.stage = new createjs.Stage("area");
30 | createjs.Ticker.addEventListener("tick", this.stage);
31 | const canvas = this.stage.canvas as HTMLCanvasElement;
32 | canvas.getContext("2d")!.imageSmoothingEnabled = false;
33 | this.xOffset = canvas.width / 2;
34 | this.yOffset = canvas.height / 2;
35 | const rect = this.stage.addChild(new createjs.Shape());
36 | rect.graphics.beginFill("white").rect(0, 0, canvas.width, canvas.height);
37 | }
38 |
39 | async initAsync(msg: SimulatorRunMessage) {
40 | const sprite = await createTurtleSprite();
41 | sprite.x = this.xOffset;
42 | sprite.y = this.yOffset;
43 | sprite.paused = true;
44 | this.turtleSprite = this.stage.addChild(sprite);
45 | // avoid flickering on start
46 | await Promise.delay(1000);
47 | }
48 |
49 | kill() {
50 | createjs.Ticker.removeEventListener("tick", this.stage as any);
51 | }
52 |
53 | set speed(s: Speed) {
54 | this.delay = delays[s];
55 | }
56 |
57 | set penColor(color: number) {
58 | this.color = `#${("00000" + color.toString(16)).substr(-6)}`;
59 | }
60 |
61 | set turtle(visible: boolean) {
62 | this.turtleSprite!.visible = visible;
63 | }
64 |
65 | move(distance: number) {
66 | const x = this.x;
67 | const y = this.y;
68 | this.x += distance * Math.sin(this.heading * Math.PI / 180);
69 | this.y += distance * Math.cos(this.heading * Math.PI / 180);
70 | const tx = this.xOffset + this.x;
71 | const ty = this.yOffset - this.y;
72 | if (this.pen || this.turtleSprite!.visible) {
73 | const line = this.stage.addChild(new createjs.Shape());
74 | line.visible = this.pen;
75 | const g = line.graphics
76 | .setStrokeStyle(this.penSize)
77 | .beginStroke(this.color)
78 | .moveTo(this.xOffset + x, this.yOffset - y);
79 | this.turtleToFront();
80 | if (this.delay > 0) {
81 | const cmd = g.lineTo(this.xOffset + x, this.yOffset - y).command;
82 | const duration = this.delay * Math.abs(distance);
83 | this.turtleSprite!.play();
84 | createjs.Tween.get(this.turtleSprite!).to({ x: tx, y: ty }, duration);
85 | return new Promise((resolve) => {
86 | createjs.Tween.get(cmd)
87 | .to({ x: tx, y: ty }, duration)
88 | .call(() => {
89 | this.turtleSprite!.gotoAndStop(0);
90 | resolve();
91 | });
92 | });
93 | }
94 | g.lineTo(tx, ty).endStroke();
95 | }
96 | this.turtleSprite!.x = tx;
97 | this.turtleSprite!.y = ty;
98 | return Promise.resolve();
99 | }
100 |
101 | turn(angle: number) {
102 | const h = (this.heading + angle) % 360;
103 | const heading = this.heading;
104 | this.heading = h < 0 ? h + 360 : h;
105 | if (this.turtleSprite!.visible && this.delay > 0) {
106 | this.turtleSprite!.play();
107 | return new Promise((resolve) => {
108 | createjs.Tween.get(this.turtleSprite!)
109 | .to({ rotation: heading + angle }, this.delay * 0.5 * Math.abs(angle))
110 | .call(() => {
111 | this.turtleSprite!.gotoAndStop(0);
112 | this.turtleSprite!.rotation = this.heading;
113 | resolve();
114 | });
115 | });
116 | }
117 | this.turtleSprite!.rotation = this.heading;
118 | return Promise.resolve();
119 | }
120 |
121 | async moveTo(nx: number, ny: number, nh: number) {
122 | if (this.x !== nx || this.y !== ny) {
123 | const pen = this.pen;
124 | this.pen = false;
125 | const angle = Math.atan2(this.x - nx, this.y - ny) * 180 / Math.PI;
126 | await this.turn(normalize(angle - this.heading - 180));
127 | await this.move(Math.sqrt((this.x - nx) ** 2 + (this.y - ny) ** 2));
128 | this.pen = pen;
129 | }
130 | await this.turn(normalize(nh - this.heading));
131 | this.x = nx;
132 | this.y = ny;
133 | this.heading = nh;
134 | this.turtleSprite!.x = this.xOffset + nx;
135 | this.turtleSprite!.y = this.yOffset - ny;
136 | this.turtleSprite!.rotation = nh;
137 | }
138 |
139 | async print(text: string, move: boolean) {
140 | const t = this.stage.addChild(new createjs.Text(text, `${8 + this.penSize * 2}px monospace`, this.color));
141 | t.x = this.xOffset + this.x;
142 | t.y = this.yOffset - this.y;
143 | t.rotation = this.heading - 90;
144 | t.textBaseline = "middle";
145 | this.turtleToFront();
146 | if (move) {
147 | const pen = this.pen;
148 | this.pen = false;
149 | await this.move(t.getBounds().width);
150 | this.pen = pen;
151 | }
152 | }
153 |
154 | clear() {
155 | while (this.stage.numChildren > 2) {
156 | this.stage.removeChildAt(1);
157 | }
158 | }
159 |
160 | drawSprite(sprite: SpriteImpl) {
161 | const bitmap = new createjs.Bitmap(sprite.canvas);
162 | bitmap.regX = sprite.width / 2;
163 | bitmap.regY = sprite.height / 2;
164 | bitmap.x = this.xOffset + this.x;
165 | bitmap.y = this.yOffset - this.y;
166 | bitmap.rotation = this.heading;
167 | bitmap.scaleX = bitmap.scaleY = this.penSize;
168 | this.stage.addChild(bitmap);
169 | this.turtleToFront();
170 | }
171 |
172 | private turtleToFront() {
173 | this.stage.setChildIndex(this.turtleSprite!, this.stage.numChildren - 1);
174 | }
175 |
176 | }
177 |
178 | function normalize(a: number) {
179 | a %= 360;
180 | return a > 180 ? a - 360 : a <= -180 ? a + 360 : a;
181 | }
182 |
183 | const delays = {
184 | [Speed.Normal]: 15,
185 | [Speed.Slow]: 30,
186 | [Speed.Fast]: 1,
187 | [Speed.Fastest]: 0,
188 | };
189 |
190 | export function log(msg: string) {
191 | // tslint:disable-next-line:no-console
192 | console.log(`%c${toLocalISOString(new Date())} %c[TURTLE]`, "color: blue; font-style: italic", "font-weight: bold", msg);
193 | }
194 |
195 | function toLocalISOString(date: Date) {
196 | const modDate = new Date();
197 | modDate.setTime(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
198 | return modDate.toISOString().slice(0, -1);
199 | }
200 |
201 | export function toSprite(buffer: RefBuffer): Sprite {
202 | const width = buffer.data[2] + (buffer.data[3] << 8);
203 | const height = buffer.data[4] + (buffer.data[5] << 8);
204 | const dataHeight = Math.ceil(height / 8) * 8;
205 | const data = buffer.data.slice(8);
206 | const array = new Uint8ClampedArray(width * height * 4);
207 | for (let i = 0; i < data.length; i++) {
208 | const x = Math.floor(2 * i / dataHeight);
209 | const y = (2 * i) % dataHeight;
210 | setColor(data[i] & 0x0f, array, width, x, y);
211 | setColor(data[i] >> 4, array, width, x, y + 1);
212 | }
213 | const canvas = document.createElement("canvas");
214 | canvas.width = width;
215 | canvas.height = height;
216 | canvas.getContext("2d")!.putImageData(new ImageData(array, width, height), 0, 0);
217 | return new SpriteImpl(canvas);
218 | }
219 |
220 | export class SpriteImpl implements Sprite {
221 | constructor(public canvas: HTMLCanvasElement) { }
222 |
223 | get width() {
224 | return this.canvas.width;
225 | }
226 |
227 | get height() {
228 | return this.canvas.height;
229 | }
230 |
231 | private getWidth() {
232 | return this.width;
233 | }
234 |
235 | private getHeight() {
236 | return this.height;
237 | }
238 | }
239 |
240 | const palette = [
241 | [0x00, 0x00, 0x00],
242 | [0xff, 0x00, 0x00],
243 | [0xff, 0x80, 0x00],
244 | [0xff, 0xff, 0x00],
245 | [0xff, 0x9d, 0xa5],
246 | [0x00, 0xff, 0x00],
247 | [0xb0, 0x9e, 0xff],
248 | [0x00, 0xff, 0xff],
249 | [0x00, 0x7f, 0xff],
250 | [0x65, 0x47, 0x1f],
251 | [0x00, 0x00, 0xff],
252 | [0x7f, 0x00, 0xff],
253 | [0xff, 0x00, 0x80],
254 | [0xff, 0x00, 0xff],
255 | [0x99, 0x99, 0x99],
256 | ];
257 |
258 | function setColor(color: number, data: Uint8Array, width: number, x: number, y: number) {
259 | if (color > 0) {
260 | color -= 1;
261 | const i = 4 * (x + y * width);
262 | data[i] = palette[color][0];
263 | data[i + 1] = palette[color][1];
264 | data[i + 2] = palette[color][2];
265 | data[i + 3] = 0xff;
266 | }
267 | }
268 |
269 | }
270 |
--------------------------------------------------------------------------------