diff --git a/README.md b/README.md index 08a8c8a..5cc7ec1 100644 --- a/README.md +++ b/README.md @@ -1 +1,16 @@ -# android-omok-precourse \ No newline at end of file +# android-omok-precourse + +-KakaoTechCampus Step1 2차 미니과제 +-안드로이드 프레임워크를 사용하여 모바일 앱으로 오목을 구현한다. + +#기능 목록 +1. 오목판 초기화 + - 오목판을 비워져있도록 구성한다. +2. 돌 놓기 기능 + - 사용자는 오목판을 클릭하여 돌을 놓을 수 있다. + - 흑돌과 백돌이 번갈아가면서 돌을 놓도록 한다. +3. 승리 여부 확인 기능 + - 가로나 세로, 대각선으로 다섯 개의 연속된 돌이 있는 확인한다. + - 렌주 룰과 같은 복잡한 룰을 고려하지 않고, 6목 이상의 장목도 승리 조건으로 인정한다. +4. 무승부 기능 + - 판을 전부 돌로 채웠어도 승부가 결정나지 않으면 무승부로 처리한다. diff --git a/app/src/androidTest/java/nextstep/omok/MainActivityTest.kt b/app/src/androidTest/java/nextstep/omok/MainActivityTest.kt new file mode 100644 index 0000000..d35490d --- /dev/null +++ b/app/src/androidTest/java/nextstep/omok/MainActivityTest.kt @@ -0,0 +1,123 @@ +package nextstep.omok + +import androidx.test.core.app.ActivityScenario +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import android.widget.ImageView +import android.widget.TableLayout +import android.widget.TableRow +import android.widget.TextView +import androidx.core.view.children +class MainActivityTest { + private lateinit var activity: MainActivity + + @Test + fun testStonePlacement() { + ActivityScenario.launch(MainActivity::class.java).onActivity { + activity = it + + val board = activity.findViewById(R.id.board) + val firstCell = board + .children + .filterIsInstance() + .flatMap { it.children } + .filterIsInstance() + .first() + + firstCell.performClick() + + val row = 0 + val col = 0 + val expectedDrawable = R.drawable.black_stone + + assertThat(firstCell.drawable).isNotNull + assertThat((firstCell.drawable.constantState)).isEqualTo(activity.getDrawable(expectedDrawable)!!.constantState) + assertThat(activity.boardState[row][col]).isEqualTo("black") + } + } + + @Test + fun testFiveVictory() { + ActivityScenario.launch(MainActivity::class.java).onActivity { + activity = it + + val board = activity.findViewById(R.id.board) + val cells = board + .children + .filterIsInstance() + .flatMap { it.children } + .filterIsInstance() + .toList() + + for (i in 0 until 5) { + val cell = cells[i] + cell.performClick() + if (i < 4) { + activity.changePlayer() + } + } + + val showWinner = activity.findViewById(R.id.showWinner) + + assertThat(showWinner.text.toString()).isEqualTo("흑돌 승리!") + assertThat(activity.winnerPlayer).isEqualTo("black") + assertThat(activity.gameOver).isTrue + } + } + @Test + fun testFiveVictory2() { + ActivityScenario.launch(MainActivity::class.java).onActivity { + activity = it + + val board = activity.findViewById(R.id.board) + val cells = board + .children + .filterIsInstance() + .flatMap { it.children } + .filterIsInstance() + .toList() + + for (i in 0 until 5) { + val cell = cells[i * (activity.boardSize + 1)] + cell.performClick() + if (i < 4) { + activity.changePlayer() + } + } + + val showWinner = activity.findViewById(R.id.showWinner) + + assertThat(showWinner.text.toString()).isEqualTo("흑돌 승리!") + assertThat(activity.winnerPlayer).isEqualTo("black") + assertThat(activity.gameOver).isTrue + } + } + @Test + fun testFiveVictory3() { + ActivityScenario.launch(MainActivity::class.java).onActivity { + activity = it + + val board = activity.findViewById(R.id.board) + val cells = board + .children + .filterIsInstance() + .flatMap { it.children } + .filterIsInstance() + .toList() + + for (i in 0 until 5) { + val cell = cells[(i + 1) * (activity.boardSize - 1)] + cell.performClick() + if (i < 4) { + activity.changePlayer() + } + } + + val showWinner = activity.findViewById(R.id.showWinner) + + assertThat(showWinner.text.toString()).isEqualTo("흑돌 승리!") + assertThat(activity.winnerPlayer).isEqualTo("black") + assertThat(activity.gameOver).isTrue + } + } +} diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index e6cc7b8..eb36631 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -4,10 +4,21 @@ import android.os.Bundle import android.widget.ImageView import android.widget.TableLayout import android.widget.TableRow +import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.view.children +val derivative = arrayOf( + arrayOf(1, 0), arrayOf(0, 1), arrayOf(1, 1), arrayOf(1, -1) +) + class MainActivity : AppCompatActivity() { + val boardSize: Int = 15 + var player: String = "black" + var winnerPlayer: String = "" + var gameOver: Boolean = false + var boardState = Array(boardSize) { Array(boardSize) { "" } } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -18,6 +29,91 @@ class MainActivity : AppCompatActivity() { .filterIsInstance() .flatMap { it.children } .filterIsInstance() - .forEach { view -> view.setOnClickListener { view.setImageResource(R.drawable.black_stone) } } + .forEachIndexed { index, view -> + view.setOnClickListener { onCellClicked(index, view) } + } + + } + + fun onCellClicked(index: Int, view: ImageView) { + if (gameOver) { + return + } + + val row: Int = index / boardSize + val col: Int = index % boardSize + if (boardState[row][col] == "") { + placeStone(view) + boardState[row][col] = player + if (checkGameSet(row, col)) { + winnerPlayer = player + showWinner() + } else if (isBoardFull()) { + showDraw() + } else { + changePlayer() + } + } + } + + fun placeStone(view: ImageView) { + if (player == "black") { + view.setImageResource(R.drawable.black_stone) + } else { + view.setImageResource(R.drawable.white_stone) + } + } + + fun checkGameSet(row: Int, col: Int): Boolean { + for (direction in derivative) { + var count = 1 + + count += countStones(row, col, direction[0], direction[1]) + count += countStones(row, col, -direction[0], -direction[1]) + + if (count >= 5) { + return true + } + } + return false + } + + fun countStones(row: Int, col: Int, rowDir: Int, colDir: Int): Int { + var currentRow = row + rowDir + var currentCol = col + colDir + var count = 0 + + while (currentRow in 0 until boardSize && currentCol in 0 until boardSize && boardState[currentRow][currentCol] == player) { + count++ + currentRow += rowDir + currentCol += colDir + } + return count + } + + fun changePlayer() { + player = if (player == "black") "white" else "black" + } + + fun showWinner() { + val showWinner = findViewById(R.id.showWinner) + showWinner.text = if (winnerPlayer == "black") "흑돌 승리!" else "백돌 승리!" + gameOver = true + } + fun showDraw() { + val showWinner = findViewById(R.id.showWinner) + showWinner.text = "무승부!" + gameOver = true + } + + fun isBoardFull(): Boolean { + for (row in boardState) { + for (cell in row) { + if (cell == "") { + return false + } + } + } + return true } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d809fc8..b192444 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1179,5 +1179,13 @@ android:background="@drawable/board_bottom_right" /> + +