Ad

Game of Life :

The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.

Game of Life

Your task is to write a program to calculate the next generation of Conway's game of life, given any starting position.
You start with a two dimensional grid of cells, where each cell is either alive or dead.
The grid is finite, and no life can exist off the edges.
When calculating the next generation of the grid, follow these four rules:

  1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
  2. Any live cell with more than three live neighbours dies, as if by overcrowding.
  3. Any live cell with two or three live neighbours lives on to the next generation.
  4. Any dead cell with exactly three live neighbours becomes a live cell.

Examples: * indicates live cell, . indicates dead cell

Example input: (4 x 8 grid)
........
....*...
...**...
........

Example output:
........
...**...
...**...
........
function nextGeneration(grid) {
  return grid.map((row, rowIndex) => {
    return row.map((cell, colIndex) => {
      if (rowIndex !== 0 && colIndex !== 0 && rowIndex < grid.length - 1 && colIndex < row.length - 1) {
        let neighboursCount = 0;
        if (grid[rowIndex][colIndex + 1] === 1) neighboursCount++;
        if (grid[rowIndex][colIndex - 1] === 1) neighboursCount++;
        if (grid[rowIndex + 1][colIndex] === 1) neighboursCount++;
        if (grid[rowIndex - 1][colIndex] === 1) neighboursCount++;
        if (grid[rowIndex + 1][colIndex + 1] === 1) neighboursCount++;
        if (grid[rowIndex + 1][colIndex - 1] === 1) neighboursCount++;
        if (grid[rowIndex - 1][colIndex + 1] === 1) neighboursCount++;
        if (grid[rowIndex - 1][colIndex - 1] === 1) neighboursCount++;
      
        if (cell === 1) {
          if (neighboursCount === 2 || neighboursCount === 3 ) {
            return 1;
          }
        } else {
          if (neighboursCount === 3 ) {
            return 1;
          }
        }
        return 0;
      }
      return 0;
    });
  });
}
Code
Diff
  • function nextGeneration(grid) {
      return grid.map((row, rowIndex) => {
        return row.map((cell, colIndex) => {
          if (rowIndex !== 0 && colIndex !== 0 && rowIndex < grid.length - 1 && colIndex < row.length - 1) {
            let neighboursCount = 0;
            if (grid[rowIndex][colIndex + 1] === 1) neighboursCount++;
            if (grid[rowIndex][colIndex - 1] === 1) neighboursCount++;
            if (grid[rowIndex + 1][colIndex] === 1) neighboursCount++;
            if (grid[rowIndex - 1][colIndex] === 1) neighboursCount++;
            if (grid[rowIndex + 1][colIndex + 1] === 1) neighboursCount++;
            if (grid[rowIndex + 1][colIndex - 1] === 1) neighboursCount++;
            if (grid[rowIndex - 1][colIndex + 1] === 1) neighboursCount++;
            if (grid[rowIndex - 1][colIndex - 1] === 1) neighboursCount++;
          
            if (cell === 1) {
              if (neighboursCount === 2 || neighboursCount === 3 ) {
                return 1;
              }
            } else {
              if (neighboursCount === 3 ) {
                return 1;
              }
            }
            return 0;
          }
          return 0;
        });
      });
    }
    • function nextGeneration(grid) {
    • return grid;
    • return grid.map((row, rowIndex) => {
    • return row.map((cell, colIndex) => {
    • if (rowIndex !== 0 && colIndex !== 0 && rowIndex < grid.length - 1 && colIndex < row.length - 1) {
    • let neighboursCount = 0;
    • if (grid[rowIndex][colIndex + 1] === 1) neighboursCount++;
    • if (grid[rowIndex][colIndex - 1] === 1) neighboursCount++;
    • if (grid[rowIndex + 1][colIndex] === 1) neighboursCount++;
    • if (grid[rowIndex - 1][colIndex] === 1) neighboursCount++;
    • if (grid[rowIndex + 1][colIndex + 1] === 1) neighboursCount++;
    • if (grid[rowIndex + 1][colIndex - 1] === 1) neighboursCount++;
    • if (grid[rowIndex - 1][colIndex + 1] === 1) neighboursCount++;
    • if (grid[rowIndex - 1][colIndex - 1] === 1) neighboursCount++;
    • if (cell === 1) {
    • if (neighboursCount === 2 || neighboursCount === 3 ) {
    • return 1;
    • }
    • } else {
    • if (neighboursCount === 3 ) {
    • return 1;
    • }
    • }
    • return 0;
    • }
    • return 0;
    • });
    • });
    • }

