Skip to content

Commit

Permalink
Added a solver and a corrected the geenaration algo, works now fine
Browse files Browse the repository at this point in the history
  • Loading branch information
monarezio committed Apr 10, 2017
1 parent cf7016a commit a1f3d19
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 49 deletions.
Binary file modified app/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import net.zdendukmonarezio.takuzu.domain.common.extensions.set
import net.zdendukmonarezio.takuzu.domain.common.utils.FieldPickerUtil
import net.zdendukmonarezio.takuzu.domain.game.models.hint.Hinter
import net.zdendukmonarezio.takuzu.domain.game.models.hint.models.Hint
import net.zdendukmonarezio.takuzu.domain.game.models.solver.Solver

/**
* Created by samuelkodytek on 06/03/2017.
*/
class Game private constructor(private val board: Board) : Takuzu {
val hinter = Hinter(board)

override fun isBoardFilled(): Boolean {
return false;
}
Expand All @@ -36,7 +38,7 @@ class Game private constructor(private val board: Board) : Takuzu {
return board.validateAll()
}

override fun getWrongFields(): Hint { //TODO: Not needed for now
override fun getWrongFields(): Hint {
return hinter.hintNext()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package net.zdendukmonarezio.takuzu.domain.game.models.game
import net.zdendukmonarezio.takuzu.domain.common.extensions.*
import net.zdendukmonarezio.takuzu.domain.common.utils.FieldPickerUtil
import net.zdendukmonarezio.takuzu.domain.common.utils.ListUtil
import net.zdendukmonarezio.takuzu.domain.game.models.solver.Solver

/**
* Created by samuelkodytek on 06/03/2017.
Expand Down Expand Up @@ -69,48 +70,57 @@ class GameBoard private constructor(fields: List<List<Field>>, lockedFields: Lis
return true
}

private fun validateRowAdjacency(): Boolean {
for(i in 0..rows()-1) {
for(j in 0..rows()-3) {
if(fields[i][j] != Field.ANON && (fields[i][j] == fields[i][j+1] && fields[i][j+1] == fields[i][j+2] ))
override fun validateAdjacency(): Boolean {

for(i in 0..rows() - 1) {
for(j in 0..columns() - 3) {
if ((fields[i][j] != Field.ANON || fields[i][j + 1] != Field.ANON || fields[i][j + 1] != Field.ANON) &&
fields[i][j] == fields[i][j + 1] && fields[i][j + 1] == fields[i][j + 2])
return false
}
}

return true
}

private fun validateColumnAdjacency(): Boolean {
for(i in 0..columns()-1) {
val col = fields.map { k -> k[i] } //Tranforming into column
for(j in 0..columns()-3) {
if(col[j] != Field.ANON && (col[j] == col[j+1] && col[j+1] == col[j+2] ))
for(i in 0..rows() - 3) {
for(j in 0..columns() - 1) {
if ((fields[i][j] != Field.ANON || fields[i + 1][j] != Field.ANON || fields[i + 2][j] != Field.ANON) &&
fields[i][j] == fields[i + 1][j] && fields[i + 1][j] == fields[i + 2][j])
return false
}
}

return true
}

override fun validateAdjacency(): Boolean {
return validateColumnAdjacency() && validateRowAdjacency()
}

override fun validateFieldAmount(): Boolean {
return validateRowEquivalency() && validateColumnEquivalency()
}

private fun validateRowsColorAmount(): Boolean {
return !fields.any { i -> i.filter { i -> i == Field.BLUE }.size > rows() / 2
|| i.filter { i -> i == Field.RED }.size > rows() / 2 }
for(i in 0..rows() - 1) {
val row = getField(i)
val size = row.filter { i -> i == Field.ANON }.size
if(size != 0) {
val blue = row.filter { i -> i == Field.BLUE }.size
val red = row.filter { i -> i == Field.RED }.size
if(blue > rows() / 2 || red > rows() / 2)
return false
}
}

return true
}

private fun validateColumnsColorAmount(): Boolean {
for(i in 0..columns() - 1) {
val col = fields.map { list -> list[i] }
if(col.filter { i -> i == Field.BLUE }.size > columns() / 2
&& col.filter { i -> i == Field.RED }.size > columns() / 2)
return false
for (i in 0..columns() - 1) {
val column = getFields().map { item -> item[i] }
val size = column.filter { i -> i == Field.ANON }.size
if (size != 0) {
val blue = column.filter { i -> i == Field.BLUE }.size
val red = column.filter { i -> i == Field.RED }.size
if(blue > rows() / 2 || red > rows() / 2)
return false
}

}

return true
Expand All @@ -136,6 +146,17 @@ class GameBoard private constructor(fields: List<List<Field>>, lockedFields: Lis
&& validateColorAmount()
}

fun getNextAvailableMove(): Pair<Int, Int>? {
for(i in 0..rows()-1) {
for(j in 0..columns()-1) {
if(fields[i][j] == Field.ANON)
return Pair(i, j)
}
}

return null
}

companion object GameBoard {

/**
Expand All @@ -144,8 +165,9 @@ class GameBoard private constructor(fields: List<List<Field>>, lockedFields: Lis
fun createBlankBoard(rows: Int, columns: Int): Board {
val gb = GameBoard(ListUtil.createNewFields(List(rows) {List(rows) { Field.ANON }}, rows * columns / 4))

if(!(gb.validateColorAmount() && gb.validateAdjacency())) //Using the famous ostrich algorithm https://en.wikipedia.org/wiki/Ostrich_algorithm
createBlankBoard(rows, columns)
if(!(gb.validateColorAmount() && gb.validateAdjacency()
&& gb.validateFieldAmount() && Solver(gb).isSolvable())) //Using the famous ostrich algorithm https://en.wikipedia.org/wiki/Ostrich_algorithm
return createBlankBoard(rows, columns)

return gb
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import net.zdendukmonarezio.takuzu.domain.common.extensions.random
import net.zdendukmonarezio.takuzu.domain.common.utils.ListUtil
import net.zdendukmonarezio.takuzu.domain.game.models.game.Board
import net.zdendukmonarezio.takuzu.domain.game.models.game.Field
import net.zdendukmonarezio.takuzu.domain.game.models.game.GameBoard
import net.zdendukmonarezio.takuzu.domain.game.models.hint.models.Hint
import net.zdendukmonarezio.takuzu.domain.game.models.hint.models.Notification.*

Expand Down Expand Up @@ -198,4 +199,22 @@ class Hinter(private val board: Board): Hintable{

return Hint(listOf(), NO_HINT_AVAILABLE)
}

fun hintOnly(): Hint {
val hintColor = hintByColor()
if (hintColor != null)
return Hint(listOf(hintColor), THREE_TILES_HINT)

val hintCombo = hintByCombination()
if (hintCombo != null)
return Hint(hintCombo, ONLY_ONE_POSSIBLE_COMBINATION)

if(board is GameBoard) {
val list = board.getNextAvailableMove()
if(list != null)
return Hint(listOf(list), NO_HINT_AVAILABLE)
}

return Hint(listOf(), NO_HINT_AVAILABLE)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,32 @@ import net.zdendukmonarezio.takuzu.domain.common.utils.ListUtil
import net.zdendukmonarezio.takuzu.domain.game.models.game.Board
import net.zdendukmonarezio.takuzu.domain.game.models.game.Field
import net.zdendukmonarezio.takuzu.domain.game.models.game.GameBoard
import net.zdendukmonarezio.takuzu.domain.game.models.hint.Hinter

/**
* Created by monarezio on 09/04/2017.
*/
class Solver(private val board: Board): Solvable {

override fun isSolvable(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
println("Solving")
val a = solve()
return a != null
}

override fun solve(): Board? {
fun helper(gameBoard: GameBoard): Board? {
fun helper(gameBoard: Board): Board? {
if(gameBoard.validateColorAmount() && gameBoard.validateAdjacency()) {
val anonymousCoords = ListUtil.toPair(gameBoard.getFields())
if (!anonymousCoords.isEmpty()) {
for (i in 0..anonymousCoords.size - 1) {
val blueBoard = gameBoard.set(anonymousCoords[i].first, anonymousCoords[i].second, Field.BLUE)
val blue = helper(blueBoard as GameBoard)
if (blue != null)
val next = Hinter(gameBoard).hintOnly().coords
.filter { i -> gameBoard.getFields()[i.first][i.second] == Field.ANON }
if (!next.isEmpty()) {
for (i in 0..next.size - 1) {
val blue = helper(gameBoard.set(next[i].first, next[i].second, Field.BLUE))
if(blue != null)
return blue

val redBoard = gameBoard.set(anonymousCoords[i].first, anonymousCoords[i].second, Field.RED)
val red = helper(redBoard as GameBoard)
if (red != null)
val red = helper(gameBoard.set(next[i].first, next[i].second, Field.RED))
if(red != null)
return red
}
} else if (gameBoard.validateAll()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class GameBoardTest {
@Test fun validateColorAmount() {
val gameBoard = GameBoard.createBoard(listOf(
listOf(Field.BLUE, Field.BLUE, Field.ANON, Field.ANON),
listOf(Field.ANON, Field.ANON, Field.ANON, Field.ANON),
listOf(Field.ANON, Field.ANON, Field.ANON, Field.ANON),
listOf(Field.BLUE, Field.ANON, Field.ANON, Field.ANON),
listOf(Field.RED, Field.RED, Field.ANON, Field.ANON),
listOf(Field.ANON, Field.ANON, Field.ANON, Field.ANON)
), listOf())
assertTrue(gameBoard.validateColorAmount())
Expand Down Expand Up @@ -96,15 +96,6 @@ class GameBoardTest {
listOf(Field.RED, Field.BLUE, Field.BLUE, Field.RED)
), listOf())
assertTrue(gameBoard.validateAll())
val newGameBoard = gameBoard.set(0, 0, Field.RED)
assertFalse(newGameBoard.validateAll())
val gameBoard2 = GameBoard.createBoard(listOf(
listOf(Field.RED, Field.BLUE, Field.RED, Field.BLUE),
listOf(Field.BLUE, Field.RED, Field.BLUE, Field.RED),
listOf(Field.BLUE, Field.BLUE, Field.ANON, Field.ANON),
listOf(Field.RED, Field.RED, Field.ANON, Field.ANON)
), listOf())
assertFalse(gameBoard2.validateAll())
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SolverTest {
val board = GameBoard.createBoard(listOf(
listOf(Field.BLUE, Field.ANON, Field.BLUE, Field.ANON),
listOf(Field.ANON, Field.RED, Field.ANON, Field.ANON),
listOf(Field.ANON, Field.ANON, Field.ANON, Field.ANON),
listOf(Field.ANON, Field.RED, Field.ANON, Field.ANON),
listOf(Field.ANON, Field.ANON, Field.ANON, Field.ANON)
), listOf(Pair(0, 0), Pair(0, 2), Pair(1, 1), Pair(2, 1)))
val solver = Solver(board)
Expand Down

0 comments on commit a1f3d19

Please sign in to comment.