Add solutions for part 1
This commit is contained in:
27
projects/09/Average/Main.jack
Normal file
27
projects/09/Average/Main.jack
Normal file
@@ -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/09/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;
|
||||
}
|
||||
}
|
||||
200
projects/09/BitmapEditor/BitmapEditor.html
Normal file
200
projects/09/BitmapEditor/BitmapEditor.html
Normal file
@@ -0,0 +1,200 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Sokoban Bitmap Editor</title>
|
||||
<script type="text/javascript">
|
||||
var grid = new Array(0);
|
||||
|
||||
function Init() {
|
||||
grid = InitGrid();
|
||||
DisplayGrid();
|
||||
}
|
||||
|
||||
function InitGrid() {
|
||||
var _grid = new Array(16);
|
||||
for (i=0; i<16; i++) {
|
||||
_grid[i] = new Array(16);
|
||||
for (j=0; j<16; j++) {
|
||||
_grid[i][j]=false;
|
||||
}
|
||||
}
|
||||
return _grid;
|
||||
}
|
||||
|
||||
function RotateBitmapRight() {
|
||||
var _grid = InitGrid();
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
for (j=0; j<16; j++) {
|
||||
_grid[j][15-i]=grid[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
grid = _grid;
|
||||
DisplayGrid();
|
||||
}
|
||||
|
||||
function MirrorBitmap() {
|
||||
var _grid = InitGrid();
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
for (j=0; j<16; j++) {
|
||||
_grid[i][15-j]=grid[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
grid = _grid;
|
||||
DisplayGrid();
|
||||
}
|
||||
|
||||
function DisplayGrid() {
|
||||
var str = "<table border=1 cellspacing=0>";
|
||||
var i,j, backgroundColor;
|
||||
for (i=-1; i<16; i++) {
|
||||
str=str+"<tr>";
|
||||
for (j=-1; j<16; j++) {
|
||||
if (i == -1 && j != -1) {
|
||||
str=str+"<td>" + (j+1) + "</td>";
|
||||
} else if (i != -1 && j == -1) {
|
||||
str=str+"<td>" + (i+1) + "</td>";
|
||||
} else if (i ==-1 && j == -1) {
|
||||
str=str+"<td/>";
|
||||
} else {
|
||||
|
||||
if (grid[i][j] == true)
|
||||
backgroundColor = "black";
|
||||
else
|
||||
backgroundColor = "white";
|
||||
|
||||
str=str+"<td onclick=\"OnCellClicked(this)\" id="; str=str+(i*16+j); str=str+" width=16 height=16 bgcolor=" + backgroundColor + "></td>";
|
||||
}
|
||||
}
|
||||
str=str+"</tr>";
|
||||
}
|
||||
str=str+"</table>"
|
||||
|
||||
gridElement = document.getElementById('grid');
|
||||
gridElement.innerHTML = str;
|
||||
GenerateBitMap() ;
|
||||
}
|
||||
|
||||
function OnCellClicked(cell) {
|
||||
var i = cell.id / 16 |0;
|
||||
var j = cell.id - i*16;
|
||||
grid[i][j] = !grid[i][j];
|
||||
if (grid[i][j])
|
||||
cell.style.backgroundColor = "black";
|
||||
else
|
||||
cell.style.backgroundColor = "white";
|
||||
GenerateBitMap();
|
||||
}
|
||||
|
||||
function GenerateBitMap() {
|
||||
var i, j;
|
||||
var value;
|
||||
|
||||
var functionTypeSelect = document.getElementById('functionType');
|
||||
methodType = functionTypeSelect.options[functionTypeSelect.selectedIndex].value;
|
||||
|
||||
generateCode = document.getElementById('generatedCode');
|
||||
generateCode.value = methodType + " void " +
|
||||
document.getElementById('functionName').value +
|
||||
"(int location) {\n\tlet memAddress = 16384+location;\n";
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
//get grid binary representation
|
||||
binary = "";
|
||||
for (j=0; j<16; j++) {
|
||||
if (grid[i][j])
|
||||
binary = "1" + binary;
|
||||
else
|
||||
binary = "0" + binary;
|
||||
}
|
||||
|
||||
isNegative = false;
|
||||
//if number is negative, get its one's complement
|
||||
if (binary[0] == "1") {
|
||||
isNegative = true;
|
||||
oneComplement = "";
|
||||
for (k=0; k<16; k++) {
|
||||
if (binary[k] == "1")
|
||||
oneComplement = oneComplement + "0";
|
||||
else
|
||||
oneComplement = oneComplement + "1";
|
||||
}
|
||||
binary = oneComplement;
|
||||
}
|
||||
|
||||
//calculate one's complement decimal value
|
||||
value = 0;
|
||||
for (k=0; k<16; k++) {
|
||||
value = value * 2;
|
||||
if (binary[k] == "1")
|
||||
value=value+1;
|
||||
}
|
||||
|
||||
//two's complement value if it is a negative value
|
||||
if (isNegative == true)
|
||||
value = -(value + 1)
|
||||
|
||||
generateCode.value = generateCode.value + GenerateCodeLine(i, value);
|
||||
}
|
||||
|
||||
generateCode.value = generateCode.value + "\treturn;\n}";
|
||||
}
|
||||
|
||||
function GenerateCodeLine(row, value) {
|
||||
str = "\tdo Memory.poke(memAddress+" + row*32 + ", " + value + ");\n";
|
||||
return str;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="Init();">
|
||||
<h4><i>IDC Herzliya / Efi Arazi School of Computer Science / Digital Systems Construction, Spring 2011 / Project 09 / Golan Parashi</i></h4>
|
||||
<h1>Sokoban Bitmap Editor</h1>
|
||||
<p>This javascript applicaiton is used to generate highly optimized jack code for drawing a 16x16 bitmap to the screen.</p>
|
||||
<p>Using the mouse, click the desired cell to mark/unmark it. You may use 90 degrees rotation and vertical mirroring by<br>
|
||||
clicking the appropriate buttons.</p>
|
||||
<p>When you are finished drawing, you may select function type and enter function's name.</p>
|
||||
<p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Bitmap</th>
|
||||
<th align="left"></th>
|
||||
<th align="left">Generated Jack Code</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td><div id="grid"/></td>
|
||||
<td>
|
||||
<form action="javascript:GenerateBitMap();">
|
||||
<table>
|
||||
<tr><td align="left">Function Type:</td></tr>
|
||||
<tr><td align="center">
|
||||
<select id="functionType" onChange="GenerateBitMap()">
|
||||
<option value="function" selected="selected">function</option>
|
||||
<option value="method">method</option>
|
||||
</select>
|
||||
</td></tr>
|
||||
<tr><td align="left">Function Name:</td></tr>
|
||||
<tr><td align="left"><input type="text" value="draw" id="functionName" onkeyup="GenerateBitMap()"/></td></tr>
|
||||
<tr><td></td></tr>
|
||||
<tr><td align="center"><input type="button" value="Generate Code >>" onclick="GenerateBitMap()"/></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
</td>
|
||||
<td><textarea id="generatedCode" cols="50" rows="20" readonly="read-only"></textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><input type="button" value="Rotate right" onclick="RotateBitmapRight()"/></td>
|
||||
<td align="center"><input type="button" value="Vertical Mirror" onclick="MirrorBitmap()"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
10
projects/09/BitmapEditor/BitmapEditor.iml
Normal file
10
projects/09/BitmapEditor/BitmapEditor.iml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
205
projects/09/CellAutomaton1D/CellularAutomaton.jack
Normal file
205
projects/09/CellAutomaton1D/CellularAutomaton.jack
Normal file
@@ -0,0 +1,205 @@
|
||||
/** Represents a 1D cellular automaton that can be printed to the screen. */
|
||||
class CellularAutomaton {
|
||||
|
||||
field Array currentConfig; // an array where each field represents one cell
|
||||
field int currentRule; // the current rule used by nextState
|
||||
field int currentRow; // the row on the screen where the last state was printed
|
||||
field int size; // cells per row
|
||||
field boolean debug; // print debugging help to screen if true
|
||||
|
||||
/** Create a new automaton where size is the number of cells per row. */
|
||||
constructor CellularAutomaton new() {
|
||||
var int i;
|
||||
let currentRule = 0;
|
||||
let currentRow = 0;
|
||||
let size = 512;
|
||||
let debug = false;
|
||||
|
||||
let currentConfig = Array.new(size);
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
let currentConfig[i] = 0;
|
||||
let i = i + 1;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns a reference to the current config. Be careful, step creates a
|
||||
* new configuration so using the reference after calling step points to
|
||||
* invalid memory.
|
||||
*/
|
||||
method Array getCurrentConfig() {
|
||||
return currentConfig;
|
||||
}
|
||||
|
||||
method void dispose() {
|
||||
do currentConfig.dispose();
|
||||
do Memory.deAlloc(this);
|
||||
return;
|
||||
}
|
||||
|
||||
method void setRule(int rule) {
|
||||
let currentRule = rule;
|
||||
return;
|
||||
}
|
||||
|
||||
/** Draws the current configuration to the currentRow on the screen. */
|
||||
method void draw() {
|
||||
if (currentRow > 255) {
|
||||
// This works, but is slow and I don't know how to make it faster.
|
||||
// So we simply start from the top instead again.
|
||||
// do drawLastRow();
|
||||
let currentRow = 0;
|
||||
do Screen.clearScreen();
|
||||
do drawNewRow();
|
||||
} else {
|
||||
do drawNewRow();
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
do Screen.setColor(true);
|
||||
do Output.moveCursor(0, 0);
|
||||
do Output.printInt(currentRow);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** If we are not yet in the last row we can simply
|
||||
* print the new config to the next row. */
|
||||
method void drawNewRow() {
|
||||
var int i;
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
if (currentConfig[i]) {
|
||||
do Screen.setColor(true);
|
||||
} else {
|
||||
do Screen.setColor(false);
|
||||
}
|
||||
do Screen.drawPixel(i, currentRow);
|
||||
let i = i + 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
method void copy(int sourceAddress, int targetAddress) {
|
||||
var int value;
|
||||
let value = Memory.peek(sourceAddress);
|
||||
do Memory.poke(targetAddress, value);
|
||||
return;
|
||||
}
|
||||
|
||||
/** If we are in the last row we first have to move all existing rows one
|
||||
* row up. We can then draw the last row. XXX: This works, but we are
|
||||
* currently not using it because it is too slow. */
|
||||
method void drawLastRow() {
|
||||
var int i;
|
||||
var int sourceAddress;
|
||||
|
||||
// Screen Base + Words = 16384 + 8160 = 24544
|
||||
let i = 16383;
|
||||
while (i < 24544) {
|
||||
let sourceAddress = i + 32;
|
||||
do copy(sourceAddress, i);
|
||||
let i = i + 1;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
if (currentConfig[i]) {
|
||||
do Screen.setColor(true);
|
||||
} else {
|
||||
do Screen.setColor(false);
|
||||
}
|
||||
do Screen.drawPixel(i, currentRow);
|
||||
let i = i + 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
method int rule_57(int left, int middle, int right) {
|
||||
if (left = 1) { if (middle = 1) { if (right = 1) { return 0; } } }
|
||||
if (left = 1) { if (middle = 1) { if (right = 0) { return 0; } } }
|
||||
if (left = 0) { if (middle = 1) { if (right = 0) { return 0; } } }
|
||||
if (left = 0) { if (middle = 0) { if (right = 1) { return 0; } } }
|
||||
return 1;
|
||||
}
|
||||
|
||||
method int rule_90(int left, int middle, int right) {
|
||||
let middle = left + right;
|
||||
if (middle = 1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
method int rule_101(int left, int middle, int right) {
|
||||
if (left = 1) { if (middle = 1) { if (right = 1) { return 0; } } }
|
||||
if (left = 1) { if (middle = 0) { if (right = 0) { return 0; } } }
|
||||
if (left = 0) { if (middle = 1) { if (right = 1) { return 0; } } }
|
||||
if (left = 0) { if (middle = 0) { if (right = 1) { return 0; } } }
|
||||
return 1;
|
||||
}
|
||||
|
||||
method int rule_110(int left, int middle, int right) {
|
||||
if (left = 1) { if (middle = 1) { if (right = 1) { return 0; } } }
|
||||
if (left = 1) { if (middle = 0) { if (right = 0) { return 0; } } }
|
||||
if (left = 0) { if (middle = 0) { if (right = 0) { return 0; } } }
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Calculates the next configuration based on currentConfig and
|
||||
* currentRule */
|
||||
method void step() {
|
||||
var int i, limit;
|
||||
var Array newConfig;
|
||||
let newConfig = Array.new(size);
|
||||
let currentRow = currentRow + 1;
|
||||
|
||||
if (currentRule = 57) {
|
||||
// Calculate new state of first cell
|
||||
let newConfig[0] = rule_57(0, currentConfig[0], currentConfig[1]);
|
||||
// Calculate new state of last cell
|
||||
let newConfig[511] = rule_57(currentConfig[510], currentConfig[511], 0);
|
||||
// All the other cells
|
||||
let i = 1; // Skip first cell and last cell
|
||||
while (i < 511) {
|
||||
let newConfig[i] = rule_57(currentConfig[i - 1], currentConfig[i], currentConfig[i + 1]);
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentRule = 90) {
|
||||
let newConfig[0] = rule_90(0, currentConfig[0], currentConfig[1]);
|
||||
let newConfig[511] = rule_90(currentConfig[510], currentConfig[511], 0);
|
||||
let i = 1;
|
||||
while (i < 511) {
|
||||
let newConfig[i] = rule_90(currentConfig[i - 1], currentConfig[i], currentConfig[i + 1]);
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentRule = 101) {
|
||||
let newConfig[0] = rule_101(0, currentConfig[0], currentConfig[1]);
|
||||
let newConfig[511] = rule_101(currentConfig[510], currentConfig[511], 0);
|
||||
let i = 1;
|
||||
while (i < 511) {
|
||||
let newConfig[i] = rule_101(currentConfig[i - 1], currentConfig[i], currentConfig[i + 1]);
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentRule = 110) {
|
||||
let newConfig[0] = rule_110(0, currentConfig[0], currentConfig[1]);
|
||||
let newConfig[511] = rule_110(currentConfig[510], currentConfig[511], 0);
|
||||
let i = 1;
|
||||
while (i < 511) {
|
||||
let newConfig[i] = rule_110(currentConfig[i - 1], currentConfig[i], currentConfig[i + 1]);
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
do currentConfig.dispose();
|
||||
let currentConfig = newConfig;
|
||||
return;
|
||||
}
|
||||
}
|
||||
370
projects/09/CellAutomaton1D/CellularAutomatonController.jack
Normal file
370
projects/09/CellAutomaton1D/CellularAutomatonController.jack
Normal file
@@ -0,0 +1,370 @@
|
||||
|
||||
|
||||
/** Manages the cellular automaton and interacts with the user. */
|
||||
class CellularAutomatonController {
|
||||
field CellularAutomaton automaton;
|
||||
field Array config;
|
||||
field Array rules;
|
||||
field int numRules;
|
||||
|
||||
constructor CellularAutomatonController new() {
|
||||
// Turned out it is easiest to manage the Automaton itself from here.
|
||||
let automaton = CellularAutomaton.new();
|
||||
// We need the cell state array to write the initial configuration
|
||||
// by the user into it.
|
||||
let config = automaton.getCurrentConfig();
|
||||
|
||||
// Array to switch between rules.
|
||||
let numRules = 4;
|
||||
let rules = Array.new(numRules);
|
||||
let rules[0] = 57;
|
||||
let rules[1] = 90;
|
||||
let rules[2] = 101;
|
||||
let rules[3] = 110;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
method void dispose() {
|
||||
// config gets deAllocated by CellularAutomaton!
|
||||
do automaton.dispose();
|
||||
do rules.dispose();
|
||||
do Memory.deAlloc(this);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Greets the user and guides through the initial configuration. */
|
||||
method void initialConfiguration() {
|
||||
do Screen.clearScreen();
|
||||
do Screen.setColor(true);
|
||||
do sayHello();
|
||||
do printHelpInitialConfiguration();
|
||||
do createInitialConfiguration();
|
||||
do selectRule();
|
||||
do finishConfiguration();
|
||||
return;
|
||||
}
|
||||
|
||||
/** Prints some dots on the screen to simulate loading, because why not? */
|
||||
method void makeWaitDots() {
|
||||
do Sys.wait(30);
|
||||
do Output.printString(".");
|
||||
do Sys.wait(30);
|
||||
do Output.printString(".");
|
||||
do Sys.wait(30);
|
||||
do Output.printString(".");
|
||||
do Sys.wait(30);
|
||||
do Output.printString(" ");
|
||||
return;
|
||||
}
|
||||
|
||||
method void waitForEnter() {
|
||||
var int key;
|
||||
var boolean exit;
|
||||
|
||||
let key = 0;
|
||||
let exit = false;
|
||||
|
||||
do Output.printString("<Enter> to continue. ");
|
||||
|
||||
while (~exit) {
|
||||
while (key = 0) {
|
||||
let key = Keyboard.keyPressed();
|
||||
}
|
||||
if (key = 128) { let exit = true; } // enter key
|
||||
while (~(key = 0)) {
|
||||
let key = Keyboard.keyPressed();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
method void sayHello() {
|
||||
do Output.moveCursor(0, 0);
|
||||
do Output.printString("> Welcome to cellular automaton 1D! ");
|
||||
do makeWaitDots();
|
||||
do Output.moveCursor(1, 0);
|
||||
do Output.printString("> Let's configure the automaton");
|
||||
do makeWaitDots();
|
||||
return;
|
||||
}
|
||||
|
||||
method void printHelpInitialConfiguration() {
|
||||
do Output.moveCursor(3, 0);
|
||||
do Output.printString("> Toggle the cells that should be alive with <space>");
|
||||
do makeWaitDots();
|
||||
do Output.moveCursor(4, 0);
|
||||
do Output.printString("> Move with <h>/<l> and use <u>/<i> to change the step size");
|
||||
do makeWaitDots();
|
||||
do Output.moveCursor(6, 0);
|
||||
do Output.printString("> stepSize = 1 - position = - activeCells = ");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
method void printStepSize(int n) {
|
||||
do Output.moveCursor(6, 15);
|
||||
do Output.printString(" ");
|
||||
do Output.moveCursor(6, 15);
|
||||
do Output.printInt(n);
|
||||
return;
|
||||
}
|
||||
|
||||
method void printCursorPosition(int n) {
|
||||
do Output.moveCursor(6, 32);
|
||||
do Output.printString(" ");
|
||||
do Output.moveCursor(6, 32);
|
||||
do Output.printInt(n);
|
||||
return;
|
||||
}
|
||||
|
||||
method void printActiveCellsj(int n) {
|
||||
do Output.moveCursor(6, 52);
|
||||
do Output.printString(" ");
|
||||
do Output.moveCursor(6, 52);
|
||||
do Output.printInt(n);
|
||||
return;
|
||||
}
|
||||
|
||||
method void createInitialConfiguration() {
|
||||
var int key;
|
||||
var boolean exit;
|
||||
var int cursorPosition;
|
||||
var int stepSize;
|
||||
var int activeCells;
|
||||
|
||||
// Variables for printing the cell selction UI.
|
||||
var int cursorY1, cursorY2, cellY1, cellY2;
|
||||
|
||||
let key = 0;
|
||||
|
||||
let cursorY1 = 90;
|
||||
let cursorY2 = 95;
|
||||
let cellY1 = 85;
|
||||
let cellY2 = 88;
|
||||
|
||||
let stepSize = 1;
|
||||
let cursorPosition = 0;
|
||||
let activeCells = 0;
|
||||
|
||||
do printStepSize(stepSize);
|
||||
do printCursorPosition(cursorPosition);
|
||||
do printActiveCellsj(activeCells);
|
||||
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
|
||||
|
||||
let exit = false;
|
||||
while (~exit) {
|
||||
while (key = 0) {
|
||||
let key = Keyboard.keyPressed();
|
||||
}
|
||||
if (key = 128) { // enter key
|
||||
if (activeCells > 0) {
|
||||
let exit = true;
|
||||
} else {
|
||||
do Output.moveCursor(9, 0);
|
||||
do Output.printString("> Toggle at least one cell!");
|
||||
}
|
||||
} // enter key
|
||||
if (key = 72) { // h key
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
|
||||
if ((cursorPosition - stepSize) > 0) {
|
||||
let cursorPosition = cursorPosition - stepSize;
|
||||
} else {
|
||||
let cursorPosition = 0;
|
||||
}
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
|
||||
do printCursorPosition(cursorPosition);
|
||||
}
|
||||
if (key = 76) { // l key
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
|
||||
if ((cursorPosition + stepSize) < 511) {
|
||||
let cursorPosition = cursorPosition + stepSize;
|
||||
} else {
|
||||
let cursorPosition = 511;
|
||||
}
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
|
||||
do printCursorPosition(cursorPosition);
|
||||
}
|
||||
if (key = 73) { // i key
|
||||
if (stepSize < 512) {
|
||||
let stepSize = stepSize * 2;
|
||||
do printStepSize(stepSize);
|
||||
}
|
||||
}
|
||||
if (key = 85) { // u key
|
||||
if (stepSize > 1) {
|
||||
let stepSize = stepSize / 2;
|
||||
do printStepSize(stepSize);
|
||||
}
|
||||
}
|
||||
if (key = 32) { // space key
|
||||
if (config[cursorPosition]) { // cell is alive -> make dead
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawLine(cursorPosition, cellY1, cursorPosition, cellY2);
|
||||
let config[cursorPosition] = 0;
|
||||
let activeCells = activeCells - 1;
|
||||
} else { // cell is dead -> make alive
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawLine(cursorPosition, cellY1, cursorPosition, cellY2);
|
||||
let config[cursorPosition] = 1;
|
||||
let activeCells = activeCells + 1;
|
||||
}
|
||||
do Screen.setColor(true);
|
||||
do printActiveCellsj(activeCells);
|
||||
}
|
||||
|
||||
while (~(key = 0)) {
|
||||
let key = Keyboard.keyPressed();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
method void printRule(int n) {
|
||||
do Output.moveCursor(12, 8);
|
||||
do Output.printString(" ");
|
||||
do Output.moveCursor(12, 8);
|
||||
do Output.printInt(n);
|
||||
return;
|
||||
}
|
||||
|
||||
method void selectRule() {
|
||||
var int i;
|
||||
var int rule;
|
||||
var int key;
|
||||
var boolean exit;
|
||||
|
||||
let i = 1;
|
||||
let rule = rules[i];
|
||||
let exit = false;
|
||||
|
||||
do Output.moveCursor(10, 0);
|
||||
do Output.printString("> Good. Let's select which rule you want to simulate");
|
||||
do makeWaitDots();
|
||||
do Output.moveCursor(11, 0);
|
||||
do Output.printString("> Use <h>/<l> to switch between rules");
|
||||
do makeWaitDots();
|
||||
|
||||
do Output.moveCursor(12, 0);
|
||||
do Output.printString("> Rule selected. Confirm with <enter>.");
|
||||
do printRule(rule);
|
||||
|
||||
while (~exit) {
|
||||
while (key = 0) {
|
||||
let key = Keyboard.keyPressed();
|
||||
}
|
||||
if (key = 128) { // enter key
|
||||
let exit = true;
|
||||
}
|
||||
|
||||
if (key = 72) { // h key -> prev rule
|
||||
if (i > 0) {
|
||||
let i = i - 1;
|
||||
}
|
||||
}
|
||||
if (key = 76) {
|
||||
if (i < (numRules - 1)) {
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
let rule = rules[i];
|
||||
do printRule(rule);
|
||||
do automaton.setRule(rule);
|
||||
|
||||
while (~(key = 0)) {
|
||||
let key = Keyboard.keyPressed();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
method void finishConfiguration() {
|
||||
do Output.moveCursor(15, 0);
|
||||
do Output.printString("> Okay, nice. We are ready to go");
|
||||
do makeWaitDots();
|
||||
do Output.moveCursor(16, 0);
|
||||
do Output.printString("> Once you press enter you will no longer see the menu");
|
||||
do makeWaitDots();
|
||||
do Output.moveCursor(17, 0);
|
||||
do Output.printString("> So remember the following keys (or at least <q> for quit)");
|
||||
do makeWaitDots();
|
||||
do Output.moveCursor(19, 0);
|
||||
do Output.printString("> Controls: ");
|
||||
do makeWaitDots();
|
||||
do Output.moveCursor(20, 0);
|
||||
do Output.printString("> <p>ause, <c>ontinue, <s>tep, <r>restart, <q>quit! ");
|
||||
|
||||
do Output.moveCursor(22, 0);
|
||||
do Output.printString(" ");
|
||||
do waitForEnter();
|
||||
do Screen.clearScreen();
|
||||
return;
|
||||
}
|
||||
|
||||
method void run() {
|
||||
var int key;
|
||||
var boolean quit;
|
||||
var boolean running;
|
||||
var boolean restart;
|
||||
var boolean step;
|
||||
|
||||
let quit = false;
|
||||
let restart = false;
|
||||
let running = true;
|
||||
let step = false;
|
||||
|
||||
while (~quit) {
|
||||
if (restart) {
|
||||
do automaton.dispose();
|
||||
let automaton = CellularAutomaton.new();
|
||||
do initialConfiguration();
|
||||
let quit = false;
|
||||
let restart = false;
|
||||
let running = true;
|
||||
let step = false;
|
||||
}
|
||||
|
||||
if (running) {
|
||||
do automaton.draw();
|
||||
do automaton.step();
|
||||
}
|
||||
|
||||
if (step) {
|
||||
do automaton.draw();
|
||||
do automaton.step();
|
||||
let step = false;
|
||||
}
|
||||
|
||||
let key = Keyboard.keyPressed();
|
||||
if (key = 82) { // r key
|
||||
let restart = true;
|
||||
}
|
||||
if (key = 80) { // p key
|
||||
let running = false;
|
||||
}
|
||||
if (key = 67) { // c key
|
||||
let running = true;
|
||||
}
|
||||
if (key = 83) { // s key
|
||||
if (~running) {
|
||||
let step = true;
|
||||
}
|
||||
}
|
||||
if (key = 81) { // q key
|
||||
let quit = true;
|
||||
}
|
||||
|
||||
while (~(key = 0)) {
|
||||
let key = Keyboard.keyPressed();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
32
projects/09/CellAutomaton1D/Main.jack
Normal file
32
projects/09/CellAutomaton1D/Main.jack
Normal file
@@ -0,0 +1,32 @@
|
||||
/** Implements a cellular automaton.
|
||||
*
|
||||
* In the first state the user can define the initial configuration (the cells
|
||||
* that are alive in the beginning. If the user is not sure about which cells
|
||||
* to enable choosing the one in the middle (255/256) is ususually a good
|
||||
* start.
|
||||
*
|
||||
* Next, the user selects the rule they want to simulate. A list of all rules
|
||||
* is available on Wikipedia. If the user is not sure which rule they want Rule
|
||||
* 90 is a good start to get the idea.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Elementary_cellular_automaton
|
||||
*
|
||||
* In the second stage the user can select the initial configuration of the
|
||||
* automaton. The keys 'h' and 'l' move the cursor one pixel to the left or
|
||||
* right respectively. By pressing the space bar the user can toggle the
|
||||
* current pixel. By pressing the 'r' key the simulation is started. Pressing
|
||||
* 'q' ends the simulator.
|
||||
*/
|
||||
|
||||
/** Initializes a new Cellular Automaton Game and runs it. */
|
||||
class Main {
|
||||
function void main() {
|
||||
var CellularAutomatonController controller;
|
||||
|
||||
let controller = CellularAutomatonController.new();
|
||||
do controller.initialConfiguration();
|
||||
do controller.run();
|
||||
do controller.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
20
projects/09/CellAutomaton1D/readme.md
Normal file
20
projects/09/CellAutomaton1D/readme.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Cellular Automaton 1D
|
||||
---------------------
|
||||
|
||||
This project implements a one dimensional cellular automaton. It is like the
|
||||
famous *Game of Life*, but in 1D. If you are not familiar with the concept you
|
||||
can read more on
|
||||
[mathworld.wolfram.com](https://mathworld.wolfram.com/CellularAutomaton.html)
|
||||
so I recommend simply try the application. It should be self explanatory and
|
||||
you will be surprised.
|
||||
|
||||
The program runs in two stages. In the first stage the user configures the
|
||||
initial population of the one automaton as well as the rule that is used for
|
||||
creating the following populations. If you are not familiar with the rules
|
||||
*Rule 90* with an initial cell in the middle is good enough.
|
||||
|
||||
In the second stage the program computes and visualizes the automaton. The
|
||||
program can be paused with `p`, continued with `c`, single stepped with `s`,
|
||||
reset with `r`, and terminated with `q`.
|
||||
|
||||
Have fun!
|
||||
65
projects/09/Fraction/Fraction.jack
Normal file
65
projects/09/Fraction/Fraction.jack
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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/09/Fraction/Fraction.jack
|
||||
|
||||
/** Represents the Fraction type and related operations. */
|
||||
class Fraction {
|
||||
field int numerator, denominator; // field = property = member variable.
|
||||
|
||||
/** Constructs a (reduced) fraction from the given numerator and denominator. */
|
||||
constructor Fraction new(int x, int y) {
|
||||
let numerator = x;
|
||||
let denominator = y;
|
||||
do reduce(); // reduces the fraction
|
||||
return this; // a constructor is expected to return a reference to the new object
|
||||
}
|
||||
|
||||
// Reduces this fraction.
|
||||
method void reduce() {
|
||||
var int g;
|
||||
let g = Fraction.gcd(numerator, denominator);
|
||||
if (g > 1) {
|
||||
let numerator = numerator / g;
|
||||
let denominator = denominator / g;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Accessors. */
|
||||
method int getNumerator() { return numerator; }
|
||||
method int getDenominator() { return denominator; }
|
||||
|
||||
/** Returns the sum of this fraction and the other one. */
|
||||
method Fraction plus(Fraction other) {
|
||||
var int sum;
|
||||
let sum = (numerator * other.getDenominator()) + (other.getNumerator() * denominator);
|
||||
return Fraction.new(sum, denominator * other.getDenominator());
|
||||
}
|
||||
|
||||
// More fraction-related methods (minus, times, div, etc.) can be added here.
|
||||
|
||||
/** Disposes this fraction. */
|
||||
method void dispose() {
|
||||
do Memory.deAlloc(this); // uses an OS routine to recycle the memory held by the object
|
||||
return;
|
||||
}
|
||||
|
||||
/** Prints this fraction in the format x/y. */
|
||||
method void print() {
|
||||
do Output.printInt(numerator);
|
||||
do Output.printString("/");
|
||||
do Output.printInt(denominator);
|
||||
return;
|
||||
}
|
||||
|
||||
// Computes the greatest common divisor of the given integers.
|
||||
function int gcd(int a, int b) {
|
||||
var int r;
|
||||
while (~(b = 0)) { // applies Euclid's algorithm
|
||||
let r = a - (b * (a / b)); // r = remainder of the integer division a/b
|
||||
let a = b; let b = r;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
16
projects/09/Fraction/Main.jack
Normal file
16
projects/09/Fraction/Main.jack
Normal file
@@ -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/09/Fraction/Main.jack
|
||||
|
||||
// Computes the sum of 2/3 and 1/5.
|
||||
class Main {
|
||||
function void main() {
|
||||
var Fraction a, b, c;
|
||||
let a = Fraction.new(2,3);
|
||||
let b = Fraction.new(1,5);
|
||||
let c = a.plus(b); // Computes c = a + b
|
||||
do c.print(); // Prints "13/15"
|
||||
return;
|
||||
}
|
||||
}
|
||||
14
projects/09/HelloWorld/Main.jack
Normal file
14
projects/09/HelloWorld/Main.jack
Normal file
@@ -0,0 +1,14 @@
|
||||
// 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/09/HelloWorld/Main.jack
|
||||
|
||||
/** Hello World program. */
|
||||
class Main {
|
||||
function void main() {
|
||||
/* Prints some text using the standard library. */
|
||||
do Output.printString("Hello world!");
|
||||
do Output.println(); // New line
|
||||
return;
|
||||
}
|
||||
}
|
||||
BIN
projects/09/Jack OS API.pdf
Normal file
BIN
projects/09/Jack OS API.pdf
Normal file
Binary file not shown.
46
projects/09/List/List.jack
Normal file
46
projects/09/List/List.jack
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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/09/List/List.jack
|
||||
|
||||
/** Represents a linked list of integers. */
|
||||
class List {
|
||||
field int data; // a list consists of a data field,
|
||||
field List next; // followed by a list
|
||||
|
||||
/* Creates a List. */
|
||||
constructor List new(int car, List cdr) {
|
||||
let data = car; // the identifiers car and cdr are used in
|
||||
let next = cdr; // memory of the Lisp programming language
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Accessors. */
|
||||
method int getData() { return data; }
|
||||
method int getNext() { return next; }
|
||||
|
||||
/** Prints this list. */
|
||||
method void print() {
|
||||
var List current; // initializes current to the first item
|
||||
let current = this; // of this list
|
||||
while (~(current = null)) {
|
||||
do Output.printInt(current.getData());
|
||||
do Output.printChar(32); // prints a space
|
||||
let current = current.getNext();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Disposes this List by recursively disposing its tail. */
|
||||
method void dispose() {
|
||||
if (~(next = null)) {
|
||||
do next.dispose();
|
||||
}
|
||||
// Uses an OS routine to recycle this object.
|
||||
do Memory.deAlloc(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// More list processing methods can come here.
|
||||
|
||||
}
|
||||
17
projects/09/List/Main.jack
Normal file
17
projects/09/List/Main.jack
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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/09/List/Main.jack
|
||||
|
||||
/** Demonstrates the use of the List abstraction. */
|
||||
class Main {
|
||||
function void main() {
|
||||
// Creates and uses the list (2,3,5).
|
||||
var List v;
|
||||
let v = List.new(5,null);
|
||||
let v = List.new(2,List.new(3,v));
|
||||
do v.print(); // prints 2 3 5
|
||||
do v.dispose(); // disposes the list
|
||||
return;
|
||||
}
|
||||
}
|
||||
15
projects/09/Square/Main.jack
Normal file
15
projects/09/Square/Main.jack
Normal file
@@ -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/09/Square/Main.jack
|
||||
|
||||
/** Initializes a new Square Dance game and starts running it. */
|
||||
class Main {
|
||||
function void main() {
|
||||
var SquareGame game;
|
||||
let game = SquareGame.new();
|
||||
do game.run();
|
||||
do game.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
108
projects/09/Square/Square.jack
Normal file
108
projects/09/Square/Square.jack
Normal file
@@ -0,0 +1,108 @@
|
||||
// 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/09/Square/Square.jack
|
||||
|
||||
/** Implements a graphical square. */
|
||||
class Square {
|
||||
|
||||
field int x, y; // screen location of the square's top-left corner
|
||||
field int size; // length of this square, in pixels
|
||||
|
||||
/** Constructs 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 the square on the screen. */
|
||||
method void draw() {
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawRectangle(x, y, x + size, y + size);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Erases the square from the screen. */
|
||||
method void erase() {
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawRectangle(x, y, x + size, y + size);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Increments the square size by 2 pixels. */
|
||||
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. */
|
||||
method void decSize() {
|
||||
if (size > 2) {
|
||||
do erase();
|
||||
let size = size - 2;
|
||||
do draw();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Moves the square up by 2 pixels. */
|
||||
method void moveUp() {
|
||||
if (y > 1) {
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawRectangle(x, (y + size) - 1, x + size, y + size);
|
||||
let y = y - 2;
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawRectangle(x, y, x + size, y + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Moves the square down by 2 pixels. */
|
||||
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. */
|
||||
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. */
|
||||
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;
|
||||
}
|
||||
}
|
||||
79
projects/09/Square/SquareGame.jack
Normal file
79
projects/09/Square/SquareGame.jack
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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/09/Square/SquareGame.jack
|
||||
|
||||
/**
|
||||
* Implements the Square Dance 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() {
|
||||
// Creates a 30 by 30 pixels square and positions it at the top-left
|
||||
// of the screen.
|
||||
let square = Square.new(0, 0, 30);
|
||||
let direction = 0; // initial state is no movement
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user