After doing:

  • Extract method
  • Move method donde calcular el precio (movie or rental)?
  • Unit test smell: Indirect Testing
  • Replace temp with query
  • Replace Type Code with State/Strategy
  • Replace Conditional with Polymorphism
  • Replace Constructor with Factory Method
Code
Diff
  • class RentalReport {
      statement(customer) {
        let result = "Rental Record for " + customer.name + "\n";
        customer.rentals.forEach((each) => {
          //show figures for this rental
          result += "\t" + each.movie.title+ "\t" + each.getAmount() + "\n";
        });
        //add footer lines
        result += "Amount owed is " + customer.getTotalAmount() + "\n";
        result += "You earned " + customer.getFrequentPoints() + " frequent renter points";
        return result;
      }
    }
    
    const MovieType = {
        CHILDREN: Symbol('CHILDREN'),
        REGULAR: Symbol('REGULAR'),
        NEW_RELEASE: Symbol('NEW_RELEASE'),
    }
    
    class Price {
      static create(priceCode) {
        switch (priceCode) {
          case MovieType.REGULAR:
            return new RegularPrice();
          case MovieType.NEW_RELEASE:
            return new NewReleasePrice();
          case MovieType.CHILDREN:
            return new ChildrenPrice();
        }
      }
      get code() {
        throw "not implemented";
      }
      getAmount(daysRented) {
        throw "not implemented";
      }
      getFrequentPoints(daysRented) {
        return 1;
      }
    }
    
    class ChildrenPrice extends Price {
      get code() {
        return MovieType.CHILDREN;
      }
      getAmount(daysRented) {
        let amount = 1.5;
        if (daysRented > 3)
          amount += (daysRented - 3) * 1.5;
        return amount;  
      }
    }
    
    class RegularPrice extends Price {
      get code() {
        return MovieType.REGULAR;
      }
      getAmount(daysRented) {
        let amount = 2;
        if (daysRented > 2)
          amount += (daysRented - 2) * 1.5;
        return amount;  
      }
    }
    
    class NewReleasePrice extends Price {
      get code() {
        return MovieType.NEW_RELEASE;
      }
      getAmount(daysRented) {
        return daysRented * 3;
      }
      getFrequentPoints(daysRented) {
        return daysRented > 1 ? 2 : 1;
      }
    }
    
    
    class Movie {
      constructor (title, priceCode) {
        this._title = title;
        this.priceCode = priceCode;
      }
      set priceCode(priceCode) {
        this._price = Price.create(priceCode);
      }
      get priceCode() {
        return this._price.code;
      }
      get title() {
        return this._title;
      }
      getAmount(daysRented) {
        return this._price.getAmount(daysRented);  
      }
      getFrequentPoints(daysRented) {
        return this._price.getFrequentPoints(daysRented);
      }
    }
    
    class Rental {
      constructor(movie, daysRented) {
        this._movie = movie;
        this._daysRented = daysRented;
      }
      get daysRented() {
        return this._daysRented;
      }
      get movie() {
        return this._movie;
      }
      getAmount() {
        return this.movie.getAmount(this.daysRented);
      }
      getFrequentPoints() {
        return this.movie.getFrequentPoints(this.daysRented);
      }
    }
    
    class Customer {
      constructor(name) {
        this._name = name;
        this._rentals = [];
      }
      get name() {
        return this._name;
      }
      get rentals() {
        return this._rentals;
      }
      addRental(rental) {
        this._rentals.push(rental);
      }
      getFrequentPoints() {
        return this.rentals.reduce((frequentPoints, rental) => frequentPoints + rental.getFrequentPoints(), 0);
      }
      getTotalAmount() {
        return this.rentals.reduce((amount, rental) => amount + rental.getAmount(), 0);
      }
    }
    • class RentalReport {
    • statement(customer) {
    • let totalAmount = 0;
    • let frequentRenterPoints = 0;
    • let result = "Rental Record for " + customer.name + "\n";
    • customer.rentals.forEach((each) => {
    • let thisAmount = 0;
    • //determine amounts for each line
    • switch (each.movie.priceCode) {
    • case MovieType.REGULAR:
    • thisAmount += 2;
    • if (each.daysRented > 2)
    • thisAmount += (each.daysRented - 2) * 1.5;
    • break;
    • case MovieType.NEW_RELEASE:
    • thisAmount += each.daysRented * 3;
    • break;
    • case MovieType.CHILDREN:
    • thisAmount += 1.5;
    • if (each.daysRented > 3)
    • thisAmount += (each.daysRented - 3) * 1.5;
    • break;
    • }
    • // add frequent renter points
    • frequentRenterPoints ++;
    • // add bonus for a two day new release rental
    • if ((each.movie.priceCode == MovieType.NEW_RELEASE) && each.daysRented > 1) frequentRenterPoints ++;
    • //show figures for this rental
    • result += "\t" + each.movie.title+ "\t" + thisAmount + "
    • ";
    • totalAmount += thisAmount;
    • result += "\t" + each.movie.title+ "\t" + each.getAmount() + "
    • ";
    • });
    • //add footer lines
    • result += "Amount owed is " + totalAmount + "
    • ";
    • result += "You earned " + frequentRenterPoints + " frequent renter points";
    • result += "Amount owed is " + customer.getTotalAmount() + "
    • ";
    • result += "You earned " + customer.getFrequentPoints() + " frequent renter points";
    • return result;
    • }
    • }
    • const MovieType = {
    • CHILDREN: Symbol('CHILDREN'),
    • REGULAR: Symbol('REGULAR'),
    • NEW_RELEASE: Symbol('NEW_RELEASE'),
    • }
    • class Price {
    • static create(priceCode) {
    • switch (priceCode) {
    • case MovieType.REGULAR:
    • return new RegularPrice();
    • case MovieType.NEW_RELEASE:
    • return new NewReleasePrice();
    • case MovieType.CHILDREN:
    • return new ChildrenPrice();
    • }
    • }
    • get code() {
    • throw "not implemented";
    • }
    • getAmount(daysRented) {
    • throw "not implemented";
    • }
    • getFrequentPoints(daysRented) {
    • return 1;
    • }
    • }
    • class ChildrenPrice extends Price {
    • get code() {
    • return MovieType.CHILDREN;
    • }
    • getAmount(daysRented) {
    • let amount = 1.5;
    • if (daysRented > 3)
    • amount += (daysRented - 3) * 1.5;
    • return amount;
    • }
    • }
    • class RegularPrice extends Price {
    • get code() {
    • return MovieType.REGULAR;
    • }
    • getAmount(daysRented) {
    • let amount = 2;
    • if (daysRented > 2)
    • amount += (daysRented - 2) * 1.5;
    • return amount;
    • }
    • }
    • class NewReleasePrice extends Price {
    • get code() {
    • return MovieType.NEW_RELEASE;
    • }
    • getAmount(daysRented) {
    • return daysRented * 3;
    • }
    • getFrequentPoints(daysRented) {
    • return daysRented > 1 ? 2 : 1;
    • }
    • }
    • class Movie {
    • constructor (title, priceCode) {
    • this._title = title;
    • this._priceCode = priceCode;
    • this.priceCode = priceCode;
    • }
    • set priceCode(priceCode) {
    • this._price = Price.create(priceCode);
    • }
    • get priceCode() {
    • return this._priceCode;
    • return this._price.code;
    • }
    • get title() {
    • return this._title;
    • }
    • getAmount(daysRented) {
    • return this._price.getAmount(daysRented);
    • }
    • getFrequentPoints(daysRented) {
    • return this._price.getFrequentPoints(daysRented);
    • }
    • }
    • class Rental {
    • constructor(movie, daysRented) {
    • this._movie = movie;
    • this._daysRented = daysRented;
    • }
    • get daysRented() {
    • return this._daysRented;
    • }
    • get movie() {
    • return this._movie;
    • }
    • getAmount() {
    • return this.movie.getAmount(this.daysRented);
    • }
    • getFrequentPoints() {
    • return this.movie.getFrequentPoints(this.daysRented);
    • }
    • }
    • class Customer {
    • constructor(name) {
    • this._name = name;
    • this._rentals = [];
    • }
    • get name() {
    • return this._name;
    • }
    • get rentals() {
    • return this._rentals;
    • }
    • addRental(rental) {
    • this._rentals.push(rental);
    • }
    • }
    • getFrequentPoints() {
    • return this.rentals.reduce((frequentPoints, rental) => frequentPoints + rental.getFrequentPoints(), 0);
    • }
    • getTotalAmount() {
    • return this.rentals.reduce((amount, rental) => amount + rental.getAmount(), 0);
    • }
    • }

