package sokoban;
public class Grid {
//Definerer et objekt, moves er arraylist med trekk.
private Moves moves;
//Definerer ulike situasjoner
//private final char WALL = '#';
private final char EMPTY = ' ';
private final char BOX = '$';
private final char BOX_ON_TARGET = '*';
private final char PLAYER = '@';
private final char PLAYER_ON_TARGET = '+';
private final char TARGET = '.';
//Initialiserer grid og targets
public char[][] grid;
public boolean[][] targets;
//Initialiserer spillerens koordinater
public int playerX = -1;
public int playerY = -1;
//Konstrokt¯r
public Grid (String level){
//Splitter opp linjene
String[] lines = level.split("\\|");
//Lager et objekt moves, som innholder antall moves og referer til klassen Moves.
moves = new Moves();
//Sjekker hvilken linje som er lengst
int maxLength = 0;
for(int i=0;i<lines.length;i++){
maxLength = Math.max(maxLength, lines[i].length());
}
//Lager grid og targets
targets = new boolean[lines.length][maxLength];
grid = new char[lines.length][maxLength];
//GÂr igjennom hver char i lines
for(int y = 0; y<lines.length;y++){
for(int x = 0; x<maxLength;x++){
//Setter for korte linjer i grid til  bli MaxLength, definerer c til  vÊre char p y,x
char c = (x < lines[y].length() ? lines[y].charAt(x) : EMPTY);
//Fyller targets med true, og setter c verdi.
if(c == PLAYER_ON_TARGET){
c = PLAYER;
targets[y][x] = true;
}
else if(c == BOX_ON_TARGET){
c = BOX;
targets[y][x] = true;
}
else if(c == TARGET){
c = EMPTY;
targets[y][x] = true;
}
//Fyller grid (se setCell metode)
setCell(y,x,c);
//Setter y,x koordinat til spiller
if(c == PLAYER){
playerX = x;
playerY = y;
}
}
moves = new Moves();
}
//Hvis ingen player er funnet, s har vi definert playerY og X til  vÊre -1. Dermed mindre enn 0.
if(playerX < 0 || playerY < 0){
System.err.println("Ingen spiller i oppgitt brett. Pr¯v et annet.");
System.exit(0);
}
}
//getHeight henter h¯yden til grid
public int getHeight(){
return grid.length;
}
//getLength henter lengden til grid
public int getLength(){
return grid[0].length;
}
//isLegal sjekker om koordinat x og y ikke overskrider maxLength og lines.length
public boolean isLegal(int y, int x){
return y >= 0 && x >= 0 && y < getHeight() && x < getHeight();
}
//setCell legger inn char verdi p x og y koordinat
public void setCell(int y, int x, char c){
if(isLegal(y,x)){
grid[y][x] = c;
}
}
//getCell henter ut hvilket symbol som ligger i koordinatet
public char getCell(int y, int x){
if(!isLegal(y,x)){
return 'X';
}
return grid[y][x];
}
//Sjekker om det er target
public boolean isTarget (int y, int x){
return isLegal(y,x) && targets[y][x];
}
//Metode for  skrive ut brettet i konsoll
public String print(){
String output = "";
for(int y = 0; y<getHeight();y++){
for(int x = 0; x<getLength();x++){
//definerer c igjen , som char i grid
char c = grid[y][x];
boolean d = targets[y][x];
//Fyller c med riktige verdier
if(c == PLAYER && d){
c = PLAYER_ON_TARGET;
}
else if(c == BOX && d){
c = BOX_ON_TARGET;
}
else if(c == EMPTY && d){
c = TARGET;
}
output += c;
}
}
return output;
}
//Sjekker antall TOMME targets som er igjen.
public int countTargetsLeft(){
int count = 0;
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getLength(); x++) {
if(isTarget(y,x) && getCell(y,x) != BOX) count++;
}
}
return count;
}
//Metode som beveger p position x og y
public String doMove(int dy, int dx){
//Vi har enda ikke dyttet p noe, derfor false
boolean isPush = false;
//Sjekker om neste koordinat er boks, og neste der er tom. Hvis true, s flyttes boksen med setCell.
if(getCell(playerY+dy, playerX+dx)==BOX && getCell(playerY + dy+dy, playerX +dx+dx)==EMPTY){
isPush = true;
setCell(playerY+dy+dy, playerX+dx+dx, BOX);
}
//Hvis vi pushet, og eller neste koordinat er tom. SÂ flytter vi oss dit. Logger trekket i moves.
if(isPush||getCell(playerY+dy,playerX+dx)==EMPTY){
//Flytter player
setCell(playerY+dy,playerX+dx,PLAYER);
//Fjerner forrige posisjon
setCell(playerY,playerX,EMPTY);
//Logger at vi r¯rte p oss
moves.add(new Move(playerY, playerX, dy, dx, isPush));
//Oppdaterer playerX og Y
playerX += dx;
playerY += dy;
}
//Hvis ikke forrige if-setning gikk, alts de to neste koordinatene er boks og tom (i den rekkef¯lgen) s skriver den ut string.
return("Cannot move "+(isPush ? "box" : "player")+" in that direction. X-retning: "+dx+" og Y-retning: "+dy);
}
//Metode som gÂr tilbake et trekk
public Move undoMove(){
//Fjerner f¯rst et move fra loggen. Bruker objektet moves, initialisert i konstrukt¯r.
Move m = moves.remove();
//Sjekker om arrayList er tom, om den ikke var det setter bruker man Move klassen til  hente dy, dx etc
if(m != null){
//Setter tidligere posisjon til tom og nÂvÊrende situasjon til spiller igjen
setCell(playerY, playerX, EMPTY);
setCell(playerY-m.getDy(),playerX-m.getDx(), PLAYER);
//Hvis forrige trekk var  flytte en boks, kan ikke tidligere pos. vÊre tom, men boks. Og der boksen var , er n tom.
if(m.isPush()){
setCell(playerY, playerX, BOX);
setCell(playerY + m.getDy(), playerX + m.getDx(), EMPTY);
}
//Oppdaterer posisjonen til spilleren
playerX -= m.getDx();
playerY -= m.getDy();
//Skriver ut beskjed om at spilleren er flyttet
}
return m;
}
//Metode for  hente ut stack med moves
public int getMoves(){
return moves.getMoves();
}
public int getPushes(){
return moves.getPushes();
}
public boolean hasWon(){
boolean hasWon = false;
if(this.countTargetsLeft()==0){
hasWon = true;
}
return hasWon;
}
public Moves getHistory(){
return moves;
}
}