2

I am trying to port some ruby code to javascript but am struggling with one particular line

The Ruby code is below: It removes all the full rows from a game of tetris:

  # removes all filled rows and replaces them with empty ones, dropping all rows
  # above them down each time a row is removed and increasing the score.  
  def remove_filled
    (2..(@grid.size-1)).each{|num| row = @grid.slice(num);
      # see if this row is full (has no nil)
      if @grid[num].all?
        # remove from canvas blocks in full row
        (0..(num_columns-1)).each{|index|
          @grid[num][index].remove;
          @grid[num][index] = nil
        }
        # move down all rows above and move their blocks on the canvas
        ((@grid.size - num + 1)..(@grid.size)).each{|num2|
          @grid[@grid.size - num2].each{|rect| rect && rect.move(0, block_size)};

          # I can't port this line
          @grid[@grid.size-num2+1] = Array.new(@grid[@grid.size - num2])
        }
        # insert new blank row at top
        @grid[0] = Array.new(num_columns);
        # adjust score for full flow
        @score += 10;
      end
    }
    self
  end

where @grid is a 2 dimensional array, initialised as follows:

@grid = Array.new(num_rows) {Array.new(num_columns)}

the javascript I have done so far is below

I have noted in the comment which is the line I can't work out

removeFilled() {
            for (var i = 2; i < this.grid.length; i++) {
                var row = this.grid.slice(i);

                var allFull = true;

                for (var g = 0; g < this.grid[i].length; g++ ) {
                    if (this.grid[i][g] == undefined) {
                        allFull = false;
                        break;
                    }
                }

                if (allFull) {
                    for (var j = 0; j < this.numColumns; j++) {
                        this.grid[i][j].remove();
                        this.grid[i][j] = undefined;
                    }

                    for (var k = this.grid.length - i + 1; k <= this.grid.length; k++) {

                        var rects = this.grid[this.grid.length - k];

                        for(var l = 0; l < rects.length; l++) {
                            var rect  = rects[l];
                            if (rect) {
                                rect.move(0, this.blockSize);
                            }
                        }

                        // ***this is the line I can't port
                        this.grid[this.grid.length - k + 1] = new Array(this.grid[this.grid.length - k]);
                    }

                    this.grid[0] =  new Array(this.numColumns);
                    this.score += 10;
                }
            }
        }

any ideas how to port the line in question?

5
  • Well, why can't you port it? (You probably want to look at Array.slice.) Commented Jul 4, 2013 at 21:57
  • so start with: grid[grid.length - k + 1] = grid[grid.length - k]. Okay, we're getting somewhere. So what does Array.new(arr) in ruby do? Commented Jul 4, 2013 at 22:10
  • Does this.grid[this.grid.length - k + 1] exist or is it being created? If it's being created then this.grid.length will increase by one and thus this.grid[this.grid.length - k] is actually itself! Unless this is the intention you should set it to a variable and use that instead: var currentGridLenght = this.grid.length; Commented Jul 4, 2013 at 22:38
  • yes, it exists. It is a row in the 2D grid. it needs to be initialised with whatever the code on right hand side of the equals sign is doing (in the Ruby code ). Commented Jul 4, 2013 at 22:52
  • Its setting the item in the grid array to be the same as the item before it (thus moving it down). Something like row[3] = a copy of row[2]. Doesn't seem entirely logical but i'm not familiar with Ruby. In javascript I would add an item at the top of the array .unshift() and .pop() the last one off the end (thus moving them down one). Commented Jul 4, 2013 at 23:23

2 Answers 2

1

If I understand correctly you want to take the array in a given position and copy it one position forward.

You can do this:

  this.grid[this.grid.length - k + 1] =  this.grid[this.grid.length - k].slice(0);
Sign up to request clarification or add additional context in comments.

Comments

1

TL;DR @raam86 gave a correct answer. Difference is that in ruby Array.new old_arr will create a copy of array. In JS you achieve same with old_arr.slice()

As far as I understand your snippet can become something like this:

function falsy(val) {
  return undefined === val || null === val || false === val;
}

function all(arr) {
  return arr.reduce(function (a, b) { return a && !falsy(b); }, true);
}

// removes all filled rows and replaces them with empty ones, dropping all rows
// above them down each time a row is removed and increasing the score.
function removeFilled() {
  var i, j, k, rects,
      _grid       = this.grid,
      _numColumns = this.numColumns,
      _blockSize  = this.blockSize;

  for (i = 2; i < _grid.length; i++) {
    // see if this row is full (has no nil)
    if (all(_grid[i])) {
      // remove from canvas blocks in full row
      for (j = 0; j < _numColumns; j++) {
        _grid[i][j].remove();
        _grid[i][j] = undefined;
      }

      // move down all rows above and move their blocks on the canvas
      for (j = _grid.length - i + 1; j < _grid.length; j++) {
        rects = _grid[_grid.length - j];
        for (k = 0; k < rects.length; k++) {
          if (!falsy(rects[k])) {
            rects[k].move(0, _blockSize);
          }
        }

        _grid[_grid.length - j + 1] = _grid[_grid.length - j].slice();
      }

      _grid[0] = new Array(_numColumns);
      this.score += 10;
    }
  }

  return this;
}

PS You should really review the logic you are using and consider refactor it. For example in one place you use num_columns in another you relay on row's amount of elements. You iterate though array changing it, I recommend you consider manipulating on a copy of array in this case your code will become less complex.

2 Comments

thanks - I agree. Once I have a working copy I inrend to heavily refactor it. I will probably use underscore js for a lot of this.
I recommend you consider lodash instead of underscore. Or even go with Sugar.js for more ruby-ness :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.