4 By 4 Skyscrapers in Java


The problem

In a grid of 4 by 4 squares you wish to place a skyscraper in every sq. with just some clues:

  • The peak of the skyscrapers is between 1 and 4
  • No two skyscrapers in a row or column could have the identical variety of flooring
  • A clue is the variety of skyscrapers which you can see in a row or column from the surface
  • Increased skyscrapers block the view of decrease skyscrapers situated behind them

Are you able to write a program that may clear up this puzzle?

Instance:

To grasp how the puzzle works, that is an instance of a row with 2 clues. Seen from the left aspect there are 4 buildings seen whereas seen from the correct aspect only one:

There is just one means wherein the skyscrapers may be positioned. From left-to-right all 4 buildings have to be seen and no constructing could disguise behind one other constructing:

Instance of a 4 by 4 puzzle with the answer:

Process:

public static int[][] solvePuzzle (int[] clues)
  • Go the clues in an array of 16 gadgets. This array accommodates the clues across the clock, index:
       0 1   2   3   15         4 14         5 13         6 12         7  1110 9 8  
  • If no clue is out there, add worth `0`
  • Every puzzle has just one attainable answer
  • `SolvePuzzle()` returns matrix `int[][]`. The primary indexer is for the row, the second indexer for the column. (Python: returns 4-tuple of 4-tuples, Ruby: 4-Array of 4-Arrays)

The answer in Java code

