From b1014cd5611045cd3fb2b76117958f4665db4460 Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Sun, 9 Nov 2025 14:17:18 -0500 Subject: [PATCH] project11 - template --- 11/Average/Main.jack | 27 +++++ 11/ComplexArrays/Main.jack | 69 +++++++++++++ 11/ConvertToBin/Main.jack | 81 +++++++++++++++ 11/Pong/Ball.jack | 203 +++++++++++++++++++++++++++++++++++++ 11/Pong/Bat.jack | 104 +++++++++++++++++++ 11/Pong/Main.jack | 20 ++++ 11/Pong/PongGame.jack | 137 +++++++++++++++++++++++++ 11/Seven/Main.jack | 16 +++ 11/Square/Main.jack | 15 +++ 11/Square/Square.jack | 113 +++++++++++++++++++++ 11/Square/SquareGame.jack | 76 ++++++++++++++ 11/readme.txt | 109 ++++++++++++++++++++ 12 files changed, 970 insertions(+) create mode 100644 11/Average/Main.jack create mode 100644 11/ComplexArrays/Main.jack create mode 100644 11/ConvertToBin/Main.jack create mode 100644 11/Pong/Ball.jack create mode 100644 11/Pong/Bat.jack create mode 100644 11/Pong/Main.jack create mode 100644 11/Pong/PongGame.jack create mode 100644 11/Seven/Main.jack create mode 100644 11/Square/Main.jack create mode 100644 11/Square/Square.jack create mode 100644 11/Square/SquareGame.jack create mode 100644 11/readme.txt diff --git a/11/Average/Main.jack b/11/Average/Main.jack new file mode 100644 index 0000000..e04ae4d --- /dev/null +++ b/11/Average/Main.jack @@ -0,0 +1,27 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Average/Main.jack + +// Inputs some numbers and computes their average +class Main { + function void main() { + var Array a; + var int length; + var int i, sum; + + let length = Keyboard.readInt("How many numbers? "); + let a = Array.new(length); // constructs the array + + let i = 0; + while (i < length) { + let a[i] = Keyboard.readInt("Enter a number: "); + let sum = sum + a[i]; + let i = i + 1; + } + + do Output.printString("The average is "); + do Output.printInt(sum / length); + return; + } +} diff --git a/11/ComplexArrays/Main.jack b/11/ComplexArrays/Main.jack new file mode 100644 index 0000000..e050b63 --- /dev/null +++ b/11/ComplexArrays/Main.jack @@ -0,0 +1,69 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/ComplexArrays/Main.jack +/** + * Performs several complex array processing tests. + * For each test, the expected result is printed, along with the + * actual result. In each test, the two results should be equal. + */ +class Main { + + function void main() { + var Array a, b, c; + + let a = Array.new(10); + let b = Array.new(5); + let c = Array.new(1); + + let a[3] = 2; + let a[4] = 8; + let a[5] = 4; + let b[a[3]] = a[3] + 3; // b[2] = 5 + let a[b[a[3]]] = a[a[5]] * b[((7 - a[3]) - Main.double(2)) + 1]; // a[5] = 8 * 5 = 40 + let c[0] = null; + let c = c[0]; + + do Output.printString("Test 1: expected result: 5; actual result: "); + do Output.printInt(b[2]); + do Output.println(); + do Output.printString("Test 2: expected result: 40; actual result: "); + do Output.printInt(a[5]); + do Output.println(); + do Output.printString("Test 3: expected result: 0; actual result: "); + do Output.printInt(c); + do Output.println(); + + let c = null; + + if (c = null) { + do Main.fill(a, 10); + let c = a[3]; + let c[1] = 33; + let c = a[7]; + let c[1] = 77; + let b = a[3]; + let b[1] = b[1] + c[1]; // b[1] = 33 + 77 = 110; + } + + do Output.printString("Test 4: expected result: 77; actual result: "); + do Output.printInt(c[1]); + do Output.println(); + do Output.printString("Test 5: expected result: 110; actual result: "); + do Output.printInt(b[1]); + do Output.println(); + return; + } + + function int double(int a) { + return a * 2; + } + + function void fill(Array a, int size) { + while (size > 0) { + let size = size - 1; + let a[size] = Array.new(3); + } + return; + } +} diff --git a/11/ConvertToBin/Main.jack b/11/ConvertToBin/Main.jack new file mode 100644 index 0000000..518c0a7 --- /dev/null +++ b/11/ConvertToBin/Main.jack @@ -0,0 +1,81 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/ConvertToBin/Main.jack +/** + * Unpacks a 16-bit number into its binary representation: + * Takes the 16-bit number stored in RAM[8000] and stores its individual + * bits in RAM[8001]..RAM[8016] (each location will contain 0 or 1). + * Before the conversion, RAM[8001]..RAM[8016] are initialized to -1. + * + * The program should be tested as follows: + * 1) Load the program into the supplied VM emulator + * 2) Put some value in RAM[8000] + * 3) Switch to "no animation" + * 4) Run the program (give it enough time to run) + * 5) Stop the program + * 6) Check that RAM[8001]..RAM[8016] contain the correct bits, and + * that none of these memory locations contains -1. + */ +class Main { + + /** + * Initializes RAM[8001]..RAM[8016] to -1, + * and converts the value in RAM[8000] to binary. + */ + function void main() { + var int value; + do Main.fillMemory(8001, 16, -1); // sets RAM[8001]..RAM[8016] to -1 + let value = Memory.peek(8000); // Uses an OS routine to read the input + do Main.convert(value); // performs the conversion + return; + } + + /** Converts the given decimal value to binary, and puts + * the resulting bits in RAM[8001]..RAM[8016]. */ + function void convert(int value) { + var int mask, position; + var boolean loop; + + let loop = true; + while (loop) { + let position = position + 1; + let mask = Main.nextMask(mask); + + if (~(position > 16)) { + + if (~((value & mask) = 0)) { + do Memory.poke(8000 + position, 1); + } + else { + do Memory.poke(8000 + position, 0); + } + } + else { + let loop = false; + } + } + return; + } + + /** Returns the next mask (the mask that should follow the given mask). */ + function int nextMask(int mask) { + if (mask = 0) { + return 1; + } + else { + return mask * 2; + } + } + + /** Fills 'length' consecutive memory locations with 'value', + * starting at 'address'. */ + function void fillMemory(int address, int length, int value) { + while (length > 0) { + do Memory.poke(address, value); + let length = length - 1; + let address = address + 1; + } + return; + } +} diff --git a/11/Pong/Ball.jack b/11/Pong/Ball.jack new file mode 100644 index 0000000..96ce029 --- /dev/null +++ b/11/Pong/Ball.jack @@ -0,0 +1,203 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Pong/Ball.jack +// (Same as projects/9/Pong/Ball.jack) +/** + * A graphical ball in a Pong game. Characterized by a screen location and + * distance of last destination. Has methods for drawing, erasing and moving + * on the screen. The ball is displayed as a filled, 6-by-6 pixles rectangle. + */ +class Ball { + + field int x, y; // the ball's screen location (in pixels) + field int lengthx, lengthy; // distance of last destination (in pixels) + + field int d, straightD, diagonalD; // used for straight line movement computation + field boolean invert, positivex, positivey; // (same) + + field int leftWall, rightWall, topWall, bottomWall; // wall locations + + field int wall; // last wall that the ball was bounced off of + + /** Constructs a new ball with the given initial location and wall locations. */ + constructor Ball new(int Ax, int Ay, + int AleftWall, int ArightWall, int AtopWall, int AbottomWall) { + let x = Ax; + let y = Ay; + let leftWall = AleftWall; + let rightWall = ArightWall - 6; // -6 for ball size + let topWall = AtopWall; + let bottomWall = AbottomWall - 6; // -6 for ball size + let wall = 0; + do show(); + return this; + } + + /** Deallocates the Ball's memory. */ + method void dispose() { + do Memory.deAlloc(this); + return; + } + + /** Shows the ball. */ + method void show() { + do Screen.setColor(true); + do draw(); + return; + } + + /** Hides the ball. */ + method void hide() { + do Screen.setColor(false); + do draw(); + return; + } + + /** Draws the ball. */ + method void draw() { + do Screen.drawRectangle(x, y, x + 5, y + 5); + return; + } + + /** Returns the ball's left edge. */ + method int getLeft() { + return x; + } + + /** Returns the ball's right edge. */ + method int getRight() { + return x + 5; + } + + /** Computes and sets the ball's destination. */ + method void setDestination(int destx, int desty) { + var int dx, dy, temp; + let lengthx = destx - x; + let lengthy = desty - y; + let dx = Math.abs(lengthx); + let dy = Math.abs(lengthy); + let invert = (dx < dy); + + if (invert) { + let temp = dx; // swap dx, dy + let dx = dy; + let dy = temp; + let positivex = (y < desty); + let positivey = (x < destx); + } + else { + let positivex = (x < destx); + let positivey = (y < desty); + } + + let d = (2 * dy) - dx; + let straightD = 2 * dy; + let diagonalD = 2 * (dy - dx); + + return; + } + + /** + * Moves the ball one step towards its destination. + * If the ball has reached a wall, returns 0. + * Else, returns a value according to the wall: + * 1 (left wall), 2 (right wall), 3 (top wall), 4 (bottom wall). + */ + method int move() { + + do hide(); + + if (d < 0) { let d = d + straightD; } + else { + let d = d + diagonalD; + + if (positivey) { + if (invert) { let x = x + 4; } + else { let y = y + 4; } + } + else { + if (invert) { let x = x - 4; } + else { let y = y - 4; } + } + } + + if (positivex) { + if (invert) { let y = y + 4; } + else { let x = x + 4; } + } + else { + if (invert) { let y = y - 4; } + else { let x = x - 4; } + } + + if (~(x > leftWall)) { + let wall = 1; + let x = leftWall; + } + if (~(x < rightWall)) { + let wall = 2; + let x = rightWall; + } + if (~(y > topWall)) { + let wall = 3; + let y = topWall; + } + if (~(y < bottomWall)) { + let wall = 4; + let y = bottomWall; + } + + do show(); + + return wall; + } + + /** + * Bounces off the current wall: sets the new destination + * of the ball according to the ball's angle and the given + * bouncing direction (-1/0/1=left/center/right or up/center/down). + */ + method void bounce(int bouncingDirection) { + var int newx, newy, divLengthx, divLengthy, factor; + + // Since results are too big, divides by 10 + let divLengthx = lengthx / 10; + let divLengthy = lengthy / 10; + if (bouncingDirection = 0) { let factor = 10; } + else { + if (((~(lengthx < 0)) & (bouncingDirection = 1)) | ((lengthx < 0) & (bouncingDirection = (-1)))) { + let factor = 20; // bounce direction is in ball direction + } + else { let factor = 5; } // bounce direction is against ball direction + } + + if (wall = 1) { + let newx = 506; + let newy = (divLengthy * (-50)) / divLengthx; + let newy = y + (newy * factor); + } + else { + if (wall = 2) { + let newx = 0; + let newy = (divLengthy * 50) / divLengthx; + let newy = y + (newy * factor); + } + else { + if (wall = 3) { + let newy = 250; + let newx = (divLengthx * (-25)) / divLengthy; + let newx = x + (newx * factor); + } + else { // assumes wall = 4 + let newy = 0; + let newx = (divLengthx * 25) / divLengthy; + let newx = x + (newx * factor); + } + } + } + + do setDestination(newx, newy); + return; + } +} diff --git a/11/Pong/Bat.jack b/11/Pong/Bat.jack new file mode 100644 index 0000000..ebafe28 --- /dev/null +++ b/11/Pong/Bat.jack @@ -0,0 +1,104 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Pong/Bat.jack +// (Same as projects/9/Pong/Bat.jack) +/** + * A graphical bat in a Pong game. + * Displayed as a filled horizontal rectangle that has a screen location, + * a width and a height. + * Has methods for drawing, erasing, moving left and right, and changing + * its width (to make the hitting action more challenging). + * This class should have been called "Paddle", following the + * standard Pong terminology. Unaware of this terminology, + * we called it "bat", and the name stuck. + */ +class Bat { + + field int x, y; // the bat's screen location + field int width, height; // the bat's width and height + field int direction; // direction of the bat's movement + // (1 = left, 2 = right) + + /** Constructs a new bat with the given location and width. */ + constructor Bat new(int Ax, int Ay, int Awidth, int Aheight) { + let x = Ax; + let y = Ay; + let width = Awidth; + let height = Aheight; + let direction = 2; + do show(); + return this; + } + + /** Deallocates the object's memory. */ + method void dispose() { + do Memory.deAlloc(this); + return; + } + + /** Shows the bat. */ + method void show() { + do Screen.setColor(true); + do draw(); + return; + } + + /** Hides the bat. */ + method void hide() { + do Screen.setColor(false); + do draw(); + return; + } + + /** Draws the bat. */ + method void draw() { + do Screen.drawRectangle(x, y, x + width, y + height); + return; + } + + /** Sets the bat's direction (0=stop, 1=left, 2=right). */ + method void setDirection(int Adirection) { + let direction = Adirection; + return; + } + + /** Returns the bat's left edge. */ + method int getLeft() { + return x; + } + + /** Returns the bat's right edge. */ + method int getRight() { + return x + width; + } + + /** Sets the bat's width. */ + method void setWidth(int Awidth) { + do hide(); + let width = Awidth; + do show(); + return; + } + + /** Moves the bat one step in the bat's direction. */ + method void move() { + if (direction = 1) { + let x = x - 4; + if (x < 0) { let x = 0; } + do Screen.setColor(false); + do Screen.drawRectangle((x + width) + 1, y, (x + width) + 4, y + height); + do Screen.setColor(true); + do Screen.drawRectangle(x, y, x + 3, y + height); + } + else { + let x = x + 4; + if ((x + width) > 511) { let x = 511 - width; } + do Screen.setColor(false); + do Screen.drawRectangle(x - 4, y, x - 1, y + height); + do Screen.setColor(true); + do Screen.drawRectangle((x + width) - 3, y, x + width, y + height); + } + return; + } +} diff --git a/11/Pong/Main.jack b/11/Pong/Main.jack new file mode 100644 index 0000000..50ad7e4 --- /dev/null +++ b/11/Pong/Main.jack @@ -0,0 +1,20 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Pong/Main.jack +// (Same as projects/9/Pong/Main.jack) +/** + * Main class of the Pong game. + */ +class Main { + + /** Initializes a Pong game and starts running it. */ + function void main() { + var PongGame game; + do PongGame.newInstance(); + let game = PongGame.getInstance(); + do game.run(); + do game.dispose(); + return; + } +} diff --git a/11/Pong/PongGame.jack b/11/Pong/PongGame.jack new file mode 100644 index 0000000..b43d823 --- /dev/null +++ b/11/Pong/PongGame.jack @@ -0,0 +1,137 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Pong/PongGame.jack +// (Same as projects/9/Pong/PongGame.jack) +/** + * Represents a Pong game. + */ +class PongGame { + + static PongGame instance; // A Pong game + field Bat bat; // bat + field Ball ball; // ball + field int wall; // current wall that the ball is bouncing off of + field boolean exit; // true when the game is over + field int score; // current score + field int lastWall; // last wall that the ball bounced off of + + // The current width of the bat + field int batWidth; + + /** Constructs a new Pong game. */ + constructor PongGame new() { + do Screen.clearScreen(); + let batWidth = 50; // initial bat size + let bat = Bat.new(230, 229, batWidth, 7); + let ball = Ball.new(253, 222, 0, 511, 0, 229); + do ball.setDestination(400,0); + do Screen.drawRectangle(0, 238, 511, 240); + do Output.moveCursor(22,0); + do Output.printString("Score: 0"); + + let exit = false; + let score = 0; + let wall = 0; + let lastWall = 0; + + return this; + } + + /** Deallocates the object's memory. */ + method void dispose() { + do bat.dispose(); + do ball.dispose(); + do Memory.deAlloc(this); + return; + } + + /** Creates an instance of a Pong game. */ + function void newInstance() { + let instance = PongGame.new(); + return; + } + + /** Returns this Pong game. */ + function PongGame getInstance() { + return instance; + } + + /** Starts the game, and handles inputs from the user that control + * the bat's movement direction. */ + method void run() { + var char key; + + while (~exit) { + // waits for a key to be pressed. + while ((key = 0) & (~exit)) { + let key = Keyboard.keyPressed(); + do bat.move(); + do moveBall(); + do Sys.wait(50); + } + + if (key = 130) { do bat.setDirection(1); } + else { + if (key = 132) { do bat.setDirection(2); } + else { + if (key = 140) { let exit = true; } + } + } + + // Waits for the key to be released. + while ((~(key = 0)) & (~exit)) { + let key = Keyboard.keyPressed(); + do bat.move(); + do moveBall(); + do Sys.wait(50); + } + } + + if (exit) { + do Output.moveCursor(10,27); + do Output.printString("Game Over"); + } + + return; + } + + /** + * Handles ball movement, including bouncing. + * If the ball bounces off a wall, finds its new direction. + * If the ball bounces off the bat, increases the score by one + * and shrinks the bat's size, to make the game more challenging. + */ + method void moveBall() { + var int bouncingDirection, batLeft, batRight, ballLeft, ballRight; + + let wall = ball.move(); + + if ((wall > 0) & (~(wall = lastWall))) { + let lastWall = wall; + let bouncingDirection = 0; + let batLeft = bat.getLeft(); + let batRight = bat.getRight(); + let ballLeft = ball.getLeft(); + let ballRight = ball.getRight(); + + if (wall = 4) { + let exit = (batLeft > ballRight) | (batRight < ballLeft); + if (~exit) { + if (ballRight < (batLeft + 10)) { let bouncingDirection = -1; } + else { + if (ballLeft > (batRight - 10)) { let bouncingDirection = 1; } + } + + let batWidth = batWidth - 2; + do bat.setWidth(batWidth); + let score = score + 1; + do Output.moveCursor(22,7); + do Output.printInt(score); + } + } + do ball.bounce(bouncingDirection); + } + return; + } +} \ No newline at end of file diff --git a/11/Seven/Main.jack b/11/Seven/Main.jack new file mode 100644 index 0000000..e599b93 --- /dev/null +++ b/11/Seven/Main.jack @@ -0,0 +1,16 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Seven/Main.jack +/** + * Computes the value of 1 + (2 * 3) and prints the result + * at the top-left of the screen. + */ +class Main { + + function void main() { + do Output.printInt(1 + (2 * 3)); + return; + } + +} diff --git a/11/Square/Main.jack b/11/Square/Main.jack new file mode 100644 index 0000000..16f2186 --- /dev/null +++ b/11/Square/Main.jack @@ -0,0 +1,15 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Square/Main.jack + +/** Initializes a new Square game and starts running it. */ +class Main { + function void main() { + var SquareGame game; + let game = SquareGame.new(); + do game.run(); + do game.dispose(); + return; + } +} diff --git a/11/Square/Square.jack b/11/Square/Square.jack new file mode 100644 index 0000000..78b9400 --- /dev/null +++ b/11/Square/Square.jack @@ -0,0 +1,113 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Square/Square.jack + +/** Implements a graphical square. + The square has top-left x and y coordinates, and a size. */ +class Square { + + field int x, y; // screen location of the top-left corner of this square + field int size; // length of this square, in pixels + + /** Constructs and draws a new square with a given location and size. */ + constructor Square new(int ax, int ay, int asize) { + let x = ax; + let y = ay; + let size = asize; + do draw(); + return this; + } + + /** Disposes this square. */ + method void dispose() { + do Memory.deAlloc(this); + return; + } + + /** Draws this square in its current (x,y) location */ + method void draw() { + // Draws the square using the color black + do Screen.setColor(true); + do Screen.drawRectangle(x, y, x + size, y + size); + return; + } + + /** Erases this square. */ + method void erase() { + // Draws the square using the color white (background color) + do Screen.setColor(false); + do Screen.drawRectangle(x, y, x + size, y + size); + return; + } + + /** Increments the square size by 2 pixels (if possible). */ + method void incSize() { + if (((y + size) < 254) & ((x + size) < 510)) { + do erase(); + let size = size + 2; + do draw(); + } + return; + } + + /** Decrements the square size by 2 pixels (if possible). */ + method void decSize() { + if (size > 2) { + do erase(); + let size = size - 2; + do draw(); + } + return; + } + + /** Moves this square up by 2 pixels (if possible). */ + method void moveUp() { + if (y > 1) { + // Erases the bottom two rows of this square in its current location + do Screen.setColor(false); + do Screen.drawRectangle(x, (y + size) - 1, x + size, y + size); + let y = y - 2; + // Draws the top two rows of this square in its new location + do Screen.setColor(true); + do Screen.drawRectangle(x, y, x + size, y + 1); + } + return; + } + + /** Moves the square down by 2 pixels (if possible). */ + method void moveDown() { + if ((y + size) < 254) { + do Screen.setColor(false); + do Screen.drawRectangle(x, y, x + size, y + 1); + let y = y + 2; + do Screen.setColor(true); + do Screen.drawRectangle(x, (y + size) - 1, x + size, y + size); + } + return; + } + + /** Moves the square left by 2 pixels (if possible). */ + method void moveLeft() { + if (x > 1) { + do Screen.setColor(false); + do Screen.drawRectangle((x + size) - 1, y, x + size, y + size); + let x = x - 2; + do Screen.setColor(true); + do Screen.drawRectangle(x, y, x + 1, y + size); + } + return; + } + + /** Moves the square right by 2 pixels (if possible). */ + method void moveRight() { + if ((x + size) < 510) { + do Screen.setColor(false); + do Screen.drawRectangle(x, y, x + 1, y + size); + let x = x + 2; + do Screen.setColor(true); + do Screen.drawRectangle((x + size) - 1, y, x + size, y + size); + } + return; + } +} diff --git a/11/Square/SquareGame.jack b/11/Square/SquareGame.jack new file mode 100644 index 0000000..0871063 --- /dev/null +++ b/11/Square/SquareGame.jack @@ -0,0 +1,76 @@ +// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/11/Square/SquareGame.jack +/** + * Implements the Square game. + * This simple game allows the user to move a black square around + * the screen, and change the square's size during the movement. + * When the game starts, a square of 30 by 30 pixels is shown at the + * top-left corner of the screen. The user controls the square as follows. + * The 4 arrow keys are used to move the square up, down, left, and right. + * The 'z' and 'x' keys are used, respectively, to decrement and increment + * the square's size. The 'q' key is used to quit the game. + */ +class SquareGame { + field Square square; // the square of this game + field int direction; // the square's current direction: + // 0=none, 1=up, 2=down, 3=left, 4=right + + /** Constructs a new square game. */ + constructor SquareGame new() { + // The initial square is located in (0,0), has size 30, and is not moving. + let square = Square.new(0, 0, 30); + let direction = 0; + return this; + } + + /** Disposes this game. */ + method void dispose() { + do square.dispose(); + do Memory.deAlloc(this); + return; + } + + /** Moves the square in the current direction. */ + method void moveSquare() { + if (direction = 1) { do square.moveUp(); } + if (direction = 2) { do square.moveDown(); } + if (direction = 3) { do square.moveLeft(); } + if (direction = 4) { do square.moveRight(); } + do Sys.wait(5); // delays the next movement + return; + } + + /** Runs the game: handles the user's inputs and moves the square accordingly */ + method void run() { + var char key; // the key currently pressed by the user + var boolean exit; + let exit = false; + + while (~exit) { + // waits for a key to be pressed + while (key = 0) { + let key = Keyboard.keyPressed(); + do moveSquare(); + } + if (key = 81) { let exit = true; } // q key + if (key = 90) { do square.decSize(); } // z key + if (key = 88) { do square.incSize(); } // x key + if (key = 131) { let direction = 1; } // up arrow + if (key = 133) { let direction = 2; } // down arrow + if (key = 130) { let direction = 3; } // left arrow + if (key = 132) { let direction = 4; } // right arrow + + // waits for the key to be released + while (~(key = 0)) { + let key = Keyboard.keyPressed(); + do moveSquare(); + } + } // while + return; + } +} + + + diff --git a/11/readme.txt b/11/readme.txt new file mode 100644 index 0000000..37d77f1 --- /dev/null +++ b/11/readme.txt @@ -0,0 +1,109 @@ +Project 11 +The compiler built in Nand to Tetris consists of two main modules: a Syntax Analyzer, built in +project 10, and a Code Generator, built in this project. The former module is the point of departure +for the latter module. In particular, in this project you will morph the Syntax Analyzer built in +project 10 into a full-scale Jack compiler. You will do it by gradually replacing the routines that +generate passive XML output with routines that generate executable VM code. +Objective +Extend the Syntax Analyzer built in chapter 10 into a full-scale Jack compiler. Apply your evolving +compiler to all the test programs described below. Execute each translated program, and make +sure that it operates according to its given documentation. This version of the compiler assumes +that the source Jack code is error-free. +Resources +The main tool that you need is the programming language in which you will implement the +compiler. You will also need the supplied VM emulator, for testing the VM code generated by your +compiler. Since the compiler is implemented by extending the syntax analyzer built in project 10, +you will also need the analyzer's source code. +Implementation Stages +We propose completing the compiler’s development in two main stages: Symbol Table, and Code +Generation. +Stage 0: Make a back-up copy of the syntax analyzer code developed in project 10. +Stage 1: Symbol Table: Start by building the compiler’s SymbolTable module, and use it for +extending the syntax analyzer built in Project 10, as follows. Presently, whenever an identifier is +encountered in the source code, say foo, the syntax analyzer outputs the XML line foo +. Extend your analyzer to output the following information about each identifier: +name; +category (field, static, local, arg, class, subroutine); +index: if the identifier’s category is field, static, local, or arg, +the running index assigned to the identifier by the symbol table; +usage: whether the identifier is presently being declared (in a static / field / var variable declaration, +or in a parameter list), or used (in an expression). + +Have your syntax analyzer output this information as part of its XML output, using markup tags of +your choice. +Test your new SymbolTable module and the new functionality just described by running your +extended syntax analyzer on the test Jack programs supplied in project 10. If your extended syntax +analyzer is capable of outputting the information described above, it means that you've developed +a complete executable capability to understand the semantics of Jack programs. At this stage you +www.nand2tetris.org / Copyright © Noam Nisan and Shimon Schocken + +can make the switch to developing the full-scale compiler, and start generating VM code instead of +XML output. This can be done gradually, as we now turn to describe. +Stage 1.5: Make a back-up copy of the extended syntax analyzer code. +Stage 2: Code Generation: We provide six Jack programs, designed to gradually unit-test the code +generation capabilities of your compiler. We advise to develop, and test, your evolving compiler on +the test programs in the order given below. This way, you will be implicitly guided to build the +compiler’s code generation capabilities in sensible stages, according to the demands presented by +each test program. +Normally, when one compiles a high-level program and runs into some difficulties, one concludes +that the program is screwed up. In this project the setting is exactly the opposite. All the supplied +test programs are error-free. Therefore, if their compilation yields any errors, it’s the compiler that +you have to fix, not the programs. Specifically, for each test program, we recommend going +through the following routine: +1. Compile the program folder using the compiler that you are developing. This action should +generate one .vm file for each source .jack file in the given folder. +2. Inspect the generated VM files. If there are visible problems, fix your compiler and go to step 1. +Remember: All the supplied test programs are error-free. +3. Load the program folder into the emulator, and run the loaded code. Note that each one of the +six supplied test programs contains specific execution guidelines; test the compiled program +(translated VM code) according to these guidelines. +4. If the program behaves unexpectedly, or some error message is displayed by the VM emulator, +fix your compiler and go to step 1. +Test Programs +Seven: Tests how the compiler handles a simple program containing an arithmetic expression with +integer constants but without variables, a do statement, and a return statement. Specifically, the +program computes the expression 1 + (3 * 2) and prints its value at the top left of the screen. To +test that your compiler has translated the program correctly, run the translated code in the VM +emulator and verify that it displays 7 correctly. +ConvertToBin: Tests how the compiler handles all the procedural elements of the Jack language: +expressions (without arrays or method calls), functions, and the statements if, while, do, let and +return. The program does not test the handling of methods, constructors, arrays, strings, static +variables, and field variables. Specifically, the program gets a 16-bit decimal value from RAM[8000], +converts it to binary, and stores the individual bits in RAM[8001],...,RAM[8016] (each location will +contain 0 or 1). Before the conversion starts, the program initializes RAM[8001],...,RAM[8016] to +-1. To test that your compiler has translated the program correctly, load the translated code into +the VM emulator, and proceed as follows: +Enter (interactively, using the simulator’s GUI) some decimal value in RAM[8000]; +www.nand2tetris.org / Copyright © Noam Nisan and Shimon Schocken + +Run the program for a few seconds, then stop its execution; +Check (by visual inspection) that memory locations RAM[8001],...,RAM[8016] contain the correct +bits, and that none of them contains -1. +Square (same as projects/9/Square): Tests how the compiler handles the object-based features of +the Jack language: constructors, methods, fields, and expressions that include method calls. Does +not test the handling of static variables. Specifically, the program launches a simple interactive +"game" that enables moving a black square around the screen, using the keyboard’s four arrow +keys. While moving, the size of the square can be increased and decreased anytime by pressing the +'z' and 'x' keys, respectively. To quit the game, press the 'q' key. To test that your compiler has +translated the program correctly, run the translated code in the VM emulator and verify that the +game unfolds as expected (to play the game, select “no animation” and set the speed slider as +needed). +Average (same as projects/9/Average and projects/10/ArrayTest): : Tests how the compiler handles +arrays, and strings. This is done by computing the average of a user-supplied sequence of integers. +To test that your compiler has translated the program correctly, run the translated code in the VM +emulator and follow the instructions displayed on the screen. +Pong: A complete test of how the compiler handles an object-based application, including the +handling of objects and static variables. In the classical Pong game, a ball is moving randomly, +bouncing off the screen "walls." The user tries to hit the ball with a small paddle which can be +moved by pressing the keyboard’s left and right arrow keys. Each time the paddle hits the ball, the +user scores a point and the paddle shrinks a little, making the game increasingly more challenging. +If the user misses and the ball hits the “floor”, the game is over. To test that your compiler has +translated this program correctly, run the translated code in the VM emulator and play the game. +Make sure to score some points, to test the part of the program that displays the score on the +screen (to play the game, select “no animation” and set the speed slider as needed). +ComplexArrays: Tests how the compiler handles complex array references, and expressions. To +that end, the program performs five complex calculations using arrays. For each such calculation, +the program prints on the screen the expected result, along with the actual result, as performed by +the compiled program. To test that your compiler has translated the program correctly, run the +translated code in the VM emulator and make sure that the expected and actual results are +identical.