#D2048 The 2048 written in D.
##How to use
- Place file as follow:
 
d2048Root/
  |-source/
  | \- d2048/
  |    |- core.d
  |    \- game.d
  \- app.d
- Execute 
dub initat d2048Root - Execute 
dub 
| import std.stdio; | |
| import std.string; | |
| import d2048.game; | |
| void main(){ | |
| D2048Game d2048 = new D2048Game; | |
| d2048.startGame; | |
| } | 
| module d2048.core; | |
| import std.stdio, | |
| std.typecons, | |
| std.algorithm.iteration, | |
| std.random, | |
| std.range; | |
| class D2048Core{ | |
| alias Position = Tuple!(int, "x", int, "y"); | |
| static defaultWorldSize = Position(4, 4); | |
| private int worldX, | |
| worldY; | |
| private int[][] world; | |
| public int score; | |
| this(){ | |
| this(defaultWorldSize); | |
| } | |
| this(Position worldSize){ | |
| worldX = worldSize.x; | |
| worldY = worldSize.y; | |
| world.length = worldY; | |
| init; | |
| } | |
| void init(){ | |
| foreach(ref row; world){ | |
| row.length = worldX; | |
| } | |
| } | |
| bool check(int[] array){ | |
| int prev = -1; | |
| if(array.filter!(e => e != 0).array == null){ | |
| return false; | |
| } | |
| if(array[0] != 0){ | |
| if(array[1..$].filter!(e => e != 0).array == null) | |
| return false; | |
| } | |
| foreach(i, n; array){ | |
| if(prev == 0) | |
| return true; | |
| else if(n == prev) | |
| return true; | |
| prev = n; | |
| } | |
| return false; | |
| } | |
| bool checkLeft(){ | |
| foreach(row; world) | |
| if(check(row)) | |
| return true; | |
| return false; | |
| } | |
| bool checkRight(){ | |
| foreach(row; world) | |
| if(check(arrayReverse(row))) | |
| return true; | |
| return false; | |
| } | |
| bool checkDown(){ | |
| foreach(i; worldX.iota){ | |
| int[] col = worldY.iota.map!(j => world[j][i]).array; | |
| if(check(arrayReverse(col))) | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool checkUp(){ | |
| foreach(i; worldX.iota){ | |
| int[] col = worldY.iota.map!(j => world[j][i]).array; | |
| if(check(col)) | |
| return true; | |
| } | |
| return false; | |
| } | |
| int[] deleteZero(int[] row){ | |
| int[] zeros; | |
| zeros.length = row.filter!"a == 0".array.length; | |
| row = row.filter!"a != 0".array ~ zeros; | |
| return row; | |
| } | |
| int[] move(int[] row){ | |
| int prev = -1; | |
| row = deleteZero(row); | |
| foreach(i, n; row){ | |
| if(n == prev){ | |
| row[i] *= 2; | |
| row[i-1] = 0; | |
| row = deleteZero(row); | |
| prev = n * 2; | |
| score += row[i];//Add Score | |
| } else { | |
| prev = n; | |
| } | |
| } | |
| return row; | |
| } | |
| void moveLeft(){ | |
| foreach(ref row; world) | |
| row = move(row); | |
| } | |
| void moveRight(){ | |
| foreach(ref row; world) | |
| row = arrayReverse(row); | |
| moveLeft; | |
| foreach(ref row; world) | |
| row = arrayReverse(row); | |
| } | |
| void moveUp(){ | |
| int[][] cols = worldX.iota.map!(x => worldY.iota.map!(y => world[y][x]).array).array; | |
| foreach(ref col; cols) | |
| col = move(col); | |
| int[][] ws = worldY.iota.map!(y => worldX.iota.map!(x => cols[x][y]).array).array; | |
| world = ws; | |
| } | |
| void moveDown(){ | |
| world = arrayReverse(world); | |
| moveUp; | |
| world = arrayReverse(world); | |
| } | |
| bool gameOver(){ | |
| if(!checkLeft | |
| && !checkRight | |
| && !checkUp | |
| && !checkDown) | |
| return true; | |
| else | |
| return false; | |
| } | |
| void printWorld(){ | |
| foreach(row; world) | |
| writeln(row); | |
| } | |
| void spawnNewBlock(){ | |
| Position[] positions; | |
| Mt19937 gen; | |
| foreach(y; worldY.iota) | |
| foreach(x; worldX.iota){ | |
| if(world[y][x] == 0) | |
| positions ~= Position(x,y); | |
| } | |
| gen.seed(unpredictableSeed); | |
| ulong idx = gen.front % positions.length; | |
| Position newPosition = positions[idx]; | |
| gen.seed(unpredictableSeed); | |
| ulong N = gen.front % 100 + 1; | |
| int newPoint = 1 <= N && N < 75 ? 2 : 4; | |
| world[newPosition.y][newPosition.x] = newPoint; | |
| } | |
| T[] arrayReverse(T)(T[] base){ | |
| T[] rV; | |
| foreach_reverse(e; base) | |
| rV ~= e; | |
| return rV; | |
| } | |
| } | 
| module d2048.game; | |
| import std.stdio, | |
| std.string; | |
| import d2048.core; | |
| class D2048Game : D2048Core{ | |
| private ulong moves; | |
| this(){ | |
| score = 0; | |
| spawnNewBlock; | |
| spawnNewBlock; | |
| } | |
| void startGame(){ | |
| writeln("===================="); | |
| writeln("D 2048"); | |
| writeln("[inputs]"); | |
| writeln("l: left"); | |
| writeln("r: right"); | |
| writeln("u: up"); | |
| writeln("d: down"); | |
| writeln("===================="); | |
| while(!gameOver){ | |
| bool noTouch; | |
| printWorld; | |
| writeln("--------------------"); | |
| writeln("moves:", moves); | |
| writeln("score:", score); | |
| write("[input]=> "); | |
| string input = readln.chomp; | |
| switch(input){ | |
| case "l": | |
| moveLeft; | |
| break; | |
| case "r": | |
| moveRight; | |
| break; | |
| case "u": | |
| moveUp; | |
| break; | |
| case "d": | |
| moveDown; | |
| break; | |
| default: | |
| noTouch = true; | |
| break; | |
| } | |
| if(!noTouch){ | |
| spawnNewBlock; | |
| moves++; | |
| } | |
| } | |
| writeln("GAME OVER"); | |
| writeln("moves:", moves); | |
| writeln("score:", score); | |
| } | |
| } |