Choice 1:

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SkyScrapers {

  personal last static Integer SIZE = 4;

  static int[][] solvePuzzle (int[] clues) {
    return new SkyScrapers().clear up(clues);
  }
  
  personal static class AbortException extends Exception { }

  personal Desk desk;

  personal int[][] clear up(int[] clues) {
    desk = new Desk(clues);
    attempt {
      Place initPosition = desk.getInitPosition();
      if (iter(initPosition)) return desk.desk;
      else throw new RuntimeException("no answer");
    } catch (AbortException e) { return desk.desk; }
  }

  personal boolean iter(Place place) {
    Set<Integer> possibleValues = desk.getPossibleValuesForPosition(place);
    for (Integer possibleValue : possibleValues) {
      desk.setValueForPosition(place, possibleValue);
      attempt {
        Place nextPosition = desk.getNextPosition(place);
        if(iter(nextPosition))
          return true;
        else
          desk.setValueForPosition(place, 0);
      } catch (AbortException e) { return true; }
    }
    return false;
  }

  static class Place {
    Integer x;
    Integer y;

    Place(Integer x, Integer y) {
      this.x = x;
      this.y = y;
    }

    Integer getX() {
      return x;
    }

    Integer getY() {
      return y;
    }
  }

  static class Desk {
    int[][] desk;
    Line[] horizontalLines = new Line[SIZE];
    Line[] verticalLines = new Line[SIZE];

    Desk(int[] clues) {
      initTable();
      initLinesWithClues(clues);
    }

    personal Integer getValueForPosition(int x, int y) {
      return desk[y][x]; // inverted!
    }

    void setValueForPosition(Place place, int worth) {
      int x = place.getX();
      int y = place.getY();
      setValueForPosition(x, y, worth);
      verticalLines[x].line[y] = worth; 
      horizontalLines[y].line[x] = worth; 
    }

    personal void setValueForPosition(int x, int y, int worth) {
      desk[y][x] = worth; // inverted!
    }

    Place getInitPosition() throws AbortException {
      Place place = new Place(0,0);
      if (getValueForPosition(0,0) != 0) place = getNextPosition(place);
      return place;  
    }

    Place getNextPosition(Place place) throws AbortException {
      int x = place.getX();
      int y = place.getY();
      do {
        if (x == SIZE-1)
          if (y == SIZE-1)
            throw new AbortException();
          else {
            x = 0;
            y++;
          }
        else
          x++;
      } whereas (getValueForPosition(x,y) != 0);
      return new Place(x,y);
    }

    Set<Integer> getPossibleValuesForPosition(Place place) {
      int x = place.getX();
      int y = place.getY();
      Set<Integer> possibleValues = new HashSet<>();
      Set<Integer> possibleValuesForHorizontalLine = horizontalLines[y].getPossibleValuesForPosition(x); 
      Set<Integer> possibleValuesForVerticalLine = verticalLines[x].getPossibleValuesForPosition(y);
      possibleValues.addAll(possibleValuesForHorizontalLine);
      possibleValues.retainAll(possibleValuesForVerticalLine);
      return possibleValues;
    }

    personal void initLinesWithClues(int[] clues) {
      IntStream.vary(0, SIZE).forEach(x -> verticalLines[x] = new Line(getVerticalLine(x), clues[x], clues[3*SIZE-1-x]));
      synchTableWithVerticalLines();
      IntStream.vary(0, SIZE).forEach(y -> horizontalLines[y] = new Line(getHorizontalLine(y), clues[4*SIZE-1-y], clues[SIZE+y]));
      synchTableWithHorizontalLines();
    }

    personal void synchTableWithHorizontalLines() {
      for (int x = 0 ; x < SIZE ; x++)
        for (int y = 0 ; y < SIZE ; y++)
          setValueForPosition(x, y, horizontalLines[y].line[x]);
    }

    personal void synchTableWithVerticalLines() {
      for (int x = 0 ; x < SIZE ; x++)
        for (int y = 0 ; y < SIZE ; y++)
          setValueForPosition(x, y, verticalLines[x].line[y]);
    }

    personal int[] getVerticalLine(int x) {
      int[] line = new int[SIZE];
      IntStream.vary(0, SIZE).forEach(y -> line[y] = getValueForPosition(x,y));
      return line;
    }

    personal int[] getHorizontalLine(int y) {
      int[] line = new int[SIZE];
      IntStream.vary(0, SIZE).forEach(x -> line[x] = getValueForPosition(x,y));
      return line;
    }

    personal void initTable() {
      desk = new int[SIZE][SIZE];
      IntStream.vary(0, SIZE).forEach(i -> Arrays.fill(desk[i], 0));
    }

  }

  static class Line {
    int[] line;
    int topClue;
    int bottomClue;

    personal Set<Integer> allNonInitClues = IntStream.rangeClosed(2, SIZE-1).boxed().gather(Collectors.toSet());

    Line(int[] line, int topClue, int bottomClue) {
      this.line = line;
      this.topClue = topClue;
      this.bottomClue = bottomClue;
      resolveInitClues();
    }

    personal void resolveInitClues() {
      if (topClue == 1) line[0] = SIZE;
      if (bottomClue == 1) line[SIZE-1] = SIZE;
      if (topClue == SIZE) IntStream.vary(0, SIZE).forEach(i -> line[i] = i + 1);
      if (bottomClue == SIZE) IntStream.vary(0, SIZE).forEach(i -> line[SIZE-1-i] = i + 1);
    }

    Set<Integer> getPossibleValuesForPosition(Integer positionInLine) {
      if(line[positionInLine] != 0)
        throw new IllegalArgumentException("Deadly Error : Making an attempt to find already found worth !!"
            + "n place = " + positionInLine + "n line : " + this);
      Set<Integer> alreadyPlacedValues = getAlreadyPlacedValues(positionInLine);
      Set<Integer> possibleValues = IntStream.rangeClosed(1, SIZE).boxed().gather(Collectors.toSet());
      possibleValues.removeAll(alreadyPlacedValues); 
      possibleValues.removeIf(valueToTest -> !isCompatibleWithClues(valueToTest, positionInLine));
      return possibleValues;
    }

    personal boolean isCompatibleWithClues(Integer valueToTest, int place) {
      line[position] = valueToTest;
      boolean consequence = true;
      if(this.isComplete()) consequence = this.isCompatibleWithClues(); // double negation!
      line[position] = 0;
      return consequence;
    }

    personal boolean isComplete() {
      return IntStream.vary(0, SIZE).allMatch(i -> line[i] != 0);
    }

    personal boolean isCompatibleWithClues() 
        (allNonInitClues.accommodates(bottomClue) && getNumberOfSkyCrapersOnLine(false) != bottomClue);
      return !isNotCompatibleWithClues;
    

    personal int getNumberOfSkyCrapersOnLine(boolean isAscending) {
      int consequence = 0;
      int maxValue = 0;
      for (int i = 0 ; i < SIZE ; i++) {
        int positionInLine = isAscending ? i : SIZE-1-i; 
        if (line[positionInLine] > maxValue) {
          maxValue = line[positionInLine];
          consequence++;
        }    
      }
      return consequence;
    }

    personal Set<Integer> getAlreadyPlacedValues(int positionInLine) {
      Set<Integer> alreadyPlacedValues = new HashSet<Integer>();
      for (int i = 0 ; i < SIZE ; i ++) {
        if (i == positionInLine) proceed;
        if (line[i] != 0) alreadyPlacedValues.add(line[i]);
      }
      return alreadyPlacedValues;
    }

  }
}

