diff --git a/.gitignore b/.gitignore index a380d480..fb7912e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules yotta_modules yotta_targets +pxt_modules built typings tmp @@ -18,4 +19,4 @@ clients/**/obj/** *.tgz *.db *.suo -*.log \ No newline at end of file +*.log diff --git a/.travis.yml b/.travis.yml index 08b12ffb..cc2e4e19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,9 @@ node_js: script: - "node node_modules/pxt-core/built/pxt.js travis" - "(cd libs/lang-test0; node ../../node_modules/pxt-core/built/pxt.js run)" + - "node node_modules/pxt-core/built/pxt.js testdir tests" - "node node_modules/pxt-core/built/pxt.js uploaddoc" - - "(cd libs/hello; node ../../node_modules/pxt-core/built/pxt.js testconv ../../testconv.json)" + - "(cd libs/hello; node ../../node_modules/pxt-core/built/pxt.js testconv https://az851932.vo.msecnd.net/files/td-converter-tests-v0.json)" sudo: false notifications: email: @@ -14,4 +15,5 @@ cache: directories: - node_modules - built/cache + - libs/hello/built/cache diff --git a/docs/about.md b/docs/about.md index d5d8242b..99839f62 100644 --- a/docs/about.md +++ b/docs/about.md @@ -38,7 +38,9 @@ Learn about the [hardware components](/device) of the micro:bit to make the most You can program the micro:bit using [Blocks](/blocks) or [JavaScript](/javascript), via the [micro:bit APIs](/reference): ```blocks -basic.showString("Hi!"); +input.onButtonPressed(Button.A, () => { + basic.showString("Hi!"); +}) ``` ## Compile and Flash: Your Program! diff --git a/docs/getting-started.md b/docs/getting-started.md index f00cd502..dab6bddf 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -2,16 +2,13 @@ ## ~avatar -Are you ready to build cool micro:bit programs? - Here are some challenges for you. Arrange the blocks in the editor to make real programs that work! ## ~ -Use the **Basic** drawer in the editor (to the left) -to drag out and arrange three blocks (two `show leds` and one `forever` block) -to create this program: +Use the **Basic** drawer in the editor +to drag out and arrange three blocks to create this program: ```blocks basic.forever(() => { diff --git a/docs/javascript.md b/docs/javascript.md index 3a2be6e2..a395019d 100644 --- a/docs/javascript.md +++ b/docs/javascript.md @@ -1,15 +1,57 @@ -# JavaScript +# JavaScript and TypeScript -If you already know some JavaScript, you might be interested in [the JavaScript and TypeScript languages](/js/lang). -Otherwise, visit the cards below to starting programming JavaScript with the micro:bit: +Visit the cards below to starting programming JavaScript and TypeScript with the micro:bit: ```codecard [{ - "name": "Calling Functions", - "url":"/js/call" + "name": "Calling", + "url": "/js/call" },{ - "name": "Sequencing Commands", - "url":"/js/sequence" + "name": "Sequencing", + "url": "/js/sequence" +},{ + "name": "Variables", + "url": "/js/variables" +},{ + "name": "Operators", + "url": "/js/operators" +},{ + "name": "Statements", + "url": "/js/statements" +},{ + "name": "Functions", + "url": "/js/functions" +},{ + "name": "Types", + "url": "/js/types" +},{ + "name": "Classes", + "url": "/js/classes" +}] +``` + +## More information on TypeScript + +You can write micro:bit programs in a subset of [TypeScript](https://www.typescriptlang.org), which is a superset of JavaScript. +Many micro:bit programs, especially at the beginner's level, are just plain JavaScript. TypeScript introduces class-based +object-oriented programming, such as: + +```typescript +class Greeter { + greeting: string; + constructor(message: string) { + this.greeting = message; + } + greet() { + return "Hello, " + this.greeting; + } } -] -``` \ No newline at end of file + +let greeter = new Greeter("world"); +basic.showString(greeter.greet()) +``` + +This site is meant for teaching programming first, and JavaScript second. For this +reason, we have stayed away from concepts that are specific to JavaScript (for +example, prototype inheritance), and instead focused on ones common to most +modern programming languages (lexically scoped variables, functions, classes). \ No newline at end of file diff --git a/docs/js/call.md b/docs/js/call.md index b548ca60..c5a2d5d8 100644 --- a/docs/js/call.md +++ b/docs/js/call.md @@ -3,8 +3,8 @@ The simplest way to get started in JavaScript with your micro:bit is to call one of the micro:bit's built-in JavaScript functions. Just like Blocks are organized into categories/drawers, the micro:bit functions are organized by -namespaces, with names corresponding to the drawer names. -The `basic` namespace contains a number of very helpful functions: +namespaces, with names corresponding to the drawer names. The `basic` namespace +contains a number of helpful functions, such as: ```typescript basic.showString("Hello!") diff --git a/docs/js/classes.md b/docs/js/classes.md new file mode 100644 index 00000000..832eecf0 --- /dev/null +++ b/docs/js/classes.md @@ -0,0 +1,268 @@ +# Classes + +Traditional JavaScript focuses on functions and prototype-based inheritance as the basic means of building up reusable components, +but this may feel a bit awkward to programmers more comfortable with an object-oriented approach, where classes inherit functionality +and objects are built from these classes. + +Starting with ECMAScript 2015, also known as ECMAScript 6, JavaScript programmers will be able to build their applications using +this object-oriented class-based approach. TypeScript, allows you to use these techniques now, compiling them +down to JavaScript that works across all major browsers and platforms, without having to wait for the next version of JavaScript. + +Let's take a look at a simple class-based example: + +```ts +class Greeter { + greeting: string; + constructor(message: string) { + this.greeting = message; + } + greet() { + return "Hello, " + this.greeting; + } +} + +let greeter = new Greeter("world"); +``` + +We declare a new class `Greeter`. This class has three members: a property called `greeting`, a constructor, and a method `greet`. + +You'll notice that in the class when we refer to one of the members of the class we prepend `this.`. +This denotes that it's a member access. + +In the last line we construct an instance of the `Greeter` class using `new`. +This calls into the constructor we defined earlier, creating a new object with the `Greeter` shape, and running the constructor to initialize it. + +# Inheritance + +### ~hint +### Inheritance is not supported yet for the micro:bit. Coming soon... +### ~ + +In TypeScript, we can use common object-oriented patterns. +Of course, one of the most fundamental patterns in class-based programming is being able to extend existing classes to create new ones using inheritance. + +Let's take a look at an example: + +```ts +class Animal { + name: string; + constructor(theName: string) { this.name = theName; } + move(distanceInMeters: number = 0) { + console.log(`${this.name} moved ${distanceInMeters}m.`); + } +} + +class Snake extends Animal { + constructor(name: string) { super(name); } + move(distanceInMeters = 5) { + console.log("Slithering..."); + super.move(distanceInMeters); + } +} + +class Horse extends Animal { + constructor(name: string) { super(name); } + move(distanceInMeters = 45) { + console.log("Galloping..."); + super.move(distanceInMeters); + } +} + +let sam = new Snake("Sammy the Python"); +let tom: Animal = new Horse("Tommy the Palomino"); + +sam.move(); +tom.move(34); +``` + +This example covers quite a few of the inheritance features in TypeScript that are common to other languages. +Here we see the `extends` keywords used to create a subclass. +You can see this where `Horse` and `Snake` subclass the base class `Animal` and gain access to its features. + +Derived classes that contain constructor functions must call `super()` which will execute the constructor function on the base class. + +The example also shows how to override methods in the base class with methods that are specialized for the subclass. +Here both `Snake` and `Horse` create a `move` method that overrides the `move` from `Animal`, giving it functionality specific to each class. +Note that even though `tom` is declared as an `Animal`, since its value is a `Horse`, when `tom.move(34)` calls the overriding method in `Horse`: + +```Text +Slithering... +Sammy the Python moved 5m. +Galloping... +Tommy the Palomino moved 34m. +``` + +# Public, private, and protected modifiers + +## Public by default + +In our examples, we've been able to freely access the members that we declared throughout our programs. +If you're familiar with classes in other languages, you may have noticed in the above examples +we haven't had to use the word `public` to accomplish this; for instance, +C# requires that each member be explicitly labeled `public` to be visible. +In TypeScript, each member is `public` by default. + +You may still mark a member `public` explicitly. +We could have written the `Animal` class from the previous section in the following way: + +```ts +class Animal { + public name: string; + public constructor(theName: string) { this.name = theName; } + public move(distanceInMeters: number) { + console.log(`${this.name} moved ${distanceInMeters}m.`); + } +} +``` + +## Understanding `private` + +When a member is marked `private`, it cannot be accessed from outside of its containing class. For example: + +```ts +class Animal { + private name: string; + constructor(theName: string) { this.name = theName; } +} + +new Animal("Cat").name; // Error: 'name' is private; +``` + +TypeScript is a structural type system. +When we compare two different types, regardless of where they came from, if the types of all members are compatible, then we say the types themselves are compatible. + +However, when comparing types that have `private` and `protected` members, we treat these types differently. +For two types to be considered compatible, if one of them has a `private` member, +then the other must have a `private` member that originated in the same declaration. +The same applies to `protected` members. + +Let's look at an example to better see how this plays out in practice: + +```ts +class Animal { + private name: string; + constructor(theName: string) { this.name = theName; } +} + +class Rhino extends Animal { + constructor() { super("Rhino"); } +} + +class Employee { + private name: string; + constructor(theName: string) { this.name = theName; } +} + +let animal = new Animal("Goat"); +let rhino = new Rhino(); +let employee = new Employee("Bob"); + +animal = rhino; +animal = employee; // Error: 'Animal' and 'Employee' are not compatible +``` + +In this example, we have an `Animal` and a `Rhino`, with `Rhino` being a subclass of `Animal`. +We also have a new class `Employee` that looks identical to `Animal` in terms of shape. +We create some instances of these classes and then try to assign them to each other to see what will happen. +Because `Animal` and `Rhino` share the `private` side of their shape from the same declaration of +`private name: string` in `Animal`, they are compatible. However, this is not the case for `Employee`. +When we try to assign from an `Employee` to `Animal` we get an error that these types are not compatible. +Even though `Employee` also has a `private` member called `name`, it's not the one we declared in `Animal`. + +## Understanding `protected` + +The `protected` modifier acts much like the `private` modifier with the exception that members +declared `protected` can also be accessed by instances of deriving classes. For example, + +```ts +class Person { + protected name: string; + constructor(name: string) { this.name = name; } +} + +class Employee extends Person { + private department: string; + + constructor(name: string, department: string) { + super(name); + this.department = department; + } + + public getElevatorPitch() { + return `Hello, my name is ${this.name} and I work in ${this.department}.`; + } +} + +let howard = new Employee("Howard", "Sales"); +console.log(howard.getElevatorPitch()); +console.log(howard.name); // error +``` + +Notice that while we can't use `name` from outside of `Person`, +we can still use it from within an instance method of `Employee` because `Employee` derives from `Person`. + +A constructor may also be marked `protected`. +This means that the class cannot be instantiated outside of its containing class, but can be extended. For example, + +```ts +class Person { + protected name: string; + protected constructor(theName: string) { this.name = theName; } +} + +// Employee can extend Person +class Employee extends Person { + private department: string; + + constructor(name: string, department: string) { + super(name); + this.department = department; + } + + public getElevatorPitch() { + return `Hello, my name is ${this.name} and I work in ${this.department}.`; + } +} + +let howard = new Employee("Howard", "Sales"); +let john = new Person("John"); // Error: The 'Person' constructor is protected +``` + +# Readonly modifier + +You can make properties readonly by using the `readonly` keyword. +Readonly properties must be initialized at their declaration or in the constructor. + +```ts +class Octopus { + readonly name: string; + readonly numberOfLegs: number = 8; + constructor (theName: string) { + this.name = theName; + } +} +let dad = new Octopus("Man with the 8 strong legs"); +dad.name = "Man with the 3-piece suit"; // error! name is readonly. +``` + +## Parameter properties + +In our last example, we had to declare a readonly member `name` and a constructor parameter `theName` in the `Octopus` class, and we then immediately set `name` to `theName`. +This turns out to be a very common practice. +*Parameter properties* let you create and initialize a member in one place. +Here's a further revision of the previous `Octopus` class using a parameter property: + +```ts +class Octopus { + readonly numberOfLegs: number = 8; + constructor(readonly name: string) { + } +} +``` + +Notice how we dropped `theName` altogether and just use the shortened `readonly name: string` parameter on the constructor to create and initialize the `name` member. +We've consolidated the declarations and assignment into one location. + +Parameter properties are declared by prefixing a constructor parameter with an accessibility modifier or `readonly`, or both. +Using `private` for a parameter property declares and initializes a private member; likewise, the same is done for `public`, `protected`, and `readonly`. + diff --git a/docs/js/functions.md b/docs/js/functions.md new file mode 100644 index 00000000..c11d20d7 --- /dev/null +++ b/docs/js/functions.md @@ -0,0 +1,161 @@ +# Functions + +Functions are the fundamental building block of programs. Here is the simplest +way to make a function that adds two numbers: + +```ts +// Named function +function add(x : number, y : number) { + return x + y; +} + +basic.showNumber(add(1, 2)) +``` + +### ~ hint +For the micro:bit, you must specify a [type](/js/types) for each function parameter. +### ~ + +Functions can refer to variables outside of the function body. +When they do so, they're said to `capture` these variables. + +```ts +let z = 100; + +function addToZ(x: number, y: number) { + return x + y + z; +} + +basic.showNumber(addToZ(1, 2)) +``` + +## Typing the function + +Let's add a return type to our add function: + +```ts +function add(x: number, y: number): number { + return x + y; +} +``` + +TypeScript can figure the return type out by looking at the return statements, so you can optionally leave this off in many cases. + +# Optional and Default Parameters + +In TypeScript, the number of arguments given to a function has to match the number of parameters the function expects. + +```ts +function buildName(firstName: string, lastName: string) { + return firstName + " " + lastName; +} + +let result1 = buildName("Bob"); // error, too few parameters +let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters +let result3 = buildName("Bob", "Adams"); // ah, just right +``` + +In JavaScript, every parameter is optional, and users may leave them off as they see fit. +When they do, their value is `undefined`. +We can get this functionality in TypeScript by adding a `?` to the end of parameters we want to be optional. +For example, let's say we want the last name parameter from above to be optional: + +```ts +function buildName(firstName: string, lastName?: string) { + if (lastName) + return firstName + " " + lastName; + else + return firstName; +} + +let result1 = buildName("Bob"); // works correctly now +let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters +let result3 = buildName("Bob", "Adams"); // ah, just right +``` + +Any optional parameters must follow required parameters. +Had we wanted to make the first name optional rather than the last name, we would need to change the order of parameters in the function, putting the first name last in the list. + +In TypeScript, we can also set a value that a parameter will be assigned if the user does not provide one, or if the user passes `undefined` in its place. +These are called default-initialized parameters. +Let's take the previous example and default the last name to `"Smith"`. + +```ts +function buildName(firstName: string, lastName = "Smith") { + return firstName + " " + lastName; +} + +let result1 = buildName("Bob"); // works correctly now, returns "Bob Smith" +let result2 = buildName("Bob", undefined); // still works, also returns "Bob Smith" +let result3 = buildName("Bob", "Adams", "Sr."); // error, too many parameters +let result4 = buildName("Bob", "Adams"); // ah, just right +``` + +Default-initialized parameters that come after all required parameters are treated as optional, and just like optional parameters, can be omitted when calling their respective function. +This means optional parameters and trailing default parameters will share commonality in their types, so both + +```ts +function buildName(firstName: string, lastName?: string) { + // ... +} +``` + +and + +```ts +function buildName(firstName: string, lastName = "Smith") { + // ... +} +``` + +share the same type `(firstName: string, lastName?: string) => string`. +The default value of `lastName` disappears in the type, only leaving behind the fact that the parameter is optional. + +Unlike plain optional parameters, default-initialized parameters don't *need* to occur after required parameters. +If a default-initialized parameter comes before a required parameter, users need to explicitly pass `undefined` to get the default initialized value. +For example, we could write our last example with only a default initializer on `firstName`: + +```ts +function buildName(firstName = "Will", lastName: string) { + return firstName + " " + lastName; +} + +let result1 = buildName("Bob"); // error, too few parameters +let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters +let result3 = buildName("Bob", "Adams"); // okay and returns "Bob Adams" +let result4 = buildName(undefined, "Adams"); // okay and returns "Will Adams" +``` + +# Rest Parameters + +Required, optional, and default parameters all have one thing in common: they talk about one parameter at a time. +Sometimes, you want to work with multiple parameters as a group, or you may not know how many parameters a function will ultimately take. +In JavaScript, you can work with the arguments directly using the `arguments` variable that is visible inside every function body. + +In TypeScript, you can gather these arguments together into a variable: + +```ts +function buildName(firstName: string, ...restOfName: string[]) { + return firstName + " " + restOfName.join(" "); +} + +let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie"); +``` + +*Rest parameters* are treated as a boundless number of optional parameters. +When passing arguments for a rest parameter, you can use as many as you want; you can even pass none. +The compiler will build an array of the arguments passed in with the name given after the ellipsis (`...`), allowing you to use it in your function. + +The ellipsis is also used in the type of the function with rest parameters: + +```ts +function buildName(firstName: string, ...restOfName: string[]) { + return firstName + " " + restOfName.join(" "); +} + +let buildNameFun: (fname: string, ...rest: string[]) => string = buildName; +``` + +### ~button /js/types +NEXT: Types +### ~ \ No newline at end of file diff --git a/docs/js/inference.md b/docs/js/inference.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/js/lang.md b/docs/js/lang.md index eea36563..a053c256 100644 --- a/docs/js/lang.md +++ b/docs/js/lang.md @@ -22,54 +22,6 @@ basic.showString(greeter.greet()) This site is meant for teaching programming first, and JavaScript second. For this reason, we have stayed away from concepts that are specific to JavaScript (for example, prototype inheritance), and instead focused on ones common to most -modern programming languages (for example, loops, lexically scoped variables, -functions, classes, lambdas). - -We leverage TypeScript's [type inference](http://www.typescriptlang.org/docs/handbook/type-inference.html) so that +modern programming languages (lexically scoped variables, functions, classes). +We leverage TypeScript's [type inference](/js/inference) so that students need not specify types when clear from context. - -## Supported language features - -* top-level code in the file: "Hello world!" really is just `basic.showString("Hello world!")` -* [basic types](http://www.typescriptlang.org/docs/handbook/basic-types.html) -* [variable declarations](http://www.typescriptlang.org/docs/handbook/variable-declarations.html): `let`, `const`, and `var` -* [functions](http://www.typescriptlang.org/docs/handbook/functions.html) with lexical scoping and recursion - -### User-defined types and modules - -* [classes](http://www.typescriptlang.org/docs/handbook/classes.html) with fields, methods and constructors; `new` keyword -* [enums](http://www.typescriptlang.org/docs/handbook/enums.html) -* [namespaces](http://www.typescriptlang.org/docs/handbook/namespaces.html) (a form of modules) - -### Control-flow constructs - -* `if ... else if ... else` statements -* `while` and `do ... while` loops -* `for(;;)` loops (see below about `for ... in/of`) -* `break/continue`; also with labeled loops -* `switch` statement (on numbers only) -* `debugger` statement for breakpoints - -### Expressions - -* conditional operator `? :`; lazy boolean operators -* all arithmetic operators (including bitwise operators); note that in microcontroller targets - all arithmetic is performed on integers, also when simulating in the browser -* strings (with a few common methods) -* [string templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (`` `x is ${x}` ``) -* arrow functions `() => ...` -* array literals `[1, 2, 3]` - - -## Unsupported language features - -We generally stay away from the more dynamic parts of JavaScript. -Things you may miss and we may implement: - -* exceptions (`throw`, `try ... catch`, `try ... finally`) -* `for ... of` statements -* object literals `{ foo: 1, bar: "two" }` -* method-like properties (get/set accessors) -* class inheritance - -If there is something you'd like to see, please file an issue at [GitHub](http://github.com/microsoft/pxt/issues). \ No newline at end of file diff --git a/docs/js/operators.md b/docs/js/operators.md new file mode 100644 index 00000000..24851c6a --- /dev/null +++ b/docs/js/operators.md @@ -0,0 +1,27 @@ +## Operators + +The following JavaScript operators are supported for the micro:bit. +Note that for the micro:bit all arithmetic is performed on integers, rather than floating point. +This also is true when simulating in the browser. + +# Assignment, arithmetic and bitwise + +* assignment operators - [read more](http://devdocs.io/javascript/operators/assignment_operators) +* arithmetic operators - [read more](http://devdocs.io/javascript/operators/arithmetic_operators) +* bitwise operators - [read more](http://devdocs.io/javascript/operators/bitwise_operators) + +# Comparision and conditional + +* comparison operators - [read more](http://devdocs.io/javascript/operators/comparison_operators) +* conditional operator - [read more](http://devdocs.io/javascript/operators/conditional_operator) + +## More + +* lambda functions `() => { ... }` +* array literals `[1, 2, 3]` +* strings, with a few common methods +* [string templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (`` `x is ${x}` ``) + +### ~button /js/controlflow +NEXT: Control Flow +### ~ \ No newline at end of file diff --git a/docs/js/sequence.md b/docs/js/sequence.md index e8a77af6..b9c7613d 100644 --- a/docs/js/sequence.md +++ b/docs/js/sequence.md @@ -1,6 +1,6 @@ -# Sequencing commands +# Sequencing -By calling one function after another, you can create an animation: +By calling one function after another, in sequence, you can create an animation: ```typescript basic.showLeds(` @@ -9,17 +9,47 @@ basic.showLeds(` . . # . . # . . . # . # # # . - `) + `); basic.showLeds(` . # . # . . . . . . . . . . . . # # # . # . . . # - `) + `); ``` -## The Semicolon +### The semicolon -Coming soon... +In JavaScript, the semicolon (;) is used to terminate (or end) a statement. However, in most +cases, the semicolon is optional and can be omitted. So both code sequences below are +legal: +```typescript +basic.showNumber(1) basic.showNumber(2) +``` + +```typescript +basic.showNumber(1); basic.showNumber(2); +``` + +## The empty statement + +In JavaScript, there is the concept of an *empty statement*, which is whitespace followed by +a semicolon in the context where a statement is expected. +So, the following code is an infinite loop +followed by a call to `showNumber` that will never execute: +```typescript +while(true) ; basic.showNumber(1); +``` +For the micro:bit, we don't allow a program to contain an empty statement, such as shown above. +If you really want an empty statement, you need to use curly braces to delimit an empty statement block: +```typescript +while(true) { } basic.showNumber(1); +``` + +[Read more](http://inimino.org/~inimino/blog/javascript_semicolons) about semicolons in JavaScript. + +### ~button /js/variables +NEXT: Variable Declarations +### ~ \ No newline at end of file diff --git a/docs/js/statements.md b/docs/js/statements.md new file mode 100644 index 00000000..ab9f0332 --- /dev/null +++ b/docs/js/statements.md @@ -0,0 +1,33 @@ +# Statements + +The following JavaScript statements are supported for the micro:bit: + +## Variable declarations +* `const` statement - [read more](http://devdocs.io/javascript/statements/const) +* `let` statement - [read more](http://devdocs.io/javascript/statements/let) +* `var` statement - [read more](http://devdocs.io/javascript/statements/var) + +## Block-structured statements + +* `{ }` block statement - [read more](http://devdocs.io/javascript/statements/block) +* `if-else` conditional statement - [read more](http://devdocs.io/javascript/statements/if...else) +* `while` loop - [read more](http://devdocs.io/javascript/statements/do...while) +* `do-while` loop - [read more](http://devdocs.io/javascript/statements/do...while) +* `for(;;)` loop - [read more](http://devdocs.io/javascript/statements/for) +* `switch` statement (on numbers only) - [read more](http://devdocs.io/javascript/statements/switch) + +## Control-flow commands + +* `break` statement - [read more](http://devdocs.io/javascript/statements/break) +* `continue` statement - [read more](http://devdocs.io/javascript/statements/continue) +* `return` statement - [read more](http://devdocs.io/javascript/statements/return) +* `debugger` statement for breakpoints - [read more](http://devdocs.io/javascript/statements/debugger) + +## Labelling statements + +* labelled statement - [read more](http://devdocs.io/javascript/statements/label) +* `default` statement - [read more](http://devdocs.io/javascript/statements/default) + +### ~button /js/functions +NEXT: Functions +### ~ diff --git a/docs/js/types.md b/docs/js/types.md new file mode 100644 index 00000000..597a19e9 --- /dev/null +++ b/docs/js/types.md @@ -0,0 +1,140 @@ +# Types + +For programs to be useful, we need to be able to work with some of the simplest units of data: +numbers, strings, structures, boolean values, and the like. + +# Boolean + +The most basic datatype is the simple true/false value, which is called a `boolean` value. + +```ts +let isDone: boolean = false; +``` + +# Number + +### ~ hint +In JavaScript, `numbers` are floating point values. +However, for the micro:bit, `numbers` are integer values. +### ~ + +Integer values can be specified via decimal, hexadecimal and octal notation: + +```ts +let decimal: number = 42; +let hex: number = 0xf00d; +let binary: number = 0b1010; +let octal: number = 0o744; +``` + +# String + +As in other languages, we use the type `string` to refer to textual data. +Use double quotes (`"`) or single quotes (`'`) to surround string data. + +```ts +let color: string = "blue"; +color = 'red'; +``` + +You can also use *template strings*, which can span multiple lines and have embedded expressions. +These strings are surrounded by the backtick/backquote (`` ` ``) character, and embedded expressions are of the form `${ expr }`. + +```ts +let fullName: string = `Bob Bobbington`; +let age: number = 37; +let sentence: string = `Hello, my name is ${ fullName }. + +I'll be ${ age + 1 } years old next month.` +``` + +This is equivalent to declaring `sentence` like so: + +```ts +let sentence: string = "Hello, my name is " + fullName + ".\n\n" + + "I'll be " + (age + 1) + " years old next month." +``` + +# Array + +Arrays allow you to work with an expandable sequence of values, addressed by an integer-valued index. +Array types can be written in one of two ways. +In the first, you use the type of the elements followed by `[]` to denote an array of that element type: + +```ts +let list: number[] = [1, 2, 3]; +``` + +The second way uses a generic array type, `Array`: + +```ts +let list: Array = [1, 2, 3]; +``` + +### ~hint +For the micro:bit, all elements of an array must have the same type. +### ~ + + +# Enum + +A helpful addition to the standard set of datatypes from JavaScript is the `enum`. +As in languages like C#, an enum is a way of giving more friendly names to sets of numeric values. + +```ts +enum Color {Red, Green, Blue}; +let c: Color = Color.Green; +``` + +By default, enums begin numbering their members starting at `0`. +You can change this by manually setting the value of one of its members. +For example, we can start the previous example at `1` instead of `0`: + +```ts +enum Color {Red = 1, Green, Blue}; +let c: Color = Color.Green; +``` + +Or, even manually set all the values in the enum: + +```ts +enum Color {Red = 1, Green = 2, Blue = 4}; +let c: Color = Color.Green; +``` + +# Any + +The TypeScript type `any` is not supported in the micro:bit. + + +# Void + +`void` is the absence of having any type at all. +You may commonly see this as the return type of functions that do not return a value: + +```ts +function warnUser(): void { + basic.showString("This is my warning message"); +} +``` + +Declaring variables of type `void` is not useful. + +# Type Inference + +In TypeScript, there are several places where type inference is used to provide type information when there is +no explicit type annotation. For example, in this code + +```ts +let x = 3; +let y = x + 3 +``` + +The type of the `x` variable is inferred to be `number`. Similarly, the type of `y` variable also is inferred to be `number`. +This kind of inference takes place when initializing variables and members, +setting parameter default values, and determining function return types. + + +### ~button /js/classes +NEXT: Classes +### ~ \ No newline at end of file diff --git a/docs/js/variables.md b/docs/js/variables.md new file mode 100644 index 00000000..3dc7c231 --- /dev/null +++ b/docs/js/variables.md @@ -0,0 +1,121 @@ +# Variable Declarations + +Declaring a variable in JavaScript has always traditionally been done with the `var` keyword. + +```typescript +var a = 10; +``` + +The `var` construct has some [problems](http://www.typescriptlang.org/docs/handbook/variable-declarations.html), +which is why `let` statements were introduced. Apart from the keyword used, `let` statements are written +the same way `var` statements are. + +```typescript +let a = 10; +``` + +The key difference is not in the syntax, but in the semantics, which we'll now dive into. + +## Block-scoping + +When a variable is declared using `let`, it uses what some call *lexical-scoping* or *block-scoping*. +Unlike variables declared with `var` whose scopes leak out to their containing function, +block-scoped variables are not visible outside of their nearest containing block or `for`-loop. + +```typescript +function f(input: boolean) { + let a = 100; + + if (input) { + // Still okay to reference 'a' + let b = a + 1; + return b; + } + + // Error: 'b' doesn't exist here + return b; +} +``` + +Here, we have two local variables `a` and `b`. +`a`'s scope is limited to the body of `f` while `b`'s scope is limited to the containing `if` statement's block. + +Another property of block-scoped variables is that they can't be read or written to before they're actually declared. +While these variables are "present" throughout their scope, all points up until their declaration are part of their *temporal dead zone*. +This is just a sophisticated way of saying you can't access them before the `let` statement, and luckily TypeScript will let you know that. + +```typescript +a++; // illegal to use 'a' before it's declared; +let a; +``` + +## Re-declarations + +With `var` declarations, it doesn't matter how many times you declare your variables, you just get one: + +```typescript +var x = 10; +var x = 20; +``` + +In the above example, all declarations of `x` actually refer to the *same* `x`, and this is perfectly valid. +This often ends up being a source of bugs. Thankfully, `let` declarations are not as forgiving. + +```typescript +let x = 10; +let x = 20; // error: can't re-declare 'x' in the same scope +``` + +## Shadowing + +The act of introducing a new name in a more deeply nested scope is called *shadowing*. +It is a bit of a double-edged sword in that it can introduce certain bugs on its own in the +event of accidental shadowing, while also preventing certain bugs. +For instance, imagine a `sumMatrix` function using `let` variables. + +```typescript +function sumMatrix(matrix: number[][]) { + let sum = 0; + for (let i = 0; i < matrix.length; i++) { + var currentRow = matrix[i]; + for (let i = 0; i < currentRow.length; i++) { + sum += currentRow[i]; + } + } + + return sum; +} +``` + +This version of the loop will actually perform the summation correctly because the inner loop's `i` shadows `i` from the outer loop. +Shadowing should *usually* be avoided in the interest of write clearer code, such as + +```typescript +function sumMatrix(matrix: number[][]) { + let sum = 0; + for (let i = 0; i < matrix.length; i++) { + var currentRow = matrix[i]; + for (let j = 0; j < currentRow.length; j++) { + sum += currentRow[j]; + } + } + + return sum; +} +``` +While there are some scenarios where it may be fitting to take advantage of it, you should use your best judgement. + +# `const` declarations + +`const` declarations are another way of declaring variables. + +```typescript +const numLivesForCat = 9; +``` + +They are like `let` declarations but, as their name implies, their value cannot be changed once they are bound. +In other words, they have the same scoping rules as `let`, but you can't re-assign to them. + +### ~button /js/expressions +NEXT: Expressions +### ~ \ No newline at end of file diff --git a/docs/projects.md b/docs/projects.md index b41155ed..31c427eb 100644 --- a/docs/projects.md +++ b/docs/projects.md @@ -14,7 +14,7 @@ Here are some cool projects that you can build with your micro:bit! "imageUrl": "/static/mb/projects/a2-buttons.png" },{ "name": "Love Meter", - "url":"/projects/lover-meter", + "url":"/projects/love-meter", "imageUrl":"/static/mb/projects/a3-pins.png" },{ "name": "Rock Paper Scissors", diff --git a/docs/reference/control/device-name.md b/docs/reference/control/device-name.md index 5c210b4d..566b0e07 100644 --- a/docs/reference/control/device-name.md +++ b/docs/reference/control/device-name.md @@ -1,32 +1,11 @@ -# Do Something +# Device Name -Do something. +Gets a friendly name for the device derived from the its serial number. ```sig - +control.deviceName(); ``` -### Parameters - -* ``a``: -* ``b``: -* ``c``: - -### Returns - - - -### Example - -The following example / This program does something. - -```blocks - -``` - -### See also - -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas) +**This is an advanced API.** For more information, see the +[micro:bit runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/). diff --git a/docs/reference/control/device-serial-number.md b/docs/reference/control/device-serial-number.md index 5c210b4d..abb4dd20 100644 --- a/docs/reference/control/device-serial-number.md +++ b/docs/reference/control/device-serial-number.md @@ -1,32 +1,10 @@ -# Do Something +# Device Serial Number -Do something. +Derive a unique, consistent serial number of this device from internal data. ```sig - +control.deviceSerialNumber(); ``` -### Parameters - -* ``a``: -* ``b``: -* ``c``: - -### Returns - - - -### Example - -The following example / This program does something. - -```blocks - -``` - -### See also - -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas) - +**This is an advanced API.** For more information, see the +[micro:bit runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/). diff --git a/docs/reference/control/event-source-id.md b/docs/reference/control/event-source-id.md index 5c210b4d..af44ba9d 100644 --- a/docs/reference/control/event-source-id.md +++ b/docs/reference/control/event-source-id.md @@ -1,32 +1,10 @@ -# Do Something +# Event Source ID -Do something. +Return a code representing the origin of the event on the bus (button, pin, radio, and so on). ```sig - +control.eventSourceId(EventBusSource.MICROBIT_ID_BUTTON_A); ``` -### Parameters - -* ``a``: -* ``b``: -* ``c``: - -### Returns - - - -### Example - -The following example / This program does something. - -```blocks - -``` - -### See also - -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas) - +**This is an advanced API.** For more information, see the +[micro:bit runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/) diff --git a/docs/reference/control/event-timestamp.md b/docs/reference/control/event-timestamp.md index 5c210b4d..5129b9ad 100644 --- a/docs/reference/control/event-timestamp.md +++ b/docs/reference/control/event-timestamp.md @@ -1,32 +1,10 @@ -# Do Something +# Event Timestamp -Do something. +Get the timestamp of the last event executed on the bus ```sig - +control.eventTimestamp(); ``` -### Parameters - -* ``a``: -* ``b``: -* ``c``: - -### Returns - - - -### Example - -The following example / This program does something. - -```blocks - -``` - -### See also - -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas) - +**This is an advanced API.** For more information, see the +[micro:bit runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/). diff --git a/docs/reference/control/event-value-id.md b/docs/reference/control/event-value-id.md index 5c210b4d..8153a7f0 100644 --- a/docs/reference/control/event-value-id.md +++ b/docs/reference/control/event-value-id.md @@ -1,32 +1,12 @@ -# Do Something +# Event Value ID -Do something. +Return a code representing the type of the event (button click, device gesture, and so on). ```sig - +control.eventValueId(EventBusValue.MICROBIT_EVT_ANY); ``` -### Parameters -* ``a``: -* ``b``: -* ``c``: - -### Returns - - - -### Example - -The following example / This program does something. - -```blocks - -``` - -### See also - -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas) +**This is an advanced API.** For more information, see the +[micro:bit runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/). diff --git a/docs/reference/control/event-value.md b/docs/reference/control/event-value.md index 5c210b4d..46b60081 100644 --- a/docs/reference/control/event-value.md +++ b/docs/reference/control/event-value.md @@ -1,32 +1,12 @@ -# Do Something +# Event Value -Do something. +Get the value of the last event executed on the bus. ```sig - +control.eventValue(); ``` -### Parameters -* ``a``: -* ``b``: -* ``c``: - -### Returns - - - -### Example - -The following example / This program does something. - -```blocks - -``` - -### See also - -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas) +**This is an advanced API.** For more information, see the +[micro:bit runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/). diff --git a/docs/reference/control/on-event.md b/docs/reference/control/on-event.md index 5c210b4d..a95dd5d8 100644 --- a/docs/reference/control/on-event.md +++ b/docs/reference/control/on-event.md @@ -1,32 +1,11 @@ -# Do Something +# On Event -Do something. +Raise an event in the event bus. ```sig - +control.onEvent(control.eventSourceId(EventBusSource.MICROBIT_ID_BUTTON_A), control.eventValueId(EventBusValue.MICROBIT_EVT_ANY), () => { }); ``` -### Parameters - -* ``a``: -* ``b``: -* ``c``: - -### Returns - - - -### Example - -The following example / This program does something. - -```blocks - -``` - -### See also - -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas) +**This is an advanced API.** For more information, see the +[micro:bit runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/). diff --git a/docs/reference/control/raise-event.md b/docs/reference/control/raise-event.md index 5c210b4d..f9a8a50c 100644 --- a/docs/reference/control/raise-event.md +++ b/docs/reference/control/raise-event.md @@ -1,32 +1,10 @@ -# Do Something +# Raise Event -Do something. +Raise an event in the event bus. ```sig - +control.raiseEvent(control.eventSourceId(EventBusSource.MICROBIT_ID_BUTTON_A), control.eventValueId(EventBusValue.MICROBIT_EVT_ANY)); ``` -### Parameters - -* ``a``: -* ``b``: -* ``c``: - -### Returns - - - -### Example - -The following example / This program does something. - -```blocks - -``` - -### See also - -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas), -[bar bas](/reference/foo/bar-bas) - +**This is an advanced API.** For more information, see the +[micro:bit runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/) diff --git a/docs/reference/game/misc.txt b/docs/reference/game/misc.txt deleted file mode 100644 index e32154ef..00000000 --- a/docs/reference/game/misc.txt +++ /dev/null @@ -1,54 +0,0 @@ - -### Score - -When a player achieves a goal, you can increase the game score - -* add score points to the current score - -``` -export function addScore(points: number) -``` - -* get the current score value - -``` -export function score() : number -``` - - -### Score - -When a player achieves a goal, you can increase the game score - -* add score points to the current score - -``` -export function addScore(points: number) -``` - -* set the current score to a particular value. - -``` -export function setScore(value: number) -``` - -* get the current score value - -``` -export function score() : number - - - -``` - -### Countdown - -If your game has a time limit, you can start a countdown in which case `game->current time` returns the remaining time. - -* start a countdown with the maximum duration of the game in milliseconds. - -``` -export function startCountdown(ms: number) -``` - - diff --git a/docs/reference/pins/analog-pitch.md b/docs/reference/pins/analog-pitch.md index b229875c..d42308b9 100644 --- a/docs/reference/pins/analog-pitch.md +++ b/docs/reference/pins/analog-pitch.md @@ -1,6 +1,6 @@ # Analog Pitch -Emits a Pulse With Modulation (PWM) signal to the current pitch [pin](/device/pins). Use [analog set pitch pin](/reference/pins/analog-set-pitch-pin) to set the pitch pin. +Emits a Pulse With Modulation (PWM) signal to the current pitch [pin](/device/pins). Use [analog set pitch pin](/reference/pins/analog-set-pitch-pin) to set the current pitch pin. ```sig pins.analogPitch(440, 300) diff --git a/docs/reference/pins/analog-read-pin.md b/docs/reference/pins/analog-read-pin.md index c9b87526..35ded767 100644 --- a/docs/reference/pins/analog-read-pin.md +++ b/docs/reference/pins/analog-read-pin.md @@ -28,9 +28,7 @@ basic.forever(() => { #### ~hint -If you are using **analog read pin** with another micro:bit -running **analog write pin**, it is a good idea to check -**analog read pin** many times and then take an average. +If you are using **analog read pin** with another micro:bit running **analog write pin**, then things can get tricky. Remember that the micro:bit that runs **analog set pin** writes 0's and 1's at a very high frequency to achieve an average of the desired value. Sadly, if you try to read that average from another micro:bit, then the micro:bit will either read 0 or 1023. You could try to read a higher number of values (e.g. a million) in a loop, then computer then average. Alternatively, you can plug in a capacitor in-between the two micro:bits. #### ~ diff --git a/libs/microbit-radio/radio.cpp b/libs/microbit-radio/radio.cpp index e41d6d9c..a93a047a 100644 --- a/libs/microbit-radio/radio.cpp +++ b/libs/microbit-radio/radio.cpp @@ -69,7 +69,7 @@ namespace radio { uint32_t sn = transmitSerialNumber ? microbit_serial_number() : 0; uint8_t buf[32]; uint32_t* buf32 = (uint32_t*)buf; - memset(buf, 32, 0); + memset(buf, 0, 32); buf32[0] = value; // 4 bytes: value buf32[1] = t; // 4 bytes: running time buf32[2] = sn; // 4 bytes: serial number diff --git a/libs/microbit/input.cpp b/libs/microbit/input.cpp index efdbc312..c5f54569 100644 --- a/libs/microbit/input.cpp +++ b/libs/microbit/input.cpp @@ -284,7 +284,7 @@ namespace input { * Sets the accelerometer sample range in gravities. * @param range a value describe the maximum strengh of acceleration measured */ - //% help=input/set-accelerator-range + //% help=input/set-accelerometer-range //% blockId=device_set_accelerometer_range block="set accelerometer|range %range" icon="\uf135" //% weight=5 void setAccelerometerRange(AcceleratorRange range) { diff --git a/libs/microbit/pins.cpp b/libs/microbit/pins.cpp index 0589aa7c..a9614e28 100644 --- a/libs/microbit/pins.cpp +++ b/libs/microbit/pins.cpp @@ -159,7 +159,7 @@ namespace pins { /** * Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler. */ - //% help=pins/pulse-micros + //% help=pins/pulse-duration //% blockId=pins_pulse_duration block="pulse duration (µs)" //% weight=21 int pulseDuration() { @@ -229,7 +229,7 @@ namespace pins { * @param name pin to set the pull mode on * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone */ - //% help=pins/digital-set-pull weight=3 + //% help=pins/set-pull weight=3 //% blockId=device_set_pull block="set pull|pin %pin|to %pull" void setPull(DigitalPin name, PinPullMode pull) { PinMode m = pull == PinPullMode::PullDown diff --git a/libs/microbit/pxt.json b/libs/microbit/pxt.json index d45a0a08..7fa62df8 100644 --- a/libs/microbit/pxt.json +++ b/libs/microbit/pxt.json @@ -26,12 +26,7 @@ "pins.ts", "serial.cpp", "serial.ts", - "buffer.cpp", - "_locales/ar/microbit-strings.json", - "_locales/de/microbit-strings.json", - "_locales/es-ES/microbit-strings.json", - "_locales/fr/microbit-strings.json", - "_locales/ja/microbit-strings.json" + "buffer.cpp" ], "public": true, "dependencies": {}, diff --git a/libs/microbit/serial.cpp b/libs/microbit/serial.cpp index e08e0b99..47f9dda0 100644 --- a/libs/microbit/serial.cpp +++ b/libs/microbit/serial.cpp @@ -61,11 +61,11 @@ namespace serial { * @param baud the new baud rate. eg: 115200 */ //% weight=10 - //% help=serial/redirect + //% help=serial/redirect-to //% blockId=serial_redirect block="serial redirect to|TX %tx|RX %rx|at baud rate %rate" //% blockExternalInputs=1 void redirect(SerialPin tx, SerialPin rx, BaudRate rate) { uBit.serial.redirect((PinName)tx, (PinName)rx); uBit.serial.baud((int)rate); } -} \ No newline at end of file +} diff --git a/libs/microbit/shims.d.ts b/libs/microbit/shims.d.ts index 87ca31d1..c600e641 100644 --- a/libs/microbit/shims.d.ts +++ b/libs/microbit/shims.d.ts @@ -301,7 +301,7 @@ declare namespace input { * Sets the accelerometer sample range in gravities. * @param range a value describe the maximum strengh of acceleration measured */ - //% help=input/set-accelerator-range + //% help=input/set-accelerometer-range //% blockId=device_set_accelerometer_range block="set accelerometer|range %range" icon="\uf135" //% weight=5 shim=input::setAccelerometerRange function setAccelerometerRange(range: AcceleratorRange): void; @@ -497,7 +497,7 @@ declare namespace pins { /** * Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler. */ - //% help=pins/pulse-micros + //% help=pins/pulse-duration //% blockId=pins_pulse_duration block="pulse duration (µs)" //% weight=21 shim=pins::pulseDuration function pulseDuration(): number; @@ -540,7 +540,7 @@ declare namespace pins { * @param name pin to set the pull mode on * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone */ - //% help=pins/digital-set-pull weight=3 + //% help=pins/set-pull weight=3 //% blockId=device_set_pull block="set pull|pin %pin|to %pull" shim=pins::setPull function setPull(name: DigitalPin, pull: PinPullMode): void; @@ -592,7 +592,7 @@ declare namespace serial { * @param baud the new baud rate. eg: 115200 */ //% weight=10 - //% help=serial/redirect + //% help=serial/redirect-to //% blockId=serial_redirect block="serial redirect to|TX %tx|RX %rx|at baud rate %rate" //% blockExternalInputs=1 shim=serial::redirect function redirect(tx: SerialPin, rx: SerialPin, rate: BaudRate): void; diff --git a/testconv.json b/testconv.json deleted file mode 100644 index c80cba75..00000000 --- a/testconv.json +++ /dev/null @@ -1,670 +0,0 @@ -{ - "apiUrl": "https://www.microbit.co.uk/api/", - "fakeids": [ - "zzltaj", - "zzpgxf", - "rhisri", - "zztzyk" - ], - "ids": [ - "balcxr", - "bambkh", - "bbfxnw", - "bbtlly", - "bbvscl", - "bbxapr", - "bcbxtu", - "bchtnm", - "bcpnpx", - "bcredt", - "bdbwuy", - "bdddfl", - "bedihg", - "behvrp", - "bevhll", - "bezbat", - "bfrafy", - "bfvuez", - "bgqdmi", - "bguxyx", - "bhbzvc", - "bhhzvr", - "bhollk", - "biczhe", - "bieoqj", - "biwfto", - "bjayrk", - "bjcbpf", - "bjcdte", - "bjomis", - "bjqlzz", - "bkaofs", - "bkbsfh", - "bkxbji", - "blbhmr", - "blkuau", - "bllhdc", - "blougi", - "blpvxv", - "bmevma", - "bmlwtk", - "bmmayl", - "bncsjd", - "bnlfif", - "bnsfch", - "bnucdu", - "bolvvm", - "bouhxx", - "bpbvyx", - "bpmeio", - "bpqvtv", - "bptlwr", - "bqceny", - "bqgsnm", - "bqkwia", - "bqvoqy", - "bqyoyn", - "brlcdr", - "bsmmsp", - "bsncre", - "bstaqt", - "butypx", - "buuzga", - "bvnciu", - "bwbuga", - "bwhttb", - "bwkezu", - "bxswvm", - "bynkeb", - "bypanj", - "bywqzx", - "byzegt", - "bzaaya", - "bzrusu", - "bzwbps", - "dalzjm", - "damymx", - "dbdpxx", - "dcapfd", - "dceikq", - "ddikkz", - "ddjpss", - "ddtadz", - "ddxbjj", - "dfkuyn", - "dfmpxf", - "dfypdn", - "dhabye", - "dhbioa", - "dieoiu", - "diuhli", - "djchkz", - "djohvc", - "djztxc", - "dkqbyq", - "dkvxwr", - "dmbcwi", - "dmekmj", - "dmghho", - "dnmrlu", - "dnnzgd", - "dooboj", - "dosuna", - "dqgnhz", - "dqqfgv", - "dqwrsw", - "drmbxg", - "drrrty", - "dscjnc", - "dsvguv", - "dtemsf", - "dtmmmc", - "dundpx", - "dushve", - "duupgd", - "dvgzyq", - "dvnoer", - "dwcxtn", - "dwtoyp", - "dxdfbw", - "dxqdqw", - "dxroxs", - "dxvgvs", - "dycuzj", - "dyhnkt", - "dyxejk", - "dzlocb", - "dzlogl", - "fadekj", - "faffgr", - "fapznm", - "fbgdog", - "fbpnng", - "fbyrog", - "fcfoox", - "fcicvk", - "fcjlto", - "fcvwvj", - "fdjhpo", - "fdtayy", - "fdyxvx", - "fegzbd", - "felusd", - "fethzd", - "ffcqby", - "ffjeei", - "ffjuuz", - "fflxnx", - "ffpyfa", - "fhcyyx", - "fhoonu", - "fitucj", - "fitvxu", - "fjdnmb", - "fjhnpw", - "fjlzrt", - "fjwknw", - "fkgprd", - "fklpld", - "fllghh", - "flqpgb", - "fmdsdi", - "fmdzgg", - "fnimjx", - "fnjmfx", - "fnscgh", - "fomwmz", - "fpelnl", - "fpngwv", - "fpqusd", - "fpuclv", - "fpvrwv", - "fqmgsu", - "fqsbhp", - "fqsrdu", - "frlxvd", - "froxsb", - "frqqnm", - "ftcrip", - "ftrzta", - "fubsaf", - "fvgogo", - "fvgxfz", - "fvkluo", - "fvsfrv", - "fwkjkj", - "fxxsgy", - "fyazlp", - "fypaix", - "fzcoly", - "fzidej", - "hatpaz", - "haxiza", - "hbfvlb", - "hbklfv", - "hbwlkf", - "hcmpdm", - "hdnlmx", - "hetmho", - "hfklxz", - "hfkvpg", - "hfmkbt", - "hftxjx", - "hfunev", - "hgepqq", - "hivbxk", - "hjesfm", - "hklazc", - "hkncxl", - "hkrfni", - "hlenxc", - "hlhipg", - "hlhvoe", - "hlwdwo", - "hnljdp", - "howggk", - "hpjppy", - "hptebp", - "hpupwc", - "hqdpet", - "hqhclr", - "hqheal", - "hqoqjh", - "hqpuxt", - "hrnitd", - "hrooif", - "hsuiag", - "hsxmox", - "humerf", - "huqcpc", - "huydje", - "hwetsq", - "hxuwlt", - "hzcxdp", - "hzpfge", - "hzpkma", - "jaeeve", - "jcmkmq", - "jcojot", - "jcvdvp", - "jdcils", - "jddumo", - "jdsqxr", - "jerwei", - "jfwcov", - "jgdknu", - "jgjijp", - "jgofmw", - "jhjauh", - "jhrjvj", - "jhseak", - "jiyhsk", - "jiyoeq", - "jjumac", - "jkppnc", - "jkxyeh", - "jkymhg", - "jlatje", - "jlbxjm", - "jlmzps", - "jmmgyn", - "jmshop", - "jnengo", - "jnhcat", - "jnvrkr", - "jnxdok", - "jociyw", - "joryiq", - "jpbfze", - "jpcrcj", - "jrfuqz", - "jrfwyh", - "jrpbtk", - "jrwkyz", - "jrxhxe", - "jsxvju", - "jszrpp", - "jtbdng", - "jtglrx", - "jtodxy", - "julzbh", - "juqrkb", - "jvstzh", - "jwckaz", - "jwplaw", - "jwskcb", - "jxgcel", - "jxjryw", - "jxmrht", - "jxqobc", - "jzenhj", - "jzwxbr", - "jzzbqg", - "laanun", - "lagxjo", - "lamnpb", - "lapexp", - "lazmuu", - "lbeyfh", - "lbhuwc", - "lcdeuk", - "lchqfb", - "lcpmnp", - "ldgoae", - "lecrpo", - "lfpidi", - "lfrpst", - "lgsrwm", - "lhjcvy", - "licgsp", - "likrcp", - "ljauxo", - "ljkskx", - "llsepx", - "llxcdk", - "lmvoxp", - "lniybn", - "loafab", - "loehfe", - "lpnzct", - "lqwdio", - "lqxnnj", - "lracic", - "lrwotp", - "lryglt", - "lsikdy", - "ltchng", - "ltsbpa", - "lucaof", - "lvahkk", - "lvvdne", - "lwtsxc", - "lxleej", - "lxwstg", - "lxwwtd", - "lzndlk", - "lzosmg", - "lzsseg", - "naevvc", - "nawmtp", - "nbomql", - "nbuuii", - "nbwine", - "ndayhb", - "ndikwg", - "ndlikc", - "ndljim", - "ndooqj", - "ndqgow", - "nfjrxg", - "nfmunh", - "nghraa", - "nhpyof", - "nhtyzy", - "nikzhg", - "nitcfc", - "njfeff", - "njvcbs", - "njynsd", - "nkdbmy", - "nlyuwy", - "nmbxkh", - "nmdfik", - "nmuhlk", - "noftar", - "noikvz", - "novevx", - "noxyjg", - "noyovd", - "npkjbk", - "nqdtvd", - "nqgyno", - "nqxloa", - "nrjdzu", - "nsaumh", - "nsegbi", - "ntfmsx", - "ntsvek", - "nujrlc", - "nvogiv", - "nvrqzl", - "nvtfbc", - "nvymrn", - "nwowql", - "nwxlij", - "nxhnvy", - "nxpwae", - "nynwto", - "nytwlb", - "nyuakq", - "nzrgyf", - "nzrwza", - "nzzcea", - "pbsolq", - "pbtnpf", - "pcdvqu", - "pchzqo", - "pdmxpl", - "pdnntw", - "pdsghq", - "pewcsa", - "pflxxj", - "pfutwa", - "pgvoic", - "phehbm", - "phgmqm", - "phhkfi", - "phjonu", - "phvurr", - "piaksu", - "pijsrg", - "piubiw", - "pjsmac", - "pjxdoj", - "pjzfgn", - "pkmwkn", - "pkntkb", - "pkquey", - "pmxlhz", - "pnvgvr", - "pooqwk", - "ppslyh", - "ppxsux", - "prglvf", - "probjd", - "psmgrz", - "psptyd", - "psqjon", - "pughxs", - "puhetz", - "pujfoc", - "purkko", - "puthiz", - "pvjilh", - "pvqrgm", - "pvzmhz", - "pxebwk", - "pxizap", - "pxyovu", - "pymfqh", - "pzmjbx", - "pzucty", - "rannhh", - "rbnvdq", - "rccfvy", - "rceosh", - "rcobok", - "rdamey", - "rdhndz", - "rdpdll", - "rdzfjv", - "redkby", - "reqjzm", - "revjgd", - "rfihyn", - "rfzukz", - "rgtmoz", - "rheeoa", - "rheyiw", - "rilbti", - "rilexn", - "riotng", - "riqiss", - "riupfo", - "rjglqu", - "rjthvx", - "rjvjwq", - "rlporb", - "rmazpa", - "rmyvbb", - "rnkxav", - "rnvzdo", - "ropkaf", - "rozudg", - "rrvdls", - "rsdjun", - "rudelg", - "rugwft", - "rupbjr", - "rvjwiu", - "rvqkwq", - "rwdqcz", - "rwjnfq", - "rxdqqf", - "rxnztr", - "rxugmm", - "rydpvf", - "ryftuq", - "rygikf", - "ryvkkx", - "rzmnrf", - "tbehov", - "tcaulx", - "tcrfuz", - "tcvaou", - "tdfxfg", - "tdkwue", - "tfrbqz", - "tgbxuq", - "tglsyl", - "tgorrv", - "theruf", - "thhvzq", - "thncnj", - "tiircu", - "tjdpzj", - "tjliry", - "tjpwmu", - "tjqgba", - "tkhgfo", - "tkxbfr", - "tmkbao", - "tmnhhx", - "tnripk", - "tnudiw", - "tnuuwe", - "tnvnko", - "toqcgf", - "tpdiyw", - "tqeddl", - "tqhpqp", - "tqwach", - "trkitt", - "trkrrh", - "tsdmft", - "ttvzqd", - "ttxeud", - "tujsjf", - "tvbjyi", - "tvkqoe", - "twrsnj", - "txkmpg", - "txouzs", - "txszvu", - "txwbbf", - "tzqydt", - "vaszak", - "vaymbt", - "vbcdot", - "vbtmwf", - "vcijrw", - "vcoevo", - "vcrvjm", - "vcudrv", - "vczceh", - "vfcwwr", - "vftxlg", - "vfusfw", - "vgovse", - "vgvkok", - "vgxdxq", - "vhhygu", - "vioniz", - "vipnog", - "vjkwgj", - "vjmnkh", - "vkhabg", - "vkhiga", - "vkybzm", - "vlrsar", - "vmhvfa", - "vndxor", - "vodekh", - "vopucc", - "vovivd", - "vpnspf", - "vpslsg", - "vreifv", - "vrikcc", - "vrxpod", - "vsbzms", - "vslnue", - "vsrguv", - "vsyfym", - "vtfund", - "vtviqj", - "vtzfzy", - "vuwzmu", - "vwkpiw", - "vwlohb", - "vwnjqy", - "vwtwos", - "vxjfnm", - "vyewot", - "vyhvrg", - "vzmvvw", - "vzniie", - "vzrycv", - "vztdyx", - "xascqb", - "xaurjv", - "xcenyy", - "xczuut", - "xdvawd", - "xdwebc", - "xdxlsd", - "xfdrwr", - "xfrysj", - "xfytns", - "xhgnmw", - "xhjkvj", - "xjngae", - "xjuzjz", - "xkrsfl", - "xlfmnd", - "xltsru", - "xmcivt", - "xmlisq", - "xmzztb", - "xndixq", - "xnhxka", - "xnurqq", - "xolqgf", - "xoojpa", - "xoulbi", - "xoygfg", - "xpekdp", - "xpiqbj", - "xrqriw", - "xrsohj", - "xrvzyi", - "xsvwgh", - "xtrrnu", - "xtsmne", - "xuxlra", - "xvjcdf", - "xvmxti", - "xvpkiq", - "xxuosa", - "xymixn", - "xzcsqr", - "xzlzgl", - "zaidka", - "zbiznd", - "zbqfmt", - "zdfkcr", - "zdntvf", - "zdwmwu", - "zehjio", - "zelzkd", - "zewaak", - "zgozuh", - "zifrtl", - "ziqeez", - "zldufm", - "zlfusn", - "zmrcwu", - "zoyilz", - "zqlcxg", - "zqotda", - "zswztj", - "zszuqa", - "zwkhxx", - "zwpewj", - "zytfqg", - "zywows", - "zzltaj", - "zzpgxf", - "zztzyk" - ] -} diff --git a/tests/base/main.ts b/tests/base/main.ts new file mode 100644 index 00000000..94cbb82d --- /dev/null +++ b/tests/base/main.ts @@ -0,0 +1 @@ +// empty - not testing anything here diff --git a/tests/base/pxt.json b/tests/base/pxt.json new file mode 100644 index 00000000..db9ff13a --- /dev/null +++ b/tests/base/pxt.json @@ -0,0 +1,13 @@ +{ + "name": "base-test", + "description": "Base package for tests", + "files": [ + "main.ts" + ], + "public": true, + "dependencies": { + "microbit": "*", + "microbit-radio": "*" + }, + "installedVersion": "file:." +} diff --git a/tests/hat-game.ts b/tests/hat-game.ts new file mode 100644 index 00000000..1f1b3e79 --- /dev/null +++ b/tests/hat-game.ts @@ -0,0 +1,232 @@ +let correctBall: number +let ballRevealing: boolean +let cupSelect: string +let index: number +let score: number +let level: number +let swapSpeed: number + +initializeGame() +input.onButtonPressed(Button.A, () => { + if (ballRevealing) { + index = index + 1 + if (index > 2) { + index = 0 + } + basic.showString(cupSelect[index], 150) + } +}) +input.onButtonPressed(Button.B, () => { + if (ballRevealing) { + ballRevealing = false + if (correctBall == index) { + score = score + level + images.createImage(` + . . . . . + . . . . # + . . . # . + # . # . . + . # . . . + `).showImage(0) + basic.pause(1000) + basic.showString("+".concat(level.toString()), 150) + basic.pause(1000) + } else { + images.createImage(` + # . . . # + . # . # . + . . # . . + . # . # . + # . . . # + `).showImage(0) + basic.pause(1000) + basic.clearScreen() + revealBall(correctBall) + basic.pause(1000) + } + } + level = level + 1 + if (level == 4) { + basic.showString("FINAL SCORE:", 75) + basic.showNumber(score, 150) + } else { + playLevel(level) + } +}) +playLevel(1) + +function revealBall(p: number) { + let xCoordinate = 2 * p + for (let j = 0; j < 3; j++) { + led.plot(j * 2, 2) + } + for (let i = 0; i < 3; i++) { + led.unplot(xCoordinate, 2) + led.plot(xCoordinate, 1) + basic.pause(100) + led.unplot(xCoordinate, 1) + led.plot(xCoordinate, 0) + basic.pause(200) + led.unplot(xCoordinate, 0) + led.plot(xCoordinate, 1) + basic.pause(100) + led.unplot(xCoordinate, 1) + led.plot(xCoordinate, 2) + basic.pause(75) + } + basic.pause(1000) +} + +function initializeGame() { + ballRevealing = false + level = 1 + score = 0 + cupSelect = "LMR" +} + +function swapCups(cup_1: number, cup_2: number, pauseDifficulty: number) { + let cup_1X = 2 * cup_1 + let cup_2X = 2 * cup_2 + let cupXAverage = (cup_1X + cup_2X) / 2 + led.unplot(cup_1X, 2) + led.unplot(cup_2X, 2) + led.plot(cup_1X, 3) + led.plot(cup_2X, 1) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 3) + led.unplot(cup_2X, 1) + led.plot(cup_1X, 4) + led.plot(cup_2X, 0) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 4) + led.unplot(cup_2X, 0) + if (cupXAverage == 2) { + led.plot((cupXAverage + cup_1X) / 2, 4) + led.plot((cupXAverage + cup_2X) / 2, 0) + basic.pause(pauseDifficulty) + led.unplot((cupXAverage + cup_1X) / 2, 4) + led.unplot((cupXAverage + cup_2X) / 2, 0) + } + led.plot(cupXAverage, 4) + led.plot(cupXAverage, 0) + basic.pause(pauseDifficulty) + led.unplot(cupXAverage, 4) + led.unplot(cupXAverage, 0) + if (cupXAverage == 2) { + led.plot((cupXAverage + cup_2X) / 2, 4) + led.plot((cupXAverage + cup_1X) / 2, 0) + basic.pause(pauseDifficulty) + led.unplot((cupXAverage + cup_2X) / 2, 4) + led.unplot((cupXAverage + cup_1X) / 2, 0) + } + led.plot(cup_2X, 4) + led.plot(cup_1X, 0) + basic.pause(pauseDifficulty) + led.unplot(cup_2X, 4) + led.unplot(cup_1X, 0) + led.plot(cup_2X, 3) + led.plot(cup_1X, 1) + basic.pause(pauseDifficulty) + led.unplot(cup_2X, 3) + led.unplot(cup_1X, 1) + led.plot(cup_2X, 2) + led.plot(cup_1X, 2) + basic.pause(pauseDifficulty) + if (correctBall == cup_1) { + correctBall = cup_2 + } else if (correctBall == cup_2) { + correctBall = cup_1 + } +} + +function swapFake(cup_1: number, cup_2: number, pauseDifficulty: number) { + let cup_1X = 2 * cup_1 + let cup_2X = 2 * cup_2 + let cupXAverage = (cup_1X + cup_2X) / 2 + led.unplot(cup_1X, 2) + led.unplot(cup_2X, 2) + led.plot(cup_1X, 3) + led.plot(cup_2X, 1) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 3) + led.unplot(cup_2X, 1) + led.plot(cup_1X, 4) + led.plot(cup_2X, 0) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 4) + led.unplot(cup_2X, 0) + if (cupXAverage == 2) { + led.plot((cupXAverage + cup_1X) / 2, 4) + led.plot((cupXAverage + cup_2X) / 2, 0) + basic.pause(pauseDifficulty) + led.unplot((cupXAverage + cup_1X) / 2, 4) + led.unplot((cupXAverage + cup_2X) / 2, 0) + } + led.plot(cupXAverage, 4) + led.plot(cupXAverage, 0) + basic.pause(pauseDifficulty) + led.unplot(cupXAverage, 4) + led.unplot(cupXAverage, 0) + if (cupXAverage == 2) { + led.plot((cupXAverage + cup_1X) / 2, 4) + led.plot((cupXAverage + cup_2X) / 2, 0) + basic.pause(pauseDifficulty) + led.unplot((cupXAverage + cup_1X) / 2, 4) + led.unplot((cupXAverage + cup_2X) / 2, 0) + } + led.plot(cup_1X, 4) + led.plot(cup_2X, 0) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 4) + led.unplot(cup_2X, 0) + led.plot(cup_1X, 3) + led.plot(cup_2X, 1) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 3) + led.unplot(cup_2X, 1) + led.plot(cup_1X, 2) + led.plot(cup_2X, 2) + basic.pause(pauseDifficulty) +} + +function playLevel(level1: number) { + basic.showNumber(level, 150) + basic.pause(3000) + basic.clearScreen() + for (let i = 0; i < 3; i++) { + led.plot(2 * i, 2) + } + basic.pause(1000) + correctBall = Math.random(3) + revealBall(correctBall) + basic.pause(1000) + let swaps = 5 + 10 * level1 + if (level1 == 1) { + swapSpeed = 80 + } else if (level1 == 2) { + swapSpeed = 40 + } else { + swapSpeed = 20 + } + for (let i1 = 0; i1 < swaps; i1++) { + let swapType = Math.random(3) + let not = Math.random(3) + if (swapType < 2) { + let swapOrientation = Math.random(2) + if (swapOrientation == 0) { + swapCups((not + 1) % 3, (not + 2) % 3, swapSpeed) + } else { + swapCups((not + 2) % 3, (not + 1) % 3, swapSpeed) + } + } else { + let swapOrientation1 = Math.random(2) + if (swapOrientation1 == 0) { + swapFake((not + 1) % 3, (not + 2) % 3, swapSpeed) + } else { + swapFake((not + 2) % 3, (not + 1) % 3, swapSpeed) + } + } + } + index = -1 + ballRevealing = true +} diff --git a/tests/hello.ts b/tests/hello.ts new file mode 100644 index 00000000..522e9d88 --- /dev/null +++ b/tests/hello.ts @@ -0,0 +1 @@ +basic.showString("Hello world!") diff --git a/tests/meteorite.ts b/tests/meteorite.ts new file mode 100644 index 00000000..a877ab1b --- /dev/null +++ b/tests/meteorite.ts @@ -0,0 +1,155 @@ +let oneX: number +let oneY: number +let twoX: number +let twoY: number +let pause: number +let meteoriteOneX: number +let meteoriteOneY: number +let meteoriteTwoX: number +let meteoriteTwoY: number +let counter: number + +basic.pause(2000) +oneX = 0 +oneY = 4 +twoX = 1 +twoY = 4 +counter = 0 +pause = 700 +led.plot(oneX, oneY) +led.plot(twoX, twoY) +input.onButtonPressed(Button.A, () => { + if (oneX > 0) { + led.unplot(oneX, oneY) + led.unplot(twoX, twoY) + oneX = oneX - 1 + twoX = twoX - 1 + led.plot(oneX, oneY) + led.plot(twoX, twoY) + } +}) +input.onButtonPressed(Button.B, () => { + if (twoX < 4) { + led.unplot(oneX, oneY) + led.unplot(twoX, twoY) + oneX = oneX + 1 + twoX = twoX + 1 + led.plot(oneX, oneY) + led.plot(twoX, twoY) + } +}) +meteoriteOneX = Math.random(5) +meteoriteOneY = 0 +meteoriteTwoX = Math.random(5) +meteoriteTwoY = -3 +basic.pause(1000) +for (let i = 0; i < 3; i++) { + led.plot(meteoriteTwoX, meteoriteTwoY) + led.plot(meteoriteOneX, meteoriteOneY) + basic.pause(pause) + led.unplot(meteoriteTwoX, meteoriteTwoY) + led.unplot(meteoriteOneX, meteoriteOneY) + meteoriteOneY = meteoriteOneY + 1 + meteoriteTwoY = meteoriteTwoY + 1 +} +basic.forever(() => { + for (let i1 = 0; i1 < 3; i1++) { + led.plot(meteoriteTwoX, meteoriteTwoY) + led.plot(meteoriteOneX, meteoriteOneY) + basic.pause(pause) + led.unplot(meteoriteOneX, meteoriteOneY) + led.unplot(meteoriteTwoX, meteoriteTwoY) + meteoriteOneY = meteoriteOneY + 1 + meteoriteTwoY = meteoriteTwoY + 1 + if (meteoriteOneY == 4) { + if (meteoriteOneX == oneX) { + for (let j = 0; j < 10; j++) { + led.plotAll() + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + basic.showNumber(counter, 150) + basic.pause(10000) + } else if (meteoriteOneX == twoX) { + for (let j1 = 0; j1 < 10; j1++) { + led.plotAll() + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + basic.showNumber(counter, 150) + basic.pause(10000) + } + } + } + while (Math.abs(meteoriteTwoX - meteoriteOneX) < 1) { + meteoriteOneX = Math.random(5) + } + meteoriteOneY = 0 + counter = counter + 1 + if (counter == 3) { + pause = pause - 250 + } else if (counter == 8) { + pause = pause - 100 + } else if (counter == 12) { + pause = pause - 100 + } else if (counter == 20) { + pause = pause - 100 + } else if (counter == 30) { + pause = pause - 70 + } + if (counter == 40) { + pause = pause - 70 + } + for (let i2 = 0; i2 < 3; i2++) { + led.plot(meteoriteOneX, meteoriteOneY) + led.plot(meteoriteTwoX, meteoriteTwoY) + basic.pause(pause) + led.unplot(meteoriteOneX, meteoriteOneY) + led.unplot(meteoriteTwoX, meteoriteTwoY) + meteoriteOneY = meteoriteOneY + 1 + meteoriteTwoY = meteoriteTwoY + 1 + if (meteoriteTwoY == 4) { + if (meteoriteTwoX == oneX) { + for (let j2 = 0; j2 < 10; j2++) { + led.plotAll() + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + basic.showNumber(counter, 150) + basic.pause(10000) + } else if (meteoriteTwoX == twoX) { + for (let j3 = 0; j3 < 10; j3++) { + led.plotAll() + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + basic.showNumber(counter, 150) + basic.pause(10000) + } + } + } + + meteoriteTwoX = Math.random(5) + while (Math.abs(meteoriteTwoX - meteoriteOneX) < 1) { + meteoriteTwoX = Math.random(5) + } + meteoriteTwoY = 0 + counter = counter + 1 + if (counter == 3) { + pause = pause - 250 + } else if (counter == 8) { + pause = pause - 100 + } else if (counter == 12) { + pause = pause - 100 + } else if (counter == 20) { + pause = pause - 100 + } else if (counter == 30) { + pause = pause - 70 + } else if (counter == 40) { + pause = pause - 70 + } +}) diff --git a/tests/pac-man-runaway.ts b/tests/pac-man-runaway.ts new file mode 100644 index 00000000..be805bff --- /dev/null +++ b/tests/pac-man-runaway.ts @@ -0,0 +1,230 @@ +let levelTime: number +let person: Entity +let monsters: Entity[] +let totalMonsters: number +let playing: boolean +let gameSuspended: boolean +let busyPos: Point[] + +class Entity { + public x: number + public y: number + public dirX: number + public dirY: number + public hitHorizontalWall(): boolean { + return this.y == 0 && this.dirY == -1 || this.y == 4 && this.dirY == 1 + } + + public hitVerticalWall(): boolean { + return this.x == 0 && this.dirX == -1 || this.x == 4 && this.dirX == 1 + } + + public possHorizontalDir(): number { + if (this.x == 0) { + return 1 + } else if (this.x == 4) { + return - 1 + } else { + return Math.random(2) * 2 - 1 + } + } + + public possVerticalDir(): number { + if (this.y == 0) { + return 1 + } else if (this.y == 4) { + return - 1 + } else { + return Math.random(2) * 2 - 1 + } + } + + public collidesX(p2: Entity): boolean { + return this.y == p2.y && this.y + this.dirY == p2.y + p2.dirY && (this.x + this.dirX == p2.x || this.x + this.dirX == p2.x + p2.dirX || p2.x + p2.dirX == this.x) + } + + public collidesY(p2: Entity): boolean { + return this.x == p2.x && this.x + this.dirX == p2.x + p2.dirX && (this.y + this.dirY == p2.y || this.y + this.dirY == p2.y + p2.dirY || p2.y + p2.dirY == this.y) + } + + public move1() { + this.x = this.x + this.dirX + this.y = this.y + this.dirY + } + + public towardsX(p2: Entity): number { + return Math.sign(p2.x - this.x) + } + + public towardsY(p2: Entity): number { + return Math.sign(p2.y - this.y) + } + + public plot() { + led.plot(this.x, this.y) + } + + public blink() { + led.plot(this.x, this.y) + basic.pause(125) + led.unplot(this.x, this.y) + basic.pause(125) + led.plot(this.x, this.y) + } + +} + +class Point { + public x: number + public y: number +} + +initializeState() +redraw() +basic.pause(1000) +basic.forever(() => { + levelTime = levelTime + 12 + basic.pause(12) + if (!playing) { + levelTime = 0 + playing = true + } + if (levelTime >= 5000) { + gameSuspended = true + game.levelUp() + levelUp() + levelTime = 0 + resetState() + redraw() + basic.pause(1000) + gameSuspended = false + } +}) +basic.forever(() => { + if (!gameSuspended) { + logic() + redraw() + basic.pause(500) + } +}) +input.onButtonPressed(Button.A, () => { + let temp = Math.abs(person.dirX) * (-1) + person.dirX = Math.abs(person.dirY) * (-1) + person.dirY = temp +}) +input.onButtonPressed(Button.B, () => { + let temp1 = Math.abs(person.dirX) + person.dirX = Math.abs(person.dirY) + person.dirY = temp1 +}) + +function redraw() { + basic.clearScreen() + person.plot() + for (let i = 0; i < totalMonsters; i++) { + monsters[i].blink() + } +} + +function initializeState() { + person = new Entity() + playing = false + busyPos = ([] as Point[]) + let busyPos1 = new Point() + busyPos1.x = 1 + busyPos1.y = 1 + let busyPos2 = new Point() + busyPos2.x = 1 + busyPos2.y = 3 + let busyPos3 = new Point() + busyPos3.x = 3 + busyPos3.y = 1 + busyPos.push(busyPos1) + busyPos.push(busyPos2) + busyPos.push(busyPos3) + monsters = ([] as Entity[]) + addMonster() + resetState() +} + +function logic() { + if (person.hitHorizontalWall()) { + person.dirY = 0 + person.dirX = person.possHorizontalDir() + } + if (person.hitVerticalWall()) { + person.dirX = 0 + person.dirY = person.possVerticalDir() + } + let lost = false + for (let i = 0; i < totalMonsters; i++) { + let m = monsters[i] + m.dirX = m.towardsX(person) + m.dirY = m.towardsY(person) + if (m.dirX != 0 && m.dirY != 0) { + let x = Math.random(2) + if (x == 1) { + m.dirX = 0 + } else { + m.dirY = 0 + } + } + if (person.collidesX(m) || person.collidesY(m)) { + lost = true + } + } + if (!lost) { + moveAll() + } else { + loseLife() + } +} + +function loseLife() { + moveAll() + basic.pause(500) + basic.showLeds(` + . # . # . + . . # . . + . . . . . + . # # # . + # . . . # + `, 400) + basic.pause(1000) + basic.clearScreen() + game.removeLife(1) + playing = false + resetState() +} + +function moveAll() { + person.move1() + for (let i = 0; i < totalMonsters; i++) { + monsters[i].move1() + } +} + +function addMonster() { + let m = new Entity() + monsters.push(m) + totalMonsters = totalMonsters + 1 +} + +function levelUp() { + addMonster() +} + +function resetState() { + levelTime = 0 + game.setLife(5) + person.x = 4 + person.y = 4 + person.dirX = -1 + person.dirY = 0 + for (let i = 0; i < totalMonsters; i++) { + let busy = busyPos[i] + let m = monsters[i] + m.x = (busy.x + Math.random(3)) - 1 + m.y = (busy.y + Math.random(3)) - 1 + } +}