Taken from the great book Refactoring: Improving the Design of Existing Code by Martin Fowler.

This kata is about practicing refactoring rhythm: small refactor, test, small refactor, test.

The task here is to refactor code (you can use a refactoring catalog) and compare your solution with others.

class RentalReport {
  statement(customer) {
    let totalAmount = 0;
    let frequentRenterPoints = 0;
    let result = "Rental Record for " + customer.name + "\n";
    customer.rentals.forEach((each) => {
      let thisAmount = 0;
      //determine amounts for each line
      switch (each.movie.priceCode) {
        case MovieType.REGULAR:
          thisAmount += 2;
          if (each.daysRented > 2)
            thisAmount += (each.daysRented - 2) * 1.5;
          break;
        case MovieType.NEW_RELEASE:
          thisAmount += each.daysRented * 3;
          break;
        case MovieType.CHILDREN:
          thisAmount += 1.5;
          if (each.daysRented > 3)
            thisAmount += (each.daysRented - 3) * 1.5;
          break;
      }
      // add frequent renter points
      frequentRenterPoints ++;

      // add bonus for a two day new release rental
      if ((each.movie.priceCode == MovieType.NEW_RELEASE) && each.daysRented > 1) frequentRenterPoints ++;
      //show figures for this rental
      result += "\t" + each.movie.title+ "\t" + thisAmount + "\n";
      totalAmount += thisAmount;       
    });
    //add footer lines
    result += "Amount owed is " + totalAmount + "\n";
    result += "You earned " + frequentRenterPoints + " frequent renter points";
    return result;
  }
 
}

