Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #import('dart:html');
- #import('dart:isolate');
- class BsIter implements Iterator<bool> {
- int value, idx = -1;
- BsIter(Bitset bs): value = bs.value << 1;
- bool next() => ((value >> ++idx) & 1) === 1;
- bool hasNext() => idx < TetrisArea.Col - 1;
- }
- class Bitset implements Iterable {
- int value;
- Bitset([this.value = 0]) {
- assert(value >> TetrisArea.Col == 0);
- }
- bool operator [](int X) {
- assert(X >= 0 && X < TetrisArea.Col);
- return ((value >> X) & 1) === 1;
- }
- void operator []=(int X, bool flag) {
- assert(X >= 0 && X < TetrisArea.Col);
- if (flag) {
- value |= 1 << X;
- } else {
- value &= ~(1 << X);
- }
- }
- BsIter iterator() => new BsIter(this);
- bool isAllSet() => value == ~(~0 << TetrisArea.Col);
- void setAll() { value = ~(~0 << TetrisArea.Col); }
- void clear() { value = 0; }
- }
- class Fields implements Iterable {
- List<Bitset> cont;
- Fields(): cont = new List<Bitset>(TetrisArea.Row) {
- for (int idx = 0; idx < TetrisArea.Row; ++idx)
- cont[idx] = new Bitset();
- }
- Bitset operator [](int idx) => cont[idx];
- bool contains(Position pos) => cont[pos.Y][pos.X];
- Iterator<Bitset> iterator() => cont.iterator();
- void setPos(Position pos) {
- cont[pos.Y][pos.X] = true;
- }
- bool canEraseLine() => cont.some((e) => e.isAllSet());
- void eraseAllCan() {
- if (!canEraseLine())
- return;
- List<Bitset> tmp = cont.filter((e) => !e.isAllSet());
- cont.setRange(TetrisArea.Row - tmp.length, tmp.length, tmp);
- for (int i = TetrisArea.Row - tmp.length; --i > 0;)
- cont[i].clear();
- }
- }
- class Position implements Hashable {
- int X, Y;
- Position(this.X, this.Y);
- Position operator +(Position rhs) {
- return new Position(X + rhs.X, Y + rhs.Y);
- }
- Position operator -(Position rhs) {
- return new Position(X - rhs.X, Y - rhs.Y);
- }
- int hashCode() => (X << 8) | Y;
- static Position from(Position rhs) => new Position(rhs.X, rhs.Y);
- bool isCollided(TetrisArea area) => X < 0
- || X >= TetrisArea.Col || Y >= TetrisArea.Row
- || area.points.contains(this);
- bool operator ==(Position rhs) {
- if (this === rhs) {
- return true;
- } else {
- return rhs != null && X == rhs.X && Y == rhs.Y;
- }
- }
- }
- class Shape {
- final List<List<Position>> points;
- final String color;
- const Shape(this.points, this.color);
- }
- class Tetro {
- List<Position> pos;
- Shape shape;
- int round;
- Tetro(this.shape, Position p) {
- this.pos = new List.from(shape.points[0]);
- for (int idx = 0; idx < this.pos.length; ++idx) {
- pos[idx] = pos[idx] + p;
- }
- this.round = 0;
- assert(pos != null);
- }
- bool tryMoveLeft(TetrisArea area) {
- pos.forEach((e) => --e.X);
- if (pos.every((e) => e.X >= 0 && !area.points.contains(e)))
- return true;
- pos.forEach((e) => ++e.X);
- return false;
- }
- bool tryMoveRight(TetrisArea area) {
- pos.forEach((e) => ++e.X);
- if (pos.every((e) => e.X < TetrisArea.Col && !area.points.contains(e)))
- return true;
- pos.forEach((e) => --e.X);
- return false;
- }
- bool tryMoveDown(TetrisArea area) {
- pos.forEach((e) => ++e.Y);
- if (pos.every((e) => e.Y < TetrisArea.Row && !area.points.contains(e)))
- return true;
- pos.forEach((e) => --e.Y);
- return false;
- }
- bool tryTurnLeft(TetrisArea area) {
- if (shape.points.length == 0)
- return false;
- int newR = round - 1 < 0 ? shape.points.length - 1 : round - 1;
- for (var idx = 0; idx != pos.length; ++idx) {
- pos[idx] = pos[idx] - shape.points[round][idx] + shape.points[newR][idx];
- if (pos[idx].isCollided(area)) {
- for (; idx >= 0; --idx)
- pos[idx] = pos[idx] + shape.points[round][idx] - shape.points[newR][idx];
- return false;
- }
- }
- round = newR;
- return true;
- }
- bool tryTurnRight(TetrisArea area) {
- if (shape.points.length == 0)
- return false;
- int newR = round + 1 == shape.points.length ? 0 : round + 1;
- for (var idx = 0; idx != pos.length; ++idx) {
- pos[idx] = pos[idx] - shape.points[round][idx] + shape.points[newR][idx];
- if (pos[idx].isCollided(area)) {
- for (; idx >= 0; --idx)
- pos[idx] = pos[idx] + shape.points[round][idx] - shape.points[newR][idx];
- return false;
- }
- }
- round = newR;
- return true;
- }
- bool isCollided(TetrisArea area) => pos.some((e) => e.isCollided(area));
- }
- class TetrisArea {
- static final Row = 20, Col = 10;
- static final TetroWidth = 20;
- List<Shape> shapes;
- CanvasRenderingContext2D context, preview;
- Timer tmr;
- Tetro current;
- Fields points;
- int rnd;
- TetrisArea(CanvasElement canvas, CanvasElement canvas1, this.shapes) {
- canvas.width = TetroWidth * Col;
- canvas.height = TetroWidth * Row;
- context = canvas.context2d;
- canvas1.height = canvas1.width = TetroWidth * 4;
- preview = canvas1.context2d;
- rnd = (Math.random() * shapes.length).toInt();
- current = new Tetro(shapes[rnd], new Position(0, 0));
- rnd = (Math.random() * shapes.length).toInt();
- points = new Fields();
- drawPreview();
- drawContext();
- }
- void Start() {
- tmr = new Timer.repeating(500, (Timer t) {
- if (!current.tryMoveDown(this)) {
- current.pos.forEach((e) { points.setPos(e); });
- points.eraseAllCan();
- current = new Tetro(shapes[rnd], new Position(0, 0));
- rnd = (Math.random() * shapes.length).toInt();
- drawPreview();
- if (current.isCollided(this))
- Stop();
- }
- drawContext();
- });
- document.on.keyPress.add(onKeyPress);
- }
- void onKeyPress(KeyboardEvent e) {
- bool needRedraw = false;
- switch (new String.fromCharCodes([e.keyCode]).toUpperCase()) {
- case 'W': needRedraw = current.tryTurnRight(this); break;
- case 'S': needRedraw = current.tryMoveDown(this); break;
- case 'A': needRedraw = current.tryMoveLeft(this); break;
- case 'D': needRedraw = current.tryMoveRight(this); break;
- case 'Q': needRedraw = current.tryTurnLeft(this); break;
- case 'E': needRedraw = current.tryTurnRight(this); break;
- case 'X': while (current.tryMoveDown(this)); needRedraw = true; break;
- }
- if (needRedraw)
- drawContext();
- }
- void Stop() {
- tmr.cancel();
- query("#text").innerHTML = 'Game Over!';
- document.on.keyPress.remove(onKeyPress);
- }
- void drawPreview() {
- preview.fillStyle = "BLACK";
- preview.fillRect(0, 0, TetroWidth * 4, TetroWidth * 4);
- preview.fillStyle = shapes[rnd].color;
- for (var e in shapes[rnd].points[0])
- preview.fillRect(e.X * TetroWidth + 1,
- e.Y * TetroWidth + 1, TetroWidth - 2, TetroWidth - 2);
- }
- void drawContext() {
- context.fillStyle = "BLACK";
- context.fillRect(0, 0, TetroWidth * Col, TetroWidth * Row);
- context.fillStyle = current.shape.color;
- for (var e in current.pos)
- context.fillRect(e.X * TetroWidth + 1,
- e.Y * TetroWidth + 1, TetroWidth - 2, TetroWidth - 2);
- context.fillStyle = "WHITE";
- for (var row = 0; row < Row; ++row) {
- for (var col = 0; col < Col; ++col) {
- if (points[row][col])
- context.fillRect(col * TetroWidth + 1, row * TetroWidth + 1,
- TetroWidth - 2, TetroWidth - 2);
- }
- }
- }
- }
- void main() {
- List<Shape> shapes = [
- new Shape([
- [new Position(0, 0), new Position(1, 0), new Position(2, 0), new Position(3, 0)],
- [new Position(1, 0), new Position(1, 1), new Position(1, 2), new Position(1, 3)]
- ], "RED"),
- new Shape([
- [new Position(0, 0), new Position(1, 0), new Position(1, 1), new Position(2, 1)],
- [new Position(1, 0), new Position(1, 1), new Position(0, 1), new Position(0, 2)]
- ], "YELLOW"),
- new Shape([
- [new Position(0, 1), new Position(1, 1), new Position(1, 0), new Position(2, 0)],
- [new Position(0, 0), new Position(0, 1), new Position(1, 1), new Position(1, 2)]
- ], "AQUA"),
- new Shape([
- [new Position(0, 0), new Position(1, 0), new Position(2, 0), new Position(0, 1)],
- [new Position(0, 0), new Position(1, 0), new Position(1, 1), new Position(1, 2)],
- [new Position(0, 1), new Position(1, 1), new Position(2, 1), new Position(2, 0)],
- [new Position(0, 0), new Position(0, 1), new Position(0, 2), new Position(1, 2)]
- ], "LIME"),
- new Shape([
- [new Position(0, 0), new Position(1, 0), new Position(2, 0), new Position(2, 1)],
- [new Position(1, 0), new Position(1, 1), new Position(1, 2), new Position(0, 2)],
- [new Position(0, 0), new Position(0, 1), new Position(1, 1), new Position(2, 1)],
- [new Position(0, 0), new Position(1, 0), new Position(0, 1), new Position(0, 2)]
- ], "PURPLE"),
- new Shape([
- [new Position(0, 0), new Position(1, 0), new Position(0, 1), new Position(1, 1)]
- ], "ORANGE")
- ];
- new TetrisArea(query("#canvas"), query('#canvas1'), shapes).Start();
- }
Advertisement
Add Comment
Please, Sign In to add comment