module main;
import std.stdio;
import std.random;
import std.process;
import core.thread;
class Tetris
{
private BlockMap fb;
private ControlBlock cb;
private size_t _cbx;
private size_t _cby;
private int fallCount;
public bool fastFall;
private Random r;
private bool _gameover;
public @property const(BlockMap) fieldBlock(){ return cast(const(BlockMap))fb; }
public @property const(BlockMap) controlBlock(){ return cast(const(BlockMap))cb; }
public @property size_t cbx(){ return _cbx; }
public @property size_t cby(){ return _cby; }
public @property bool gameovar(){ return _gameover; }
public this()
{
this.fb = new BlockMap(10, 24);
this.r.seed(unpredictableSeed);
}
public void forwardTime()
{
if(_gameover == true) return;
fallCount++;
if(fallCount >= (fastFall ? 1 : 10))
{
fall();
fallCount = 0;
}
if(cb is null)
{
lineBreak();
setControlBlock();
}
}
private void lineBreak()
{
x: foreach(size_t x; 0..fb.x)
{
foreach(size_t y; 0..fb.y)
{
if(fb[x, y] == false) continue x;
}
foreach(size_t y; 0..fb.y)
{
fb[x, y] = false;
}
}
}
private void setControlBlock()
{
cb = ControlBlock.basicOminoFactory(r.front());
_cbx = fb.x / 2 - cb.x / 2;
_cby = 4 - cb.y;
_gameover = collideJudge();
}
private void fix()
{
foreach(size_t x; 0..cb.x)
{
foreach(size_t y; 0..cb.y)
{
if(cb[x, y] == true) fb[_cbx + x, _cby + y] = true;
}
}
cb = null;
}
private bool collideJudge()
{
foreach(size_t x; 0..cb.x)
{
foreach(size_t y; 0..cb.y)
{
if(_cbx + x < 0 || _cbx + x >= fb.x || _cby + y < 0 || _cby + y >= fb.y) return true;
if(cb[x, y] == true && fb[_cbx + x, _cby + y] == true) return true;
}
}
return false;
}
private void fall()
{
_cby++;
if(collideJudge == true)
{
_cby--;
fix();
}
}
public void rightMove()
{
_cbx++;
if(collideJudge == true) _cbx--;
}
public void leftMove()
{
_cbx--;
if(collideJudge == true) _cbx++;
}
public void rightTurn()
{
cb.rightTurn();
if(collideJudge == true) cb.leftTurn();
}
public void leftTurn()
{
cb.leftTurn();
if(collideJudge == true) cb.rightTurn();
}
}
class BlockMap
{
public const size_t x;
public const size_t y;
private bool[] bm;
public this(size_t x, size_t y, bool[][] bm = null)
{
this.x = x;
this.y = y;
this.bm = new bool[x * y];
if(bm !is null)
{
foreach(size_t ix; 0..bm.length)
{
foreach(size_t iy; 0..bm[ix].length)
{
this[ix, iy] = bm[ix][iy];
}
}
}
}
public bool opIndexAssign(bool value, size_t x, size_t y)
{
return bm[this.y * x + y] = value;
}
public bool opIndex(size_t x, size_t y) const
{
return bm[this.y * x + y];
}
}
class ControlBlock
{
private BlockMap[] cbList;
private size_t index;
public this(BlockMap[] cbList...)
{
this.cbList = cbList;
}
alias presentControlBlock this;
public @property BlockMap presentControlBlock()
{
return cbList[index];
}
public void rightTurn()
{
index++;
if(index >= cbList.length) index = 0;
}
public void leftTurn()
{
index--;
if(index < 0) index = cbList.length;
}
public static ControlBlock basicOminoFactory(int index)
{
BlockMap[] bmList;
final switch(index % 1)
{
case 0:
bmList = new BlockMap[2];
bmList[0] = new BlockMap(4, 4, [[0,0,1,0],[0,0,1,0],[0,0,1,0],[0,0,1,0]]);
bmList[1] = new BlockMap(4, 4, [[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
break;
}
return new ControlBlock(bmList);
}
}
class ConsoleUI
{
public Tetris t;
public void show()
{
char[] str;
str ~= "\f";
foreach(size_t y; 0..t.fieldBlock.y)
{
foreach(size_t x; 0..t.fieldBlock.x)
{
size_t cbx = x - t.cbx;
size_t cby = y - t.cby;
size_t cbxt = t.controlBlock.x;
size_t cbyt = t.controlBlock.y;
if(t.fieldBlock[x, y] == true)
{
str ~= "[]";
}
else if(!(cbx < 0 || cbx >= cbxt || cby < 0 || cby >= cbyt) && t.controlBlock[cbx, cby] == true)
{
str ~= "[]";
}
else
{
str ~= " ";
}
}
str ~= "\n";
}
stdout.rawWrite(str);
}
}
void main()
{
ConsoleUI cui = new ConsoleUI();
cui.t = new Tetris();
while(true)
{
cui.t.forwardTime();
cui.show();
if(cui.t.gameovar == true) break;
Thread.sleep(1000000);
}
}
bW9kdWxlIG1haW47CgppbXBvcnQgc3RkLnN0ZGlvOwppbXBvcnQgc3RkLnJhbmRvbTsKaW1wb3J0IHN0ZC5wcm9jZXNzOwppbXBvcnQgY29yZS50aHJlYWQ7CgpjbGFzcyBUZXRyaXMKewoJcHJpdmF0ZSBCbG9ja01hcCBmYjsKCXByaXZhdGUgQ29udHJvbEJsb2NrIGNiOwoJcHJpdmF0ZSBzaXplX3QgX2NieDsKCXByaXZhdGUgc2l6ZV90IF9jYnk7Cglwcml2YXRlIGludCBmYWxsQ291bnQ7CglwdWJsaWMgYm9vbCBmYXN0RmFsbDsKCXByaXZhdGUgUmFuZG9tIHI7Cglwcml2YXRlIGJvb2wgX2dhbWVvdmVyOwoKCXB1YmxpYyBAcHJvcGVydHkgY29uc3QoQmxvY2tNYXApIGZpZWxkQmxvY2soKXsgcmV0dXJuIGNhc3QoY29uc3QoQmxvY2tNYXApKWZiOyB9CglwdWJsaWMgQHByb3BlcnR5IGNvbnN0KEJsb2NrTWFwKSBjb250cm9sQmxvY2soKXsgcmV0dXJuIGNhc3QoY29uc3QoQmxvY2tNYXApKWNiOyB9CglwdWJsaWMgQHByb3BlcnR5IHNpemVfdCBjYngoKXsgcmV0dXJuIF9jYng7IH0KCXB1YmxpYyBAcHJvcGVydHkgc2l6ZV90IGNieSgpeyByZXR1cm4gX2NieTsgfQoJcHVibGljIEBwcm9wZXJ0eSBib29sIGdhbWVvdmFyKCl7IHJldHVybiBfZ2FtZW92ZXI7IH0KCglwdWJsaWMgdGhpcygpCgl7CgkJdGhpcy5mYiA9IG5ldyBCbG9ja01hcCgxMCwgMjQpOwoJCXRoaXMuci5zZWVkKHVucHJlZGljdGFibGVTZWVkKTsKCX0KCglwdWJsaWMgdm9pZCBmb3J3YXJkVGltZSgpCgl7CgkJaWYoX2dhbWVvdmVyID09IHRydWUpIHJldHVybjsKCQlmYWxsQ291bnQrKzsKCQlpZihmYWxsQ291bnQgPj0gKGZhc3RGYWxsID8gMSA6IDEwKSkKCQl7CgkJCWZhbGwoKTsKCQkJZmFsbENvdW50ID0gMDsKCQl9CgkJaWYoY2IgaXMgbnVsbCkKCQl7CgkJCWxpbmVCcmVhaygpOwoJCQlzZXRDb250cm9sQmxvY2soKTsKCQl9Cgl9CgoJcHJpdmF0ZSB2b2lkIGxpbmVCcmVhaygpCgl7CgkJeDogZm9yZWFjaChzaXplX3QgeDsgMC4uZmIueCkKCQl7CgkJCWZvcmVhY2goc2l6ZV90IHk7IDAuLmZiLnkpCgkJCXsKCQkJCWlmKGZiW3gsIHldID09IGZhbHNlKSBjb250aW51ZSB4OwoJCQl9CgkJCWZvcmVhY2goc2l6ZV90IHk7IDAuLmZiLnkpCgkJCXsKCQkJCWZiW3gsIHldID0gZmFsc2U7CgkJCX0KCQl9Cgl9CgoJcHJpdmF0ZSB2b2lkIHNldENvbnRyb2xCbG9jaygpCgl7CgkJY2IgPSBDb250cm9sQmxvY2suYmFzaWNPbWlub0ZhY3Rvcnkoci5mcm9udCgpKTsKCQlfY2J4ID0gZmIueCAvIDIgLSBjYi54IC8gMjsKCQlfY2J5ID0gNCAtIGNiLnk7CgkJX2dhbWVvdmVyID0gY29sbGlkZUp1ZGdlKCk7Cgl9CgoJcHJpdmF0ZSB2b2lkIGZpeCgpCgl7CgkJZm9yZWFjaChzaXplX3QgeDsgMC4uY2IueCkKCQl7CgkJCWZvcmVhY2goc2l6ZV90IHk7IDAuLmNiLnkpCgkJCXsKCQkJCWlmKGNiW3gsIHldID09IHRydWUpIGZiW19jYnggKyB4LCBfY2J5ICsgeV0gPSB0cnVlOwoJCQl9CgkJfQoJCWNiID0gbnVsbDsKCX0KCglwcml2YXRlIGJvb2wgY29sbGlkZUp1ZGdlKCkKCXsKCQlmb3JlYWNoKHNpemVfdCB4OyAwLi5jYi54KQoJCXsKCQkJZm9yZWFjaChzaXplX3QgeTsgMC4uY2IueSkKCQkJewoJCQkJaWYoX2NieCArIHggPCAwIHx8IF9jYnggKyB4ID49IGZiLnggfHwgX2NieSArIHkgPCAwIHx8IF9jYnkgKyB5ID49IGZiLnkpIHJldHVybiB0cnVlOwoJCQkJaWYoY2JbeCwgeV0gPT0gdHJ1ZSAmJiBmYltfY2J4ICsgeCwgX2NieSArIHldID09IHRydWUpIHJldHVybiB0cnVlOwoJCQl9CgkJfQoJCXJldHVybiBmYWxzZTsKCX0KCglwcml2YXRlIHZvaWQgZmFsbCgpCgl7CgkJX2NieSsrOwoJCWlmKGNvbGxpZGVKdWRnZSA9PSB0cnVlKQoJCXsKCQkJX2NieS0tOwoJCQlmaXgoKTsKCQl9Cgl9CgoJcHVibGljIHZvaWQgcmlnaHRNb3ZlKCkKCXsKCQlfY2J4Kys7CgkJaWYoY29sbGlkZUp1ZGdlID09IHRydWUpIF9jYngtLTsKCX0KCglwdWJsaWMgdm9pZCBsZWZ0TW92ZSgpCgl7CgkJX2NieC0tOwoJCWlmKGNvbGxpZGVKdWRnZSA9PSB0cnVlKSBfY2J4Kys7Cgl9CgoJcHVibGljIHZvaWQgcmlnaHRUdXJuKCkKCXsKCQljYi5yaWdodFR1cm4oKTsKCQlpZihjb2xsaWRlSnVkZ2UgPT0gdHJ1ZSkgY2IubGVmdFR1cm4oKTsKCX0KCglwdWJsaWMgdm9pZCBsZWZ0VHVybigpCgl7CgkJY2IubGVmdFR1cm4oKTsKCQlpZihjb2xsaWRlSnVkZ2UgPT0gdHJ1ZSkgY2IucmlnaHRUdXJuKCk7Cgl9Cn0KCmNsYXNzIEJsb2NrTWFwCnsKCXB1YmxpYyBjb25zdCBzaXplX3QgeDsKCXB1YmxpYyBjb25zdCBzaXplX3QgeTsKCXByaXZhdGUgYm9vbFtdIGJtOwoKCXB1YmxpYyB0aGlzKHNpemVfdCB4LCBzaXplX3QgeSwgYm9vbFtdW10gYm0gPSBudWxsKQoJewoJCXRoaXMueCA9IHg7CgkJdGhpcy55ID0geTsKCQl0aGlzLmJtID0gbmV3IGJvb2xbeCAqIHldOwoKCQlpZihibSAhaXMgbnVsbCkKCQl7CgkJCWZvcmVhY2goc2l6ZV90IGl4OyAwLi5ibS5sZW5ndGgpCgkJCXsKCQkJCWZvcmVhY2goc2l6ZV90IGl5OyAwLi5ibVtpeF0ubGVuZ3RoKQoJCQkJewoJCQkJCXRoaXNbaXgsIGl5XSA9IGJtW2l4XVtpeV07CgkJCQl9CgkJCX0KCQl9Cgl9CgoJcHVibGljIGJvb2wgb3BJbmRleEFzc2lnbihib29sIHZhbHVlLCBzaXplX3QgeCwgc2l6ZV90IHkpCgl7CgkJcmV0dXJuIGJtW3RoaXMueSAqIHggKyB5XSA9IHZhbHVlOwoJfQoKCXB1YmxpYyBib29sIG9wSW5kZXgoc2l6ZV90IHgsIHNpemVfdCB5KSBjb25zdAoJewoJCXJldHVybiBibVt0aGlzLnkgKiB4ICsgeV07Cgl9Cn0KCmNsYXNzIENvbnRyb2xCbG9jawp7Cglwcml2YXRlIEJsb2NrTWFwW10gY2JMaXN0OwoJcHJpdmF0ZSBzaXplX3QgaW5kZXg7CgoJcHVibGljIHRoaXMoQmxvY2tNYXBbXSBjYkxpc3QuLi4pCgl7CgkJdGhpcy5jYkxpc3QgPSBjYkxpc3Q7Cgl9CgoJYWxpYXMgcHJlc2VudENvbnRyb2xCbG9jayB0aGlzOwoJcHVibGljIEBwcm9wZXJ0eSBCbG9ja01hcCBwcmVzZW50Q29udHJvbEJsb2NrKCkKCXsKCQlyZXR1cm4gY2JMaXN0W2luZGV4XTsKCX0KCglwdWJsaWMgdm9pZCByaWdodFR1cm4oKQoJewoJCWluZGV4Kys7CgkJaWYoaW5kZXggPj0gY2JMaXN0Lmxlbmd0aCkgaW5kZXggPSAwOyAKCX0KCglwdWJsaWMgdm9pZCBsZWZ0VHVybigpCgl7CgkJaW5kZXgtLTsKCQlpZihpbmRleCA8IDApIGluZGV4ID0gY2JMaXN0Lmxlbmd0aDsKCX0KCglwdWJsaWMgc3RhdGljIENvbnRyb2xCbG9jayBiYXNpY09taW5vRmFjdG9yeShpbnQgaW5kZXgpCgl7CgkJQmxvY2tNYXBbXSBibUxpc3Q7CgkJZmluYWwgc3dpdGNoKGluZGV4ICUgMSkKCQl7CgkJCWNhc2UgMDoKCQkJCWJtTGlzdCA9IG5ldyBCbG9ja01hcFsyXTsKCQkJCWJtTGlzdFswXSA9IG5ldyBCbG9ja01hcCg0LCA0LCBbWzAsMCwxLDBdLFswLDAsMSwwXSxbMCwwLDEsMF0sWzAsMCwxLDBdXSk7CgkJCQlibUxpc3RbMV0gPSBuZXcgQmxvY2tNYXAoNCwgNCwgW1swLDAsMCwwXSxbMSwxLDEsMV0sWzAsMCwwLDBdLFswLDAsMCwwXV0pOwoJCQkJYnJlYWs7CgkJfQoJCXJldHVybiBuZXcgQ29udHJvbEJsb2NrKGJtTGlzdCk7Cgl9Cn0KCmNsYXNzIENvbnNvbGVVSQp7CglwdWJsaWMgVGV0cmlzIHQ7CgoJcHVibGljIHZvaWQgc2hvdygpCgl7CgkJY2hhcltdIHN0cjsKCQlzdHIgfj0gIlxmIjsKCQlmb3JlYWNoKHNpemVfdCB5OyAwLi50LmZpZWxkQmxvY2sueSkKCQl7CgkJCWZvcmVhY2goc2l6ZV90IHg7IDAuLnQuZmllbGRCbG9jay54KQoJCQl7CgkJCQlzaXplX3QgY2J4ID0geCAtIHQuY2J4OwoJCQkJc2l6ZV90IGNieSA9IHkgLSB0LmNieTsKCQkJCXNpemVfdCBjYnh0ID0gdC5jb250cm9sQmxvY2sueDsKCQkJCXNpemVfdCBjYnl0ID0gdC5jb250cm9sQmxvY2sueTsKCQkJCWlmKHQuZmllbGRCbG9ja1t4LCB5XSA9PSB0cnVlKQoJCQkJewoJCQkJCXN0ciB+PSAiW10iOwoJCQkJfQoJCQkJZWxzZSBpZighKGNieCA8IDAgfHwgY2J4ID49IGNieHQgfHwgY2J5IDwgMCB8fCBjYnkgPj0gY2J5dCkgJiYgdC5jb250cm9sQmxvY2tbY2J4LCBjYnldID09IHRydWUpCgkJCQl7CgkJCQkJc3RyIH49ICJbXSI7CgkJCQl9CgkJCQllbHNlCgkJCQl7CgkJCQkJc3RyIH49ICIgICI7CgkJCQl9CgkJCX0KCQkJc3RyIH49ICJcbiI7CgkJfQoJCXN0ZG91dC5yYXdXcml0ZShzdHIpOwoJfQp9Cgp2b2lkIG1haW4oKQp7CglDb25zb2xlVUkgY3VpID0gbmV3IENvbnNvbGVVSSgpOwoJY3VpLnQgPSBuZXcgVGV0cmlzKCk7Cgl3aGlsZSh0cnVlKQoJewoJCWN1aS50LmZvcndhcmRUaW1lKCk7CgkJY3VpLnNob3coKTsKCQlpZihjdWkudC5nYW1lb3ZhciA9PSB0cnVlKSBicmVhazsKCQlUaHJlYWQuc2xlZXAoMTAwMDAwMCk7Cgl9Cn0K