aboutsummaryrefslogtreecommitdiff
path: root/K
diff options
context:
space:
mode:
Diffstat (limited to 'K')
-rw-r--r--K/Board.jack333
-rw-r--r--K/K.md9
-rw-r--r--K/KGame.jack63
-rw-r--r--K/Main.jack16
4 files changed, 421 insertions, 0 deletions
diff --git a/K/Board.jack b/K/Board.jack
new file mode 100644
index 0000000..d598093
--- /dev/null
+++ b/K/Board.jack
@@ -0,0 +1,333 @@
+/**
+- K: a 2048 clone written in Jack language
+- Coursework for Nand2Tetris (http://nand2tetris.org/)
+- Author: Yuchen Pei (me@ypei.me)
+- This file: the board model for the K game
+*/
+class Board {
+ field Array grid;
+ field int nTurn, seed, status; // status: 0: begin game; 1: in game; 2: lose; 3: win;
+ static String boardBar, strLost, strCont, strGameOver, strWon, strTurn;
+
+ constructor Board new() {
+ var int i;
+ let grid = Array.new(4);
+ let i = 0;
+ while (i < 4) {
+ let grid[i] = Array.new(4);
+ let i = i + 1;
+ }
+ do initBoard();
+ let seed = 0;
+ return this;
+ }
+
+ function void init() {
+ let boardBar = "+----+";
+ let strLost = "You lost!";
+ let strWon = "You won!";
+ let strCont = "Press any key to continue";
+ let strGameOver = "Game over!";
+ let strTurn = "Turn: ";
+ return;
+ }
+
+ method void initBoard() {
+ var int i, j;
+ var Array t;
+ let i = 0;
+ while (i < 4) {
+ let j = 0;
+ let t = grid[i];
+ while (j < 4) {
+ let t[j] = 32;
+ let j = j + 1;
+ }
+ let i = i + 1;
+ }
+ let t = grid[0];
+ let t[0] = 65;
+ let nTurn = 0;
+ let status = 0;
+ return;
+ }
+
+
+ method void transpose() {
+ do exch(0, 1);
+ do exch(0, 2);
+ do exch(0, 3);
+ do exch(1, 2);
+ do exch(1, 3);
+ do exch(2, 3);
+ return;
+ }
+
+ method void exch(int i, int j){
+ var int t;
+ var Array s1, s2;
+ let s1 = grid[i];
+ let s2 = grid[j];
+ let t = s1[j];
+ let s1[j] = s2[i];
+ let s2[i] = t;
+ return;
+ }
+
+ method void align(Array xs, boolean left){
+ var int i, j;
+ let i = 0;
+ let j = 0;
+ if (left) {
+ while (i < 4) {
+ if (xs[i] > 64) {
+ let xs[j] = xs[i];
+ let j = j + 1;
+ }
+ let i = i + 1;
+ }
+ while (j < 4) {
+ let xs[j] = 32;
+ let j = j + 1;
+ }
+ } else {
+ while (i < 4) {
+ if (xs[3 - i] > 64) {
+ let xs[3 - j] = xs[3 - i];
+ let j = j + 1;
+ }
+ let i = i + 1;
+ }
+ while (j < 4) {
+ let xs[3 - j] = 32;
+ let j = j + 1;
+ }
+ }
+ return;
+ }
+
+ method void reduce(Array xs, boolean left){
+ if ((xs[0] = xs[1]) & (xs[2] = xs[3]) & (xs[0] > 64) & (xs[2] > 64)) {
+ if (left) {
+ let xs[0] = xs[0] + 1;
+ let xs[1] = xs[2] + 1;
+ let xs[2] = 32;
+ let xs[3] = 32;
+ } else {
+ let xs[3] = xs[3] + 1;
+ let xs[2] = xs[1] + 1;
+ let xs[1] = 32;
+ let xs[0] = 32;
+ }
+ return;
+ }
+ if ((xs[0] = xs[1]) & (xs[0] > 64)) {
+ if (left) {
+ let xs[0] = xs[0] + 1;
+ let xs[1] = xs[2];
+ let xs[2] = xs[3];
+ let xs[3] = 32;
+ } else {
+ let xs[1] = xs[1] + 1;
+ let xs[0] = 32;
+ }
+ return;
+ }
+ if ((xs[2] = xs[3]) & (xs[2] > 64)) {
+ if (left) {
+ let xs[2] = xs[2] + 1;
+ let xs[3] = 32;
+ } else {
+ let xs[3] = xs[3] + 1;
+ let xs[2] = xs[1];
+ let xs[1] = xs[0];
+ let xs[0] = 32;
+ }
+ return;
+ }
+ if ((xs[1] = xs[2]) & (xs[1] > 64)) {
+ if (left) {
+ let xs[1] = xs[1] + 1;
+ let xs[2] = xs[3];
+ let xs[3] = 32;
+ } else {
+ let xs[2] = xs[2] + 1;
+ let xs[1] = xs[0];
+ let xs[0] = 32;
+ }
+ return;
+ }
+ return;
+ }
+
+ method void addTile(){
+ var Array t;
+ var int r, c, parity, newTile;
+ /*
+ let t = grid[1];
+ if (t[1] = 32) {
+ let t[1] = 65;
+ }
+ */
+
+ if (~(status = 1)) {
+ return;
+ }
+
+ let seed = seed * 25173 + 13849;
+ if (seed < 0) {
+ let seed = - seed;
+ }
+
+ if (seed - (seed / 2 * 2) = 0) {
+ let parity = 1;
+ } else {
+ let parity = -1;
+ }
+
+ let seed = seed - (seed / 16 * 16);
+ let r = seed / 4;
+ let c = seed - (4 * r);
+ let t = grid[r];
+ let newTile = 65;
+
+ while (t[c] > 64){
+ let seed = seed + parity;
+ if (seed < 0) {
+ let seed = 15;
+ }
+ let seed = seed - (seed / 16 * 16);
+ let r = seed / 4;
+ let c = seed - (4 * r);
+ let t = grid[r];
+ let newTile = 131 - newTile;
+ }
+ let t[c] = newTile;
+ return;
+ }
+
+ method void transform(char dir){
+ var boolean isVertical, left;
+ var int i;
+ if ((dir = 0) | (dir = 1)) {
+ let left = true;
+ } else {
+ let left = false;
+ }
+ if ((dir = 0) | (dir = 2)) {
+ let isVertical = false;
+ } else {
+ let isVertical = true;
+ }
+ if (isVertical) {
+ do transpose();
+ }
+ let i = 0;
+ while (i < 4) {
+ do align(grid[i], left);
+ do reduce(grid[i], left);
+ let i = i + 1;
+ }
+ if (isVertical) {
+ do transpose();
+ }
+ return;
+ }
+
+ method void next(int dir){
+ let nTurn = nTurn + 1;
+ do transform(dir);
+ do updateStatus();
+ return;
+ }
+
+ method int getStatus(){
+ return status;
+ }
+
+ method void setStatus(int x){
+ let status = x;
+ return;
+ }
+
+ method void updateStatus(){
+ var int i, j;
+ var Array r;
+ let i = 0;
+ while (i < 4) {
+ let r = grid[i];
+ let j = 0;
+ while (j < 4) {
+ if (r[j] = 75) {
+ let status = 3;
+ return;
+ }
+ if (r[j] = 32) {
+ let status = 1;
+ return;
+ }
+ let j = j + 1;
+ }
+ let i = i + 1;
+ }
+ let status = 2;
+ return;
+ }
+
+ method void draw(){
+ var int r, c, i, j;
+ var Array t;
+ let r = 9;
+ let c = 30;
+
+ if (status = 0) {
+ do Output.moveCursor(r - 1, c - 1);
+ do Output.printChar(75);
+ do Output.moveCursor(r + 1, c - 1);
+ do Output.printString(strCont);
+ } else { if (status = 2) {
+ do Output.moveCursor(r - 1, c - 1);
+ do Output.printString(strGameOver);
+ do Output.moveCursor(r + 1, c - 1);
+ do Output.printString(strLost);
+ do Output.moveCursor(r + 3, c - 1);
+ do Output.printString(strCont);
+ } else { if (status = 3) {
+ do Output.moveCursor(r - 1, c - 1);
+ do Output.printString(strGameOver);
+ do Output.moveCursor(r + 1, c - 1);
+ do Output.printString(strWon);
+ do Output.moveCursor(r + 3, c - 1);
+ do Output.printString(strCont);
+ } else {
+ do Output.moveCursor(r - 1, c - 1);
+ do Output.printString(boardBar);
+ do Output.moveCursor(r + 4, c - 1);
+ do Output.printString(boardBar);
+
+ let i = 0;
+ while (i < 4) {
+ let j = 0;
+ do Output.moveCursor(r + i, c - 1);
+ do Output.printChar(124); // 124 is |
+ let t = grid[i];
+ while (j < 4) {
+ do Output.printChar(t[j]);
+ let j = j + 1;
+ }
+ do Output.printChar(124);
+ let i = i + 1;
+ }
+
+ do Output.moveCursor(r + 6, c - 2);
+ do Output.printString(strTurn);
+ do Output.printInt(nTurn);
+ }}}
+ return;
+ }
+
+ method void dispose() {
+ do Memory.deAlloc(this);
+ return;
+ }
+}
diff --git a/K/K.md b/K/K.md
new file mode 100644
index 0000000..0130662
--- /dev/null
+++ b/K/K.md
@@ -0,0 +1,9 @@
+K is a clone of 2048. Instead of aiming for the 11th power of 2, the goal of this game is to reach the 11th letter in the alphabet, which is 'K'.
+Written in Jack, a minimal OOP language created by creators of the [Nand2Tetris course](http://nand2tetris.org).
+
+Controls:
+- Arrow keys to move the letters
+- R to restart
+- Q to quit
+
+Caveats. The pseudorandom number generator is far from industrial strength, so you may notice new letters are more likely to spawn in certain locations than others...
diff --git a/K/KGame.jack b/K/KGame.jack
new file mode 100644
index 0000000..277afaf
--- /dev/null
+++ b/K/KGame.jack
@@ -0,0 +1,63 @@
+/**
+- K: a 2048 clone written in Jack language
+- Coursework for Nand2Tetris (http://nand2tetris.org/)
+- Author: Yuchen Pei (me@ypei.me)
+- This file: the game I/O for the K game
+*/
+class KGame{
+ field Board board;
+
+ constructor KGame new() {
+ let board = Board.new();
+ do board.draw();
+ return this;
+ }
+
+ method void dispose() {
+ do board.dispose();
+ do Memory.deAlloc(this);
+ return;
+ }
+
+ method void run() {
+ var int key, key1, st;
+ var boolean exit;
+ let exit = false;
+ while (~exit) {
+ let st = board.getStatus();
+ let key = 0;
+ while (key = 0) {
+ let key = Keyboard.keyPressed();
+ }
+ let key1 = key;
+ while (~(key1 = 0)) {
+ let key1 = Keyboard.keyPressed();
+ }
+ if (key = 81) {
+ let exit = true;
+ } else { if ((st = 0)) {
+ do Screen.clearScreen();
+ do board.setStatus(1);
+ do board.draw();
+ } else { if ((st = 2) | (st = 3)) {
+ do Screen.clearScreen();
+ do board.setStatus(0);
+ do board.draw();
+ do board.initBoard();
+ } else { if (key = 82) { // r for restart
+ do Screen.clearScreen();
+ do board.initBoard();
+ do board.draw();
+ } else { if ((key > 129) & (key < 134)) {
+ do Screen.clearScreen();
+ do board.next(key - 130);
+ do board.draw();
+ do Sys.wait(300);
+ do Screen.clearScreen();
+ do board.addTile();
+ do board.draw();
+ }}}}}
+ }
+ return;
+ }
+}
diff --git a/K/Main.jack b/K/Main.jack
new file mode 100644
index 0000000..c1b6a79
--- /dev/null
+++ b/K/Main.jack
@@ -0,0 +1,16 @@
+/**
+- K: a 2048 clone written in Jack language
+- Coursework for Nand2Tetris (http://nand2tetris.org/)
+- Author: Yuchen Pei (me@ypei.me)
+- This file: the main file for the K game
+*/
+class Main {
+ function void main() {
+ var KGame game;
+ do Board.init();
+ let game = KGame.new();
+ do game.run();
+ do game.dispose();
+ return;
+ }
+}