package models;
import boardGenerator.GameDifficultyLevel;
import boardGenerator.Pair;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Random;
/**
* Clase Partida
* Implementa una partida Sudoku Observable
* En esta clase se crea el tablero de la partida actual
* la solucion, el cronometro, el modelo y otros
*
* Provee las diferentes funcionalidades del juego como
* Iniciar Nueva Partida, Verificar Jugada, Sugerir Jugada
* Resolver Tablero, reiniciar Tablero, Insertar Valor
* Borrar Valor, Calcular Puntuacion y otros
*/
public class Partida extends Observable{
private int[][] board;
private int[][] solution;
private int numberCount;
private int corrections;
private int checks;
private int suggest;
private SudokuModelo model;
private Configuration configuration;
private int punctuation;
private Cronometer cronometro = Cronometer.getInstance();
int minutes = 0;
private boolean borro;
private boolean verifico;
private boolean pista;
/**
* Constructor de la Clase Partida
* @param nuevaConfig Configuracion de la Partida
*/
public Partida(Configuration nuevaConfig) {
configuration = nuevaConfig;
}
/**
* Nuva Partida
* Crea el modelo Sudoku (segun generador) obtiene
* tableros a resolver y solucion, inicia el tiempo
* y el contador, calcula la partida inicial e informa
* al observador los cambios realizados
*/
public void nuevaPartida(){
model = new SudokuModelo(configuration.getGenerator(),configuration.getDifficulty());
board = model.getBoard();
solution = model.getSolution();
numberCount = model.getNumberCount();
cronometro.iniciarTiempo();
punctuation = 0;
corrections = 0;
checks = 0;
suggest = 0;
borro = false; pista = false; verifico = false;
calcularPuntuacionInicial();
setChanged();
notifyObservers("NUMBERCOUNT_CHANGED");
setChanged();
notifyObservers("CHANGE_POINTS");
}
/**
* Verifica la Jugada Actual
* @return Lista de pos x e y donde hay un
* numero incorrecto
*/
public List<Pair<Integer,Integer>> verificarJugada() {
List<Pair<Integer,Integer>> lista = new LinkedList<>();
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
if( (board[i][j] != solution[i][j]) && (board[i][j] != 0)){
Pair<Integer,Integer> casilla = new Pair(i,j);
lista.add(casilla);
}
}
}
checks++;
verifico = true;
calcularPuntuacion();
return lista;
}
/**
* Calcula una posible jugada y notifica al
* observador con el valor y la posicion en donde
* puede poner ese numero correctamente
*/
public void sugerirJugada(){
if (numberCount == 81) return;
Random rdmGen = new Random();
int i;
int j;
do {
i = rdmGen.nextInt(9);
j = rdmGen.nextInt(9);
} while (board[i][j]==solution[i][j]);
suggest++;
pista = true;
calcularPuntuacion();
Pair<Pair<Integer,Integer>,Integer> tmp = new Pair<Pair<Integer,Integer>,Integer>();
Pair<Integer,Integer> pos = new Pair(i,j);
tmp.setFirst(pos);tmp.setSecond(solution[i][j]);
setChanged();
notifyObservers(tmp);
}
/**
* Resuelve la partida Actual
*/
public void resolver(){
board = solution;
punctuation = 0;
numberCount = 81;
setChanged();
notifyObservers("NUMBERCOUNT_CHANGED");
setChanged();
notifyObservers("CHANGE_POINTS");
}
/**
* Reinicia el tablero al problema original
* pero el tiempo y la puntuacion sigen como estaban
*/
public void resetBoard(){
this.board = model.getBoard();
numberCount = model.getNumberCount();
setChanged();
notifyObservers("NUMBERCOUNT_CHANGED");
}
/**
* Inserta un valor en la grilla problema
* @param i filas
* @param j columnas
* @param valor a insertar
*/
public void InsertarValor(int i,int j,int valor){
if(board[i][j] == 0){
numberCount++;
} else {
if(board[i][j] != valor){
corrections++;
borro = true;
calcularPuntuacion();
}
}
board[i][j]= valor;
setChanged();
notifyObservers("NUMBERCOUNT_CHANGED");
}
/**
* Borra un valor en la grilla problema
* pone un 0 en el lugar que habia un numero
* @param i fila
* @param j columna
*/
public void BorrarValor(int i,int j){
if(board[i][j] == 0) return;
numberCount--;
corrections++;
board[i][j]= 0;
borro = true;
calcularPuntuacion();
setChanged();
notifyObservers("NUMBERCOUNT_CHANGED");
}
/**
* Obtiene el tiempo de la partida actual
* @return
*/
public String getTiempoPartida() {
return this.cronometro.obtenerTiempo();
}
/**
* Obtiene la puntuacion de la partida actual
* @return
*/
public int getPuntuacion() {
return punctuation;
}
/**
* Obtiene el tablero de la partida actual
* @return
*/
public int[][] getTablero() {
return board;
}
/**
* Calcula la puntuacion inicial
* de la partida segun dificultad
*/
private void calcularPuntuacionInicial(){
if (configuration.getDifficulty()== GameDifficultyLevel.EASY)
punctuation = 6000;
if (configuration.getDifficulty()== GameDifficultyLevel.MODERATE)
punctuation = 8000;
if (configuration.getDifficulty()== GameDifficultyLevel.HARD)
punctuation = 10000;
}
/**
* Calcula la puntuacion ante cambios en el tablero
* segun la dificultad actual
*/
public void calcularPuntuacion(){
minutes = cronometro.obtenerMinutos();
if (minutes != 0){
if (configuration.getDifficulty()== GameDifficultyLevel.EASY)
punctuation += -(minutes*5);
if (configuration.getDifficulty()== GameDifficultyLevel.MODERATE)
punctuation += -(minutes*10);
if (configuration.getDifficulty()== GameDifficultyLevel.HARD)
punctuation += -(minutes*15);
}
if (pista){
if (configuration.getDifficulty()== GameDifficultyLevel.EASY)
punctuation += -(suggest*50);
if (configuration.getDifficulty()== GameDifficultyLevel.MODERATE)
punctuation += -(suggest*150);
if (configuration.getDifficulty()== GameDifficultyLevel.HARD)
punctuation += -(suggest*200);
pista = false;
}
if (borro){
if (configuration.getDifficulty()== GameDifficultyLevel.EASY)
punctuation += -(corrections*15);
if (configuration.getDifficulty()== GameDifficultyLevel.MODERATE)
punctuation += -(corrections*20);
if (configuration.getDifficulty()== GameDifficultyLevel.HARD)
punctuation += -(corrections*25);
borro = false;
}
if (verifico){
if (configuration.getDifficulty()== GameDifficultyLevel.EASY)
punctuation += -(checks*20);
if (configuration.getDifficulty()== GameDifficultyLevel.MODERATE)
punctuation += -(checks*25);
if (configuration.getDifficulty()== GameDifficultyLevel.HARD)
punctuation += -(checks*30);
verifico = false;
}
setChanged();
notifyObservers("CHANGE_POINTS");
}
/**
* Obtiene la configuracion de la partida actual
* @return
*/
public Configuration getConfig(){
return configuration;
}
/**
* Obtiene la instancia del cronometro de la partida actual
* @return
*/
public Cronometer getCronometro(){
return this.cronometro;
}
/**
* Obtiene la cantidad de numeros que faltan colocar en la partida actual
* @return
*/
public int getCantNumbersToPut(){
return 81-numberCount;
}
}