Skip to content
This repository has been archived by the owner on Jul 7, 2022. It is now read-only.

Refactor AR Screen to not destroy all pieces' node #391

Merged
merged 49 commits into from May 25, 2022
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
0334155
Integrate the AR with the new delegation state
KurohanaJuri May 15, 2022
c58be93
Piece move on state changes
KurohanaJuri May 16, 2022
d74a32c
Change `currentPieces` map type
KurohanaJuri May 16, 2022
f2d4b27
Remove old pieces
KurohanaJuri May 16, 2022
4f143d0
Merge branch 'main' into refactor/cyk/update_pieces
KurohanaJuri May 16, 2022
17d9bca
Piece update correctly (eat, move, promotion)
KurohanaJuri May 16, 2022
7df005f
Merge branch 'main' of github.com:epfl-SDP/android into refactor/cyk/…
KurohanaJuri May 17, 2022
472e98f
Remove unused functions
KurohanaJuri May 17, 2022
f0668bf
Extract to have a function that create and place a pieces
KurohanaJuri May 17, 2022
d275abb
re
KurohanaJuri May 17, 2022
6b54b6a
Remove null check on context
KurohanaJuri May 17, 2022
811181d
Clean `updateBoard`
KurohanaJuri May 17, 2022
877bf0d
Remove private on `context`
KurohanaJuri May 17, 2022
5221135
Remove useless check `isLoaded`
KurohanaJuri May 17, 2022
f1a7528
Add doc on `ArGameScrrenState`
KurohanaJuri May 17, 2022
94d0bf5
Add doc on `DelegatingArState`
KurohanaJuri May 17, 2022
538f1ec
update old tests
KurohanaJuri May 17, 2022
308523c
Add private modifier on `toArPosition`
KurohanaJuri May 17, 2022
ea23fba
Merge branch 'main' of github.com:epfl-SDP/android into refactor/cyk/…
KurohanaJuri May 17, 2022
d56f3e8
Fix formatting
KurohanaJuri May 17, 2022
215aa3d
Add private context and throw error if null
KurohanaJuri May 18, 2022
341a055
Merge branch 'refactor/cyk/update_pieces' of github.com:epfl-SDP/andr…
KurohanaJuri May 18, 2022
801de48
Add and update tests on `ChessScene`
KurohanaJuri May 18, 2022
2b61fef
Use `runTest` instead of `TestScope`
KurohanaJuri May 18, 2022
3b480e1
Use truth in `ChessSceneTest`
KurohanaJuri May 18, 2022
76bc70e
remove useless context as parameter of some functions
KurohanaJuri May 18, 2022
d299d7d
Update outdated doc
KurohanaJuri May 18, 2022
c60682e
Simplify Ar delegation
KurohanaJuri May 18, 2022
236215d
Use chanel and flow to update the board
KurohanaJuri May 23, 2022
eed10da
Move the scene inside the composable
KurohanaJuri May 23, 2022
27dad19
Fix formatting
KurohanaJuri May 24, 2022
625d292
Update ChessSceneTest to take correct value + add test
KurohanaJuri May 24, 2022
c2fc401
Remove unused thing in `ChessScene`
KurohanaJuri May 24, 2022
514d450
Merge branch 'main' of github.com:epfl-SDP/android into refactor/cyk/…
KurohanaJuri May 24, 2022
52fac8c
Simplfy the ÀrChessBoardScreen`
KurohanaJuri May 24, 2022
1e84fc6
Fix formatting
KurohanaJuri May 24, 2022
ef36444
Increase the `waitUntil` timeout
KurohanaJuri May 24, 2022
314dae5
Add test for `DelegatingArState`
KurohanaJuri May 24, 2022
3a13d59
Remove `DelegatingArState` and use `ChessBoardState` instead
KurohanaJuri May 25, 2022
2782014
Remove `ArGameScreenState`
KurohanaJuri May 25, 2022
0517738
Create a const val for the timeout in `ChessSceneTest`
KurohanaJuri May 25, 2022
1827d7d
Fix typo
KurohanaJuri May 25, 2022
a85ea39
Move BBox declaration location
KurohanaJuri May 25, 2022
54e7405
Remove old documentation
KurohanaJuri May 25, 2022
d555265
Merge branch 'refactor/cyk/update_pieces' of github.com:epfl-SDP/andr…
KurohanaJuri May 25, 2022
1bc91f2
Add doc for `currentPieces` inside `ChessScene`
KurohanaJuri May 25, 2022
884ec5e
Use `ActivityScenarioRule` inside `ChessSceneTest`
KurohanaJuri May 25, 2022
efed896
Fix some typo
KurohanaJuri May 25, 2022
c28d57f
Merge branch 'main' into refactor/cyk/update_pieces
alexandrepiveteau May 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,151 +1,90 @@
package ch.epfl.sdp.mobile.test.ui.game.ar

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import ch.epfl.sdp.mobile.state.HomeActivity
import ch.epfl.sdp.mobile.ui.game.ChessBoardState
import androidx.test.ext.junit.rules.ActivityScenarioRule
import ch.epfl.sdp.mobile.application.chess.engine.Color.*
import ch.epfl.sdp.mobile.application.chess.engine.Game
import ch.epfl.sdp.mobile.application.chess.engine.Piece as EnginePiece
import ch.epfl.sdp.mobile.application.chess.engine.PieceIdentifier
import ch.epfl.sdp.mobile.application.chess.engine.Rank
import ch.epfl.sdp.mobile.state.game.delegating.DelegatingChessBoardState.Companion.toPosition
import ch.epfl.sdp.mobile.state.game.delegating.DelegatingChessBoardState.Piece
import ch.epfl.sdp.mobile.ui.game.ChessBoardState.*
import ch.epfl.sdp.mobile.ui.game.ar.ChessScene
import dev.romainguy.kotlin.math.Float3
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import com.google.common.truth.Truth.assertThat
import io.github.sceneview.math.Scale
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.yield
import org.junit.Rule
import org.junit.Test

class ChessSceneTest {
@get:Rule val rule = createAndroidComposeRule<HomeActivity>()

class SinglePieceSnapshotChessBoardState(
private val piece: ChessBoardState.Piece =
object : ChessBoardState.Piece {
override val color = ChessBoardState.Color.White
override val rank = ChessBoardState.Rank.Pawn
},
) : ChessBoardState<ChessBoardState.Piece> {
var position: ChessBoardState.Position by mutableStateOf(ChessBoardState.Position(0, 0))

override val pieces: Map<ChessBoardState.Position, ChessBoardState.Piece>
get() = mapOf(position to piece)
override val checkPosition: ChessBoardState.Position? = null
override val lastMove: Set<ChessBoardState.Position> = emptySet()
}

@Test
fun given_emptyState_when_initChessScene_then_rootIsNotNull() {
val state = SinglePieceSnapshotChessBoardState()
val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)
@get:Rule val rule = ActivityScenarioRule(ComponentActivity::class.java)

assertNotEquals(null, chessScene.boardNode)
}
private val simpleBoard =
Game.create().board.associate { (pos, piece) -> pos.toPosition() to Piece(piece) }

@Test
fun given_chessScene_when_scaled_then_rootHasCorrectScaleVector() {
val state = SinglePieceSnapshotChessBoardState()
val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)

chessScene.scale(4f)
assertEquals(Float3(4f), chessScene.boardNode.scale)
fun given_emptyState_when_initChessScene_then_has32ChildrenNodes() = runTest {
rule.scenario.onActivity {
val chessScene = ChessScene(it.applicationContext, it.lifecycleScope, simpleBoard)

launch {
yieldWhile { chessScene.boardNode.children.size != simpleBoard.size }
assertThat(chessScene.boardNode.children.size).isEqualTo(simpleBoard.size)
}
}
}

@Test
fun given_stateWithOneKing_when_initChessScene_then_rootIsNotNull() {
val piece =
object : ChessBoardState.Piece {
override val color = ChessBoardState.Color.Black
override val rank = ChessBoardState.Rank.King
}
val state = SinglePieceSnapshotChessBoardState(piece)

val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)
assertNotEquals(null, chessScene.boardNode)
}
fun given_chessScene_when_scaled_then_rootHasCorrectScaleVector() = runTest {
rule.scenario.onActivity {
val chessScene = ChessScene(it.applicationContext, it.lifecycleScope, simpleBoard)

@Test
fun given_stateWithOneBishop_when_initChessScene_then_rootIsNotNull() {
val piece =
object : ChessBoardState.Piece {
override val color = ChessBoardState.Color.Black
override val rank = ChessBoardState.Rank.Bishop
}
val state = SinglePieceSnapshotChessBoardState(piece)

val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)
assertNotEquals(null, chessScene.boardNode)
}
launch {
yieldWhile { chessScene.boardNode.children.size != simpleBoard.size }

@Test
fun given_stateWithOneKnight_when_initChessScene_then_rootIsNotNull() {
val piece =
object : ChessBoardState.Piece {
override val color = ChessBoardState.Color.Black
override val rank = ChessBoardState.Rank.Knight
}
val state = SinglePieceSnapshotChessBoardState(piece)

val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)
assertNotEquals(null, chessScene.boardNode)
chessScene.scale(4f)
assertThat(chessScene.boardNode.scale).isEqualTo(Scale(4f))
}
}
}

@Test
fun given_stateWithOnePawn_when_initChessScene_then_rootIsNotNull() {
val piece =
object : ChessBoardState.Piece {
override val color = ChessBoardState.Color.Black
override val rank = ChessBoardState.Rank.Pawn
}
val state = SinglePieceSnapshotChessBoardState(piece)

val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)
assertNotEquals(null, chessScene.boardNode)
}
fun given_chessScene_whenUpdated_then_haveCorrectNumberOfChildren() = runTest {
rule.scenario.onActivity {
val chessScene = ChessScene(it.applicationContext, it.lifecycleScope, simpleBoard)

@Test
fun given_stateWithOneQueen_when_initChessScene_then_rootIsNotNull() {
val piece =
object : ChessBoardState.Piece {
override val color = ChessBoardState.Color.Black
override val rank = ChessBoardState.Rank.Queen
}
val state = SinglePieceSnapshotChessBoardState(piece)

val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)
assertNotEquals(null, chessScene.boardNode)
}
val iterator = simpleBoard.entries.iterator()
val oldMovePiece = iterator.next()
val newMovePiece = oldMovePiece.apply { (Position(4, 4) to value) }.toPair()

@Test
fun given_stateWithOneRook_when_initChessScene_then_rootIsNotNull() {
val piece =
object : ChessBoardState.Piece {
override val color = ChessBoardState.Color.Black
override val rank = ChessBoardState.Rank.Rook
}
val state = SinglePieceSnapshotChessBoardState(piece)

val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)
assertNotEquals(null, chessScene.boardNode)
}
val newPiece = (Position(4, 5) to Piece(EnginePiece(White, Rank.Pawn, PieceIdentifier(40))))
val newBoard = mapOf(newMovePiece, newPiece)

@Test
fun given_stateWithOneWhitePawn_when_initChessScene_then_rootIsNotNull() {
val piece =
object : ChessBoardState.Piece {
override val color = ChessBoardState.Color.White
override val rank = ChessBoardState.Rank.Pawn
}
val state = SinglePieceSnapshotChessBoardState(piece)

val chessScene =
ChessScene(rule.activity.applicationContext, rule.activity.lifecycleScope, state.pieces)
assertNotEquals(null, chessScene.boardNode)
launch {
yieldWhile { chessScene.boardNode.children.size != simpleBoard.size }

chessScene.update(newBoard)
}

launch {
yieldWhile { chessScene.boardNode.children.size != newBoard.size }

assertThat(chessScene.boardNode.children.size).isEqualTo(newBoard.size)
}
}
}
}

/**
* This function yields until the [predicate] is not satisfied.
*
* @param predicate if this function returns true yield, otherwise the function ends.
*/
private suspend fun yieldWhile(predicate: () -> Boolean) {
while (predicate()) yield()
}
14 changes: 4 additions & 10 deletions mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefullArScreen.kt
Expand Up @@ -17,17 +17,11 @@ fun StatefulArScreen(
modifier: Modifier = Modifier,
) {

val facade = LocalChessFacade.current
val chessFacade = LocalChessFacade.current
val scope = rememberCoroutineScope()
val match = remember(facade, id) { facade.match(id) }
val match = remember(chessFacade, id) { chessFacade.match(id) }

val gameScreenState =
remember(match, scope) {
ActualChessBoardState(
match = match,
scope = scope,
)
}
val state = remember(match, scope) { ActualChessBoardState(match, scope) }

ArChessBoardScreen(gameScreenState, modifier)
ArChessBoardScreen(state, modifier)
}
Expand Up @@ -44,14 +44,15 @@ fun <Piece : ChessBoardState.Piece> ArChessBoardScreen(

chessScene =
ChessScene(context, view.lifecycleScope, state.pieces).apply {
// Scale the whole scene to the desired size
scale(BoardScale)
}

// Place the chess board on the taped position
arSceneView.onTouchAr =
{ hitResult, _ ->
anchorOrMoveBoard(arSceneView, chessScene, hitResult.createAnchor())
// Scale the board
this.scale(BoardScale)

// Place the chess board on the tapped position.
arSceneView.onTouchAr =
{ hitResult, _ ->
anchorOrMoveBoard(arSceneView, chessScene, hitResult.createAnchor())
}
}

arSceneView
Expand Down