const MovieType = {
    CHILDREN: Symbol('CHILDREN'),
    REGULAR: Symbol('REGULAR'),
    NEW_RELEASE: Symbol('NEW_RELEASE'),
}

class Movie {
  constructor (title, priceCode) {
    this._title = title;
    this._priceCode = priceCode;
  }
  get priceCode() {
    return this._priceCode;
  }
  get title() {
    return this._title;
  }
}

class Rental {
  constructor(movie, daysRented) {
    this._movie = movie;
    this._daysRented = daysRented;
  }
  get daysRented() {
    return this._daysRented;
  }
  get movie() {
    return this._movie;
  }
}

class Customer {
  constructor(name) {
    this._name = name;
    this._rentals = [];
  }
  get name() {
    return this._name;
  }
  get rentals() {
    return this._rentals;
  }
  addRental(rental) {
    this._rentals.push(rental);
  }
}

Game of Life :

The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.

Game of Life

Your task is to write a program to calculate the next generation of Conway's game of life, given any starting position.
You start with a two dimensional grid of cells, where each cell is either alive or dead.
The grid is finite, and no life can exist off the edges.
When calculating the next generation of the grid, follow these four rules:

  1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
  2. Any live cell with more than three live neighbours dies, as if by overcrowding.
  3. Any live cell with two or three live neighbours lives on to the next generation.
  4. Any dead cell with exactly three live neighbours becomes a live cell.

Examples: * indicates live cell, . indicates dead cell

Example input: (4 x 8 grid)
........
....*...
...**...
........

Example output:
........
...**...
...**...
........
function nextGeneration(grid) {
  return grid;
}

given we are anonymous
then should say "Hello World!"

given we are "McFly"
then should say "Hello McFly!"

function sayHello() {
}