1
0
Fork 0
mirror of https://gitlab.com/mfocko/CodeWars.git synced 2024-09-19 22:16:57 +02:00
CodeWars/4kyu/4_by_4_skyscrapers/solution.java
Matej Focko fc899b0b02
chore: initial commit
Signed-off-by: Matej Focko <mfocko@redhat.com>
2021-12-28 16:19:58 +01:00

264 lines
7.2 KiB
Java

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class SkyScrapers {
private static class Permutations<T extends Comparable<T>> implements Iterable<List<T>> {
public class PermutationsIterator implements Iterator<List<T>> {
private List<T> elements;
private boolean _hasNext;
private boolean firstIteration = true;
public PermutationsIterator(List<T> elements) {
this.elements = elements;
_hasNext = elements.size() > 0;
}
private void swap(int k, int l) {
T tmp = elements.get(k);
elements.set(k, elements.get(l));
elements.set(l, tmp);
}
public boolean hasNext() {
return _hasNext;
}
public List<T> next() {
if (!_hasNext) {
throw new NoSuchElementException("No more permutations are left");
}
var lastIteration = new ArrayList<T>(elements);
int k = 0, l = 0;
_hasNext = false;
for (int i = elements.size() - 1; i > 0; i--) {
if (elements.get(i).compareTo(elements.get(i - 1)) > 0) {
k = i - 1;
_hasNext = true;
break;
}
}
for (int i = elements.size() - 1; i > k; i--) {
if (elements.get(i).compareTo(elements.get(k)) > 0) {
l = i;
break;
}
}
swap(k, l);
Collections.reverse(elements.subList(k + 1, elements.size()));
return lastIteration;
}
}
private List<T> elements;
public Permutations(List<T> elements) {
this.elements = elements;
Collections.sort(this.elements);
}
public Iterator<List<T>> iterator() {
return new PermutationsIterator(elements);
}
public Stream<List<T>> stream() {
return StreamSupport.stream(this.spliterator(), false);
}
}
private static class PossibleConfigurations implements Iterable<List<Integer>> {
private List<Integer> initial;
private int clue;
private void generateInitial(int size) {
initial = new ArrayList<Integer>();
for (int i = 0; i < size; i++) {
initial.add(i + 1);
}
}
public PossibleConfigurations(int size, int clue) {
generateInitial(size);
this.clue = clue;
}
public Iterator<List<Integer>> iterator() {
if (clue == 0) {
return (new Permutations(initial)).iterator();
}
return (new Permutations(initial))
.stream()
.filter(heights -> isValid((List<Integer>) heights, clue))
.iterator();
}
}
private static boolean isValid(List<Integer> heights, int clue) {
int canSee = 1;
int lastHeight = heights.get(0);
for (int i = 1; i < heights.size(); i++) {
int currentHeight = heights.get(i);
if (currentHeight > lastHeight) {
lastHeight = currentHeight;
canSee++;
}
}
return canSee == clue;
}
private static int getDx(int clueIndex) {
if (clueIndex >= 4 && clueIndex <= 7) {
return -1;
}
if (clueIndex >= 12) {
return 1;
}
return 0;
}
private static int getDy(int clueIndex) {
if (clueIndex <= 3) {
return 1;
}
if (clueIndex >= 8 && clueIndex <= 11) {
return -1;
}
return 0;
}
private static int getStartX(int clueIndex) {
if (clueIndex < 4) {
return clueIndex;
}
if (clueIndex <= 7) {
return 3;
}
if (clueIndex <= 11) {
return 3 - clueIndex % 4;
}
return 0;
}
private static int getStartY(int clueIndex) {
if (clueIndex < 4) {
return 0;
}
if (clueIndex <= 7) {
return clueIndex % 4;
}
if (clueIndex <= 11) {
return 3;
}
return 3 - clueIndex % 4;
}
private static List<Integer> backupHeights(int[][] heights, int clueIndex) {
List<Integer> backup = new ArrayList<Integer>();
int dx = getDx(clueIndex);
int dy = getDy(clueIndex);
for (
int x = getStartX(clueIndex), y = getStartY(clueIndex);
x >= 0 && x < 4 && y >= 0 && y < 4;
x += dx, y += dy
) {
backup.add(heights[y][x]);
}
return backup;
}
private static boolean emplaceHeights(
int[][] heights, int clueIndex, List<Integer> newHeights, boolean force
) {
int i = 0;
int dx = getDx(clueIndex);
int dy = getDy(clueIndex);
for (
int x = getStartX(clueIndex), y = getStartY(clueIndex);
x >= 0 && x < 4 && y >= 0 && y < 4;
x += dx, y += dy
) {
if (
!force && heights[y][x] != 0 && heights[y][x] != newHeights.get(i)
) {
return false;
}
heights[y][x] = newHeights.get(i++);
}
return true;
}
private static boolean solvePuzzle(
int[][] heights, int[] clues, int clueIndex, boolean ignoreZeroes
) {
while (clueIndex < 16 && ((ignoreZeroes && clues[clueIndex] == 0) || (!ignoreZeroes && clues[clueIndex] != 0))) {
clueIndex++;
}
if (clueIndex >= 16) {
return true;
}
// create copy of heights to ensure correct resetting
List<Integer> currentHeights = backupHeights(heights, clueIndex);
// iterate through the options
for (List<Integer> possibleHeights : new PossibleConfigurations(4, clues[clueIndex])) {
// emplace heights and if conflict occurs, reset and try next one
if (!emplaceHeights(heights, clueIndex, possibleHeights, false)) {
emplaceHeights(heights, clueIndex, currentHeights, true);
continue;
}
// if no conflict present, try filling out other clues
if (solvePuzzle(heights, clues, clueIndex + 1, ignoreZeroes)) {
return true;
}
// otherwise reset heights and try again
emplaceHeights(heights, clueIndex, currentHeights, true);
}
// if we got here, there is no feasible configuration of buildings
return false;
}
static int[][] solvePuzzle(int[] clues) {
var result = new int[4][4];
solvePuzzle(result, clues, 0, true);
// in case there are left zeroes
solvePuzzle(result, clues, 0, false);
return result;
}
}