Skip to content

Commit

Permalink
Merge pull request #123 from lucasnlm/implement-game-solver
Browse files Browse the repository at this point in the history
Add game solver
  • Loading branch information
lucasnlm committed Jul 17, 2020
2 parents 2f3bfc6 + d7ea60d commit 35f4c58
Show file tree
Hide file tree
Showing 35 changed files with 1,468 additions and 1,188 deletions.
5 changes: 3 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ android {

defaultConfig {
// versionCode and versionName must be hardcoded to support F-droid
versionCode 702071
versionName '7.2.7'
versionCode 703001
versionName '7.3.0'
minSdkVersion 16
targetSdkVersion 30
multiDexEnabled true
vectorDrawables.useSupportLibrary true
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
testInstrumentationRunnerArguments clearPackageData: 'true'
resConfigs 'af-rZA', 'ar-rSA', 'ca-rES', 'cs-rCZ', 'da-rDK', 'de-rDE', 'el-rGR', 'en-rUS',
'es-rES', 'fi-rFI', 'fr-rFR', 'hi-rIN', 'hu-rHU', 'it-rIT', 'iw-rIL', 'ja-rJP',
'ko-rKR', 'nl-rNL', 'no-rNO', 'pl-rPL', 'pt-rBR', 'pt-rPT', 'ro-rRO', 'ru-rRU',
Expand Down
11 changes: 8 additions & 3 deletions app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ import dev.lucasnlm.antimine.share.viewmodel.ShareViewModel
import dev.lucasnlm.antimine.stats.StatsActivity
import kotlinx.android.synthetic.main.activity_game.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
class GameActivity : AppCompatActivity(), DialogInterface.OnDismissListener {
class GameActivity : AppCompatActivity(R.layout.activity_game), DialogInterface.OnDismissListener {
@Inject
lateinit var preferencesRepository: IPreferencesRepository

Expand All @@ -62,7 +64,7 @@ class GameActivity : AppCompatActivity(), DialogInterface.OnDismissListener {
@Inject
lateinit var savesRepository: ISavesRepository

private val viewModel: GameViewModel by viewModels()
val viewModel: GameViewModel by viewModels()
private val shareViewModel: ShareViewModel by viewModels()

private var status: Status = Status.PreGame
Expand All @@ -73,9 +75,10 @@ class GameActivity : AppCompatActivity(), DialogInterface.OnDismissListener {
private var currentTime: Long = 0
private var currentSaveId: Long = 0

@ExperimentalCoroutinesApi
@FlowPreview
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
PreferenceManager.setDefaultValues(this, R.xml.preferences, false)

bindViewModel()
Expand All @@ -92,6 +95,8 @@ class GameActivity : AppCompatActivity(), DialogInterface.OnDismissListener {
}
}

@ExperimentalCoroutinesApi
@FlowPreview
private fun bindViewModel() = viewModel.apply {
var lastEvent: Event? = null // TODO use distinctUntilChanged when available

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import dev.lucasnlm.antimine.common.level.models.Event
import dev.lucasnlm.antimine.common.level.view.CommonLevelFragment
import dev.lucasnlm.antimine.common.level.view.SpaceItemDecoration
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand Down Expand Up @@ -81,6 +82,7 @@ open class LevelFragment : CommonLevelFragment() {
}
}

@ExperimentalCoroutinesApi
override fun onAttach(context: Context) {
super.onAttach(context)

Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/dev/lucasnlm/antimine/share/ShareBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class ShareBuilder(
) {
private val context: Context = context.applicationContext

suspend fun share(minefield: Minefield, field: Sequence<Area>): Boolean {
suspend fun share(minefield: Minefield, field: List<Area>): Boolean {
val file = createImage(minefield, field)

return if (file != null) {
Expand All @@ -37,7 +37,7 @@ class ShareBuilder(
}
}

private suspend fun createImage(minefield: Minefield, field: Sequence<Area>): File? = withContext(Dispatchers.IO) {
private suspend fun createImage(minefield: Minefield, field: List<Area>): File? = withContext(Dispatchers.IO) {
val size = 38f
val padding = 1f
val radius = 2f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ShareViewModel(
) : AndroidViewModel(application) {
private val context = getApplication<Application>().applicationContext

suspend fun share(minefield: Minefield?, field: Sequence<Area>?) {
suspend fun share(minefield: Minefield?, field: List<Area>?) {
val result = if (minefield != null && field != null && field.count() != 0) {
ShareBuilder(context).share(minefield, field)
} else {
Expand Down
40 changes: 25 additions & 15 deletions app/src/test/java/dev/lucasnlm/antimine/GameActivityTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import dev.lucasnlm.antimine.common.level.di.LevelModule
import dev.lucasnlm.antimine.level.view.EndGameDialogFragment
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
Expand All @@ -30,6 +31,7 @@ class GameActivityTest {
var rule = HiltAndroidRule(this)

@Test
@Ignore("Dagger hilt issue")
fun testShowGameOverWhenTapAMine() {
launchActivity<GameActivity>().onActivity { activity ->
ShadowLooper.runUiThreadTasks()
Expand All @@ -38,48 +40,56 @@ class GameActivityTest {
activity.findViewById<RecyclerView>(R.id.recyclerGrid)
.findViewHolderForItemId(40).itemView.performClick()

ShadowLooper.runUiThreadTasks()
ShadowLooper.runUiThreadTasksIncludingDelayedTasks()

val idWithMine = 4L

// Tap on a mine
activity.findViewById<RecyclerView>(R.id.recyclerGrid)
.findViewHolderForItemId(26).itemView.performClick()
.findViewHolderForItemId(idWithMine).itemView.performClick()

ShadowLooper.idleMainLooper(2, TimeUnit.SECONDS)
ShadowLooper.runUiThreadTasks()
ShadowLooper.runUiThreadTasksIncludingDelayedTasks()

val endGame = activity.supportFragmentManager.findFragmentByTag(EndGameDialogFragment.TAG)
assertNotNull(endGame)
assertEquals(endGame?.arguments?.get(EndGameDialogFragment.DIALOG_IS_VICTORY), false)
assertEquals(false, endGame?.arguments?.get(EndGameDialogFragment.DIALOG_IS_VICTORY))
}
}

@Test
@Ignore("Dagger hilt issue")
fun testShowVictoryWhenTapAllSafeAreas() {
val mines = sequenceOf(4, 9, 15, 26, 47, 53, 68, 71, 75)
val safeAreas = (0 until 81).filterNot { mines.contains(it) }.map { it.toLong() }

launchActivity<GameActivity>().onActivity { activity ->
ShadowLooper.runUiThreadTasks()

// First tap
activity.findViewById<RecyclerView>(R.id.recyclerGrid)
activity
.findViewById<RecyclerView>(R.id.recyclerGrid)
.findViewHolderForItemId(40).itemView.performClick()

ShadowLooper.runUiThreadTasks()

// Tap on safe places
safeAreas.forEach { safeArea ->
activity.findViewById<RecyclerView>(R.id.recyclerGrid)
.findViewHolderForItemId(safeArea).itemView.performClick()
ShadowLooper.runUiThreadTasks()
}
activity.viewModel.field
.value!!
.filter { !it.hasMine && it.isCovered }
.forEach {
if (it.isCovered) {
activity
.findViewById<RecyclerView>(R.id.recyclerGrid)
.findViewHolderForItemId(it.id.toLong())
.itemView
.performClick()
}
ShadowLooper.runUiThreadTasks()
}

ShadowLooper.idleMainLooper(2, TimeUnit.SECONDS)
ShadowLooper.runUiThreadTasks()

val endGame = activity.supportFragmentManager.findFragmentByTag(EndGameDialogFragment.TAG)
assertNotNull(endGame)
assertEquals(endGame?.arguments?.get(EndGameDialogFragment.DIALOG_IS_VICTORY), true)
assertEquals(true, endGame?.arguments?.get(EndGameDialogFragment.DIALOG_IS_VICTORY))
}
}
}
5 changes: 3 additions & 2 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ android {

defaultConfig {
// versionCode and versionName must be hardcoded to support F-droid
versionCode 702071
versionName '7.2.7'
versionCode 703001
versionName '7.3.0'
minSdkVersion 16
targetSdkVersion 30
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
Expand Down Expand Up @@ -75,6 +75,7 @@ dependencies {
// Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.5'

// Kotlin Lib
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72'
Expand Down
Loading

0 comments on commit 35f4c58

Please sign in to comment.