Choice 2:

import java.util.*;
public class SkyScrapers {
  
  public static last int SIZE = 4;
  public static last int[][] course = new int[][]{{0,1}, {1,0}, {0,-1}, {-1, 0}};
  public static int[][][] square3d;
  public static int row = 0, col = 0;
  public static int rely;

  static int[][] solvePuzzle (int[] clues) {
    
    generateEmptySquare();

    whereas(rely < SIZE * SIZE) {
      for(int i = 0; i < SIZE * 4; i++) {
       System.out.printf("i = %d, clue[i]=%d, r = %d, c = %dpercentn", i, clues[i], row, col);
        cleanAllHintsInLine(i);
        checkLineForOneHint(i);
        useClue(i, clues[i]);
        if((i + 1) % SIZE != 0) {
          row += course[i / SIZE][0];
          col += course[i / SIZE][1];
        }
      }
      checkSquareForOneHint();
    }
    
    int[][] consequence = new int[SIZE][SIZE];
    for(int i = 0; i < SIZE; i++) {
      for(int j = 0; j < SIZE; j++) {
        consequence[i][j] = square3d[i][j][0];
      }
    }
    
    return consequence;
  }
  
  static void useClue(int i, int clue) {
    swap(clue) {
        case 1:
          setSkyscraper(iRow(i, 0), iCol(i, 0), SIZE);
          cleanHintLine(i, SIZE);
          break;
        case 2:
          cleanHint(i, 0, SIZE);
          if(getSkyscraper(i, SIZE - 1) == SIZE) {
            setSkyscraper(iRow(i, 0), iCol(i, 0), SIZE - 1);
          }
          if(getSkyscraper(i, SIZE - 2) == SIZE) {
            cleanHint(i, 1, SIZE - 1);
          }
          if(getSkyscraper(i, SIZE - 2) == SIZE && getSkyscraper(i, SIZE - 1) == SIZE - 1) {
            setSkyscraper(iRow(i, 0), iCol(i, 0), 2);
            setSkyscraper(iRow(i, 1), iCol(i, 1), 1);
          }
          break;
        case 3:
          cleanHint(i, 0, SIZE);
          cleanHint(i, 1, SIZE);
          cleanHint(i, 0, SIZE - 1);
          if(getSkyscraper(i, SIZE - 1) == SIZE && getSkyscraper(i, SIZE - 2) == SIZE - 1) {
            setSkyscraper(iRow(i, 0), iCol(i, 0), 2);
            setSkyscraper(iRow(i, 1), iCol(i, 1), 1);
          } else if (getSkyscraper(i, SIZE - 1) == SIZE - 1 && getSkyscraper(i, SIZE - 2) == SIZE) {
            setSkyscraper(iRow(i, 0), iCol(i, 0), 1);
            setSkyscraper(iRow(i, 1), iCol(i, 1), 2);
          } else if (getSkyscraper(i, SIZE - 2) == SIZE && getSkyscraper(i, 0) == 2) {
            setSkyscraper(iRow(i, 1), iCol(i, 1), 3);
          }
          break;
        case SIZE:
          for(int j = 0; j < SIZE; j++) {
            setSkyscraper(iRow(i, j), iCol(i, j), j + 1);
          }
          break;
    }
  }
  
