From 69b627bbec69c333ce5a786ef2098ace31e1039d Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 01:15:15 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) 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. 무승부 기능 + - 판을 전부 돌로 채웠어도 승부가 결정나지 않으면 무승부로 처리한다. From a1ac1286e0b2c3066a413465a9473a55224d5b19 Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 01:19:14 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20=EC=98=A4=EB=AA=A9=ED=8C=90=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=ED=99=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nextstep/omok/MainActivity.kt | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index e6cc7b8..217d969 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() { + private val boardSize: Int = 15; + private var player: String = "black" + private var winnerPlayer: String = "" + private var gameOver: Boolean = false + private val boardState = Array(boardSize) { Array(boardSize) { "" } } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -18,6 +29,31 @@ 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() + } + } + } + } From 4bdac2c8c93447a7341a1de4bcd97183d3402910 Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 01:21:58 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=EC=98=A4=EB=AA=A9=ED=8C=90=20?= =?UTF-8?q?=EB=8F=8C=20=EB=86=93=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/nextstep/omok/MainActivity.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 217d969..7a34011 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -55,5 +55,12 @@ class MainActivity : AppCompatActivity() { } } } + private fun placeStone(view: ImageView) { + if (player == "black") { + view.setImageResource(R.drawable.black_stone) + } else { + view.setImageResource(R.drawable.white_stone) + } + } } From a1ab0efb926ff048d5e6e8a59f65193fca9f31ab Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 01:27:20 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20=EC=8A=B9=EB=A6=AC=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=20=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nextstep/omok/MainActivity.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 7a34011..878f6f2 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -55,6 +55,7 @@ class MainActivity : AppCompatActivity() { } } } + private fun placeStone(view: ImageView) { if (player == "black") { view.setImageResource(R.drawable.black_stone) @@ -63,4 +64,30 @@ class MainActivity : AppCompatActivity() { } } + 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 + } } From a53bca4b0d1dd3ffb2d7e0df86081a163c67e3f0 Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 01:29:12 +0900 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20=ED=9D=91=EB=8F=8C=EA=B3=BC=20?= =?UTF-8?q?=EB=B0=B1=EB=8F=8C=20=EB=B2=88=EA=B0=88=EC=95=84=20=EB=91=90?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/nextstep/omok/MainActivity.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 878f6f2..876fafb 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -90,4 +90,8 @@ class MainActivity : AppCompatActivity() { } return count } + + private fun changePlayer() { + player = if (player == "black") "white" else "black" + } } From b27db3cf37d1f6080e0faf0cc505f7f71f866c80 Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 01:31:51 +0900 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20=EC=98=A4=EB=AA=A9=ED=8C=90=20?= =?UTF-8?q?=ED=95=98=EB=8B=A8=EC=97=90=20=EC=8A=B9=EC=9E=90=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/nextstep/omok/MainActivity.kt | 7 +++++++ app/src/main/res/layout/activity_main.xml | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 876fafb..6f4ca09 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -94,4 +94,11 @@ class MainActivity : AppCompatActivity() { private fun changePlayer() { player = if (player == "black") "white" else "black" } + + private fun showWinner() { + val showWinner = findViewById(R.id.showWinner) + showWinner.text = if (winnerPlayer == "black") "흑돌 승리!" else "백돌 승리!" + gameOver = 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" /> + + From 367ed1d7b0654438a6c55ed97927cb879bbd8557 Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 01:32:13 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20=EC=98=A4=EB=AA=A9=ED=8C=90=20?= =?UTF-8?q?=ED=95=98=EB=8B=A8=EC=97=90=20=EB=AC=B4=EC=8A=B9=EB=B6=80=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/nextstep/omok/MainActivity.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 6f4ca09..de39fa4 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -100,5 +100,20 @@ class MainActivity : AppCompatActivity() { showWinner.text = if (winnerPlayer == "black") "흑돌 승리!" else "백돌 승리!" gameOver = true } + private fun showDraw() { + val showWinner = findViewById(R.id.showWinner) + showWinner.text = "무승부!" + gameOver = true + } + private fun isBoardFull(): Boolean { + for (row in boardState) { + for (cell in row) { + if (cell == "") { + return false + } + } + } + return true + } } From c197503ba757a805206e95044992ea4e01cfc3ef Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 09:46:05 +0900 Subject: [PATCH 8/9] =?UTF-8?q?test:=20=EC=98=A4=EB=AA=A9=20=EA=B2=8C?= =?UTF-8?q?=EC=9E=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/omok/MainActivityTest.kt | 123 ++++++++++++++++++ .../main/java/nextstep/omok/MainActivity.kt | 20 +-- 2 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 app/src/androidTest/java/nextstep/omok/MainActivityTest.kt 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 de39fa4..15c7146 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -13,11 +13,11 @@ val derivative = arrayOf( ) class MainActivity : AppCompatActivity() { - private val boardSize: Int = 15; - private var player: String = "black" - private var winnerPlayer: String = "" - private var gameOver: Boolean = false - private val boardState = Array(boardSize) { Array(boardSize) { "" } } + 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) @@ -56,7 +56,7 @@ class MainActivity : AppCompatActivity() { } } - private fun placeStone(view: ImageView) { + fun placeStone(view: ImageView) { if (player == "black") { view.setImageResource(R.drawable.black_stone) } else { @@ -91,22 +91,22 @@ class MainActivity : AppCompatActivity() { return count } - private fun changePlayer() { + fun changePlayer() { player = if (player == "black") "white" else "black" } - private fun showWinner() { + fun showWinner() { val showWinner = findViewById(R.id.showWinner) showWinner.text = if (winnerPlayer == "black") "흑돌 승리!" else "백돌 승리!" gameOver = true } - private fun showDraw() { + fun showDraw() { val showWinner = findViewById(R.id.showWinner) showWinner.text = "무승부!" gameOver = true } - private fun isBoardFull(): Boolean { + fun isBoardFull(): Boolean { for (row in boardState) { for (cell in row) { if (cell == "") { From e69b80428d24c27eaae24c87102f3d29651e5693 Mon Sep 17 00:00:00 2001 From: ddangcong80 Date: Mon, 10 Jun 2024 09:47:06 +0900 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20MainActivity=20=EB=AC=B8=EB=B2=95=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/nextstep/omok/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 15c7146..eb36631 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -13,7 +13,7 @@ val derivative = arrayOf( ) class MainActivity : AppCompatActivity() { - val boardSize: Int = 15; + val boardSize: Int = 15 var player: String = "black" var winnerPlayer: String = "" var gameOver: Boolean = false