zhangsongcui

Tetris (Dart part)

Jul 9th, 2012
229
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 8.97 KB | None | 0 0
  1. #import('dart:html');
  2. #import('dart:isolate');
  3.  
  4. class BsIter implements Iterator<bool> {
  5.   int value, idx = -1;
  6.  
  7.   BsIter(Bitset bs): value = bs.value << 1;
  8.  
  9.   bool next() => ((value >> ++idx) & 1) === 1;
  10.   bool hasNext() => idx < TetrisArea.Col - 1;
  11. }
  12.  
  13. class Bitset implements Iterable {
  14.   int value;
  15.  
  16.   Bitset([this.value = 0]) {
  17.     assert(value >> TetrisArea.Col == 0);
  18.   }
  19.  
  20.   bool operator [](int X) {
  21.     assert(X >= 0 && X < TetrisArea.Col);
  22.     return ((value >> X) & 1) === 1;
  23.   }
  24.   void operator []=(int X, bool flag) {
  25.     assert(X >= 0 && X < TetrisArea.Col);
  26.     if (flag) {
  27.       value |= 1 << X;
  28.     } else {
  29.       value &= ~(1 << X);
  30.     }
  31.   }
  32.  
  33.   BsIter iterator() => new BsIter(this);
  34.   bool isAllSet() => value == ~(~0 << TetrisArea.Col);
  35.   void setAll() { value = ~(~0 << TetrisArea.Col); }
  36.   void clear() { value = 0; }
  37. }
  38.  
  39. class Fields implements Iterable {
  40.   List<Bitset> cont;
  41.  
  42.   Fields(): cont = new List<Bitset>(TetrisArea.Row) {
  43.     for (int idx = 0; idx < TetrisArea.Row; ++idx)
  44.       cont[idx] = new Bitset();
  45.   }
  46.  
  47.   Bitset operator [](int idx) => cont[idx];
  48.  
  49.   bool contains(Position pos) => cont[pos.Y][pos.X];
  50.  
  51.   Iterator<Bitset> iterator() => cont.iterator();
  52.   void setPos(Position pos) {
  53.     cont[pos.Y][pos.X] = true;
  54.   }
  55.  
  56.   bool canEraseLine() => cont.some((e) => e.isAllSet());
  57.  
  58.   void eraseAllCan() {
  59.     if (!canEraseLine())
  60.       return;
  61.     List<Bitset> tmp = cont.filter((e) => !e.isAllSet());
  62.     cont.setRange(TetrisArea.Row - tmp.length, tmp.length, tmp);
  63.     for (int i = TetrisArea.Row - tmp.length; --i > 0;)
  64.       cont[i].clear();
  65.   }
  66. }
  67.  
  68. class Position implements Hashable {
  69.   int X, Y;
  70.  
  71.   Position(this.X, this.Y);
  72.  
  73.   Position operator +(Position rhs) {
  74.     return new Position(X + rhs.X, Y + rhs.Y);
  75.   }
  76.  
  77.   Position operator -(Position rhs) {
  78.     return new Position(X - rhs.X, Y - rhs.Y);
  79.   }
  80.  
  81.   int hashCode() => (X << 8) | Y;
  82.  
  83.   static Position from(Position rhs) => new Position(rhs.X, rhs.Y);
  84.  
  85.   bool isCollided(TetrisArea area) => X < 0
  86.       || X >= TetrisArea.Col || Y >= TetrisArea.Row
  87.       || area.points.contains(this);
  88.  
  89.   bool operator ==(Position rhs) {
  90.      if (this === rhs) {
  91.        return true;
  92.      } else {
  93.        return rhs != null && X == rhs.X && Y == rhs.Y;
  94.      }
  95.   }
  96. }
  97.  
  98. class Shape {
  99.   final List<List<Position>> points;
  100.   final String color;
  101.  
  102.   const Shape(this.points, this.color);
  103. }
  104.  
  105. class Tetro {
  106.   List<Position> pos;
  107.   Shape shape;
  108.   int round;
  109.  
  110.   Tetro(this.shape, Position p) {
  111.     this.pos = new List.from(shape.points[0]);
  112.     for (int idx = 0; idx < this.pos.length; ++idx) {
  113.       pos[idx] = pos[idx] + p;
  114.     }
  115.     this.round = 0;
  116.     assert(pos != null);
  117.   }
  118.  
  119.   bool tryMoveLeft(TetrisArea area) {
  120.     pos.forEach((e) => --e.X);
  121.     if (pos.every((e) => e.X >= 0 && !area.points.contains(e)))
  122.       return true;
  123.     pos.forEach((e) => ++e.X);
  124.     return false;
  125.   }
  126.  
  127.   bool tryMoveRight(TetrisArea area) {
  128.     pos.forEach((e) => ++e.X);
  129.     if (pos.every((e) => e.X < TetrisArea.Col && !area.points.contains(e)))
  130.       return true;
  131.     pos.forEach((e) => --e.X);
  132.     return false;
  133.   }
  134.  
  135.   bool tryMoveDown(TetrisArea area) {
  136.     pos.forEach((e) => ++e.Y);
  137.     if (pos.every((e) => e.Y < TetrisArea.Row && !area.points.contains(e)))
  138.       return true;
  139.     pos.forEach((e) => --e.Y);
  140.     return false;
  141.   }
  142.  
  143.   bool tryTurnLeft(TetrisArea area) {
  144.     if (shape.points.length == 0)
  145.       return false;
  146.     int newR = round - 1 < 0 ? shape.points.length - 1 : round - 1;
  147.     for (var idx = 0; idx != pos.length; ++idx) {
  148.       pos[idx] = pos[idx] - shape.points[round][idx] + shape.points[newR][idx];
  149.       if (pos[idx].isCollided(area)) {
  150.         for (; idx >= 0; --idx)
  151.           pos[idx] = pos[idx] + shape.points[round][idx] - shape.points[newR][idx];
  152.         return false;
  153.       }
  154.     }
  155.     round = newR;
  156.     return true;
  157.   }
  158.  
  159.   bool tryTurnRight(TetrisArea area) {
  160.     if (shape.points.length == 0)
  161.       return false;
  162.     int newR = round + 1 == shape.points.length ? 0 : round + 1;
  163.     for (var idx = 0; idx != pos.length; ++idx) {
  164.       pos[idx] = pos[idx] - shape.points[round][idx] + shape.points[newR][idx];
  165.       if (pos[idx].isCollided(area)) {
  166.         for (; idx >= 0; --idx)
  167.           pos[idx] = pos[idx] + shape.points[round][idx] - shape.points[newR][idx];
  168.         return false;
  169.       }
  170.     }
  171.     round = newR;
  172.     return true;
  173.   }
  174.  
  175.   bool isCollided(TetrisArea area) => pos.some((e) => e.isCollided(area));
  176. }
  177.  
  178. class TetrisArea {
  179.   static final Row = 20, Col = 10;
  180.   static final TetroWidth = 20;
  181.   List<Shape> shapes;
  182.  
  183.   CanvasRenderingContext2D context, preview;
  184.   Timer tmr;
  185.   Tetro current;
  186.   Fields points;
  187.   int rnd;
  188.  
  189.   TetrisArea(CanvasElement canvas, CanvasElement canvas1, this.shapes) {
  190.     canvas.width = TetroWidth * Col;
  191.     canvas.height = TetroWidth * Row;
  192.     context = canvas.context2d;
  193.     canvas1.height = canvas1.width = TetroWidth * 4;
  194.     preview = canvas1.context2d;
  195.     rnd = (Math.random() * shapes.length).toInt();
  196.     current = new Tetro(shapes[rnd], new Position(0, 0));
  197.     rnd = (Math.random() * shapes.length).toInt();
  198.     points = new Fields();
  199.     drawPreview();
  200.     drawContext();
  201.   }
  202.  
  203.   void Start() {
  204.     tmr = new Timer.repeating(500, (Timer t) {
  205.       if (!current.tryMoveDown(this)) {
  206.         current.pos.forEach((e) { points.setPos(e); });
  207.         points.eraseAllCan();
  208.         current = new Tetro(shapes[rnd], new Position(0, 0));
  209.         rnd = (Math.random() * shapes.length).toInt();
  210.         drawPreview();
  211.         if (current.isCollided(this))
  212.           Stop();
  213.       }
  214.       drawContext();
  215.     });
  216.     document.on.keyPress.add(onKeyPress);
  217.   }
  218.  
  219.   void onKeyPress(KeyboardEvent e) {
  220.     bool needRedraw = false;
  221.     switch (new String.fromCharCodes([e.keyCode]).toUpperCase()) {
  222.       case 'W': needRedraw = current.tryTurnRight(this); break;
  223.       case 'S': needRedraw = current.tryMoveDown(this); break;
  224.       case 'A': needRedraw = current.tryMoveLeft(this); break;
  225.       case 'D': needRedraw = current.tryMoveRight(this); break;
  226.       case 'Q': needRedraw = current.tryTurnLeft(this); break;
  227.       case 'E': needRedraw = current.tryTurnRight(this); break;
  228.       case 'X': while (current.tryMoveDown(this)); needRedraw = true; break;
  229.     }
  230.     if (needRedraw)
  231.       drawContext();
  232.   }
  233.  
  234.   void Stop() {
  235.     tmr.cancel();
  236.     query("#text").innerHTML = 'Game Over!';
  237.     document.on.keyPress.remove(onKeyPress);
  238.   }
  239.  
  240.   void drawPreview() {
  241.     preview.fillStyle = "BLACK";
  242.     preview.fillRect(0, 0, TetroWidth * 4, TetroWidth * 4);
  243.     preview.fillStyle = shapes[rnd].color;
  244.     for (var e in shapes[rnd].points[0])
  245.       preview.fillRect(e.X * TetroWidth + 1,
  246.         e.Y * TetroWidth + 1, TetroWidth - 2, TetroWidth - 2);
  247.   }
  248.  
  249.   void drawContext() {
  250.     context.fillStyle = "BLACK";
  251.     context.fillRect(0, 0, TetroWidth * Col, TetroWidth * Row);
  252.     context.fillStyle = current.shape.color;
  253.     for (var e in current.pos)
  254.       context.fillRect(e.X * TetroWidth + 1,
  255.         e.Y * TetroWidth + 1, TetroWidth - 2, TetroWidth - 2);
  256.     context.fillStyle = "WHITE";
  257.     for (var row = 0; row < Row; ++row) {
  258.       for (var col = 0; col < Col; ++col) {
  259.         if (points[row][col])
  260.           context.fillRect(col * TetroWidth + 1, row * TetroWidth + 1,
  261.             TetroWidth - 2, TetroWidth - 2);
  262.       }
  263.     }
  264.   }
  265. }
  266.  
  267. void main() {
  268.   List<Shape> shapes = [
  269.     new Shape([
  270.       [new Position(0, 0), new Position(1, 0), new Position(2, 0), new Position(3, 0)],
  271.       [new Position(1, 0), new Position(1, 1), new Position(1, 2), new Position(1, 3)]
  272.     ], "RED"),
  273.     new Shape([
  274.       [new Position(0, 0), new Position(1, 0), new Position(1, 1), new Position(2, 1)],
  275.       [new Position(1, 0), new Position(1, 1), new Position(0, 1), new Position(0, 2)]
  276.     ], "YELLOW"),
  277.     new Shape([
  278.       [new Position(0, 1), new Position(1, 1), new Position(1, 0), new Position(2, 0)],
  279.       [new Position(0, 0), new Position(0, 1), new Position(1, 1), new Position(1, 2)]
  280.     ], "AQUA"),
  281.     new Shape([
  282.       [new Position(0, 0), new Position(1, 0), new Position(2, 0), new Position(0, 1)],
  283.       [new Position(0, 0), new Position(1, 0), new Position(1, 1), new Position(1, 2)],
  284.       [new Position(0, 1), new Position(1, 1), new Position(2, 1), new Position(2, 0)],
  285.       [new Position(0, 0), new Position(0, 1), new Position(0, 2), new Position(1, 2)]
  286.     ], "LIME"),
  287.     new Shape([
  288.       [new Position(0, 0), new Position(1, 0), new Position(2, 0), new Position(2, 1)],
  289.       [new Position(1, 0), new Position(1, 1), new Position(1, 2), new Position(0, 2)],
  290.       [new Position(0, 0), new Position(0, 1), new Position(1, 1), new Position(2, 1)],
  291.       [new Position(0, 0), new Position(1, 0), new Position(0, 1), new Position(0, 2)]
  292.     ], "PURPLE"),
  293.     new Shape([
  294.       [new Position(0, 0), new Position(1, 0), new Position(0, 1), new Position(1, 1)]
  295.     ], "ORANGE")
  296.   ];
  297.   new TetrisArea(query("#canvas"), query('#canvas1'), shapes).Start();
  298. }
Advertisement
Add Comment
Please, Sign In to add comment