  static void generateEmptySquare() {
    square3d = new int[SIZE][SIZE][SIZE+1];
    for(int r = 0; r < SIZE; r++) {
      for(int c = 0; c < SIZE; c++) {
        for(int d = 0; d < SIZE + 1; d++) {
          square3d[r][c][d] = d;
        }
      }
    }
    rely = 0;
  }
  
  static void checkSquareForOneHint() {
    for(int i = 0; i < SIZE; i++) {
      for(int j = 0; j < SIZE; j++) {
        checkIsOnlyOneHintAndSetIfYes(i, j);
      }
    }
  }
  
  static void checkLineForOneHint(int i) {
    for(int h = 1; h <= SIZE; h++) {
      int pos = 0;
      int rely = 0;
      for(int j = 0; j < SIZE; j++) {
        if(square3d[iRow(i, j)][iCol(i, j)][h] > 0) {
          rely++;
          pos = j;
        }
      }
      if(rely == 1) {
        setSkyscraper(iRow(i, pos), iCol(i, pos), h);
      }
    }
  }
  
  static boolean checkIsOnlyOneHintAndSetIfYes(int row, int col) {
    if(square3d[row][col][0] > 0) {
      return true;
    }
    int num = 0;
    int rely = 0;
    for(int dig = 1; dig <= SIZE; dig++) {
      if(square3d[row][col][dig] > 0) {
        rely++;
        num = dig;
      }
    }
    if(rely == 1) {
      setSkyscraper(row, col, num);
      return true;
    }
    return false;
  }
  
  static void setSkyscraper(int row, int col, int worth) {
    if(square3d[row][col][0] == 0) {
      square3d[row][col][0] = worth;
      for(int h = 0; h < SIZE; h++) {
        square3d[row][col][h+1] = 0;
        square3d[row][h][value] = 0;
        square3d[h][col][value] = 0;
      }
      rely++;
    }
  }
  
  static int getSkyscraper(int i, int j) {
    return square3d[iRow(i, j)][iCol(i, j)][0];
  }

  static int iRow(int i, int j) {
    return row + course[((i / SIZE) + 1) % SIZE][0] * j;
  }

  static int iCol(int i, int j) {
    return col + course[((i / SIZE) + 1) % SIZE][1] * j;
  }

  
  static int howManySee(int i) {
    int max = 0;
    int rely = 0;
    for(int j = 0; j < SIZE; j++) {
      if(square3d[iRow(i, j)][iCol(i, j)][0] > max) {
        max = square3d[iRow(i, j)][iCol(i, j)][0];
        rely++;
      }
    }
    return rely;
  }
  
  static void cleanAllHintsInLine(int i) {
    for(int j=0; j < SIZE; j++) {
      int v = getSkyscraper(i, j);
      if(v > 0) {
        cleanHintLine(i, v);
      }
    }
  }

  static void cleanHintLine(int i, int trace) {
    for(int j = 0; j < SIZE; j++) {
      cleanHint(i, j, trace);
    }
  }
  
  static void cleanHint(int i, int j, int trace) {
      square3d[iRow(i, j)][iCol(i, j)][hint] = 0;
  }

}

Take a look at instances to validate our answer

import org.junit.Take a look at;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;

public class SolutionTest {

    personal static int clues[][] = {
    { 2, 2, 1, 3,  
      2, 2, 3, 1,  
      1, 2, 2, 3,  
      3, 2, 1, 3 },
    { 0, 0, 1, 2,   
      0, 2, 0, 0,   
      0, 3, 0, 0, 
      0, 1, 0, 0 }
    };

    personal static int outcomes[][][] = {
    { { 1, 3, 4, 2 },       
      { 4, 2, 1, 3 },       
      { 3, 4, 2, 1 },
      { 2, 1, 3, 4 } },
    { { 2, 1, 4, 3 }, 
      { 3, 4, 1, 2 }, 
      { 4, 2, 3, 1 }, 
      { 1, 3, 2, 4 } }
    };
 
    @Take a look at
    public void testSolvePuzzle1 () {
        assertEquals (SkyScrapers.solvePuzzle (clues[0]), outcomes[0]);
    }

    @Take a look at
    public void testSolvePuzzle2 () {
        assertEquals (SkyScrapers.solvePuzzle (clues[1]), outcomes[1]);
    }
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles