From eeb206714babebbee3d296225f1391f530a62b43 Mon Sep 17 00:00:00 2001 From: settle54 Date: Mon, 10 Jun 2024 06:22:49 +0900 Subject: [PATCH 1/4] save --- .../main/java/nextstep/omok/MainActivity.kt | 132 +++++++++++++++++- 1 file changed, 126 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index e6cc7b8..f03199a 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -4,20 +4,140 @@ import android.os.Bundle import android.widget.ImageView import android.widget.TableLayout import android.widget.TableRow +import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.view.children +enum class Player { + BLACK, WHITE, NONE +} + class MainActivity : AppCompatActivity() { + var currentPlayer = Player.BLACK + val boardSize = 15 + var boardState = Array(boardSize) { Array(boardSize) { Player.NONE } } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + setupBoard() + } + /** + * 보드를 설정하는 메소드. + */ + fun setupBoard() { val board = findViewById(R.id.board) - board - .children + for (rowIndex in 0 until boardSize) { + val tableRow = board.getChildAt(rowIndex) as TableRow + for (columnIndex in 0 until boardSize) { + val imageView = tableRow.getChildAt(columnIndex) as ImageView + imageView.setOnClickListener { putStones(rowIndex, columnIndex) } + } + } + } + + /** + * 돌을 놓을 때 이미지를 표시하는 메소드. + * putStones() 메소드에서 사용된다. + */ + fun updateImage(rowIndex: Int, columnIndex: Int) { + val cell = (findViewById(R.id.board).getChildAt(rowIndex) as TableRow) + .getChildAt(columnIndex) as ImageView + val resource = when (currentPlayer) { + Player.BLACK -> R.drawable.black_stone + Player.WHITE -> R.drawable.white_stone + else -> return + } + cell.setImageResource(resource) + cell.isEnabled = false + } + + /** + * 돌을 놓는 메소드. + * 돌을 놓을 때마다 승리 여부를 확인한 후, + * 한 쪽이 승리하면 메시지를 띄우고 게임을 다시 시작한다. + */ + fun putStones(rowIndex: Int, columnIndex: Int) { + if (boardState[rowIndex][columnIndex] == Player.NONE) { + boardState[rowIndex][columnIndex] = currentPlayer + updateImage(rowIndex, columnIndex) + if (checkWin(rowIndex, columnIndex)) { + endGame() + } else { + changePlayer() + } + } + } + + /** + * 주어진 방향으로 연속된 돌의 개수를 세는 메소드. + * checkWin() 메소드에서 사용된다. + */ + fun countStones(row: Int, col: Int, dRow: Int, dCol: Int): Int { + var count = 0 + var r = row + dRow + var c = col + dCol + while (r in 0 until boardSize && c in 0 until boardSize && boardState[r][c] == currentPlayer) { + count++ + r += dRow + c += dCol + } + return count + } + + /** + * 돌을 놓은 위치에서 승리 여부를 확인하는 메소드. + * 수평, 수직, 대각선 방향으로 연속된 돌의 개수를 구한 후, + * 한 방향에서 연속된 돌의 개수가 5 이상이면 승리로 간주한다. + */ + fun checkWin(rowIndex: Int, columnIndex: Int): Boolean { + val directions = arrayOf( + Pair(1, 0), Pair(0, 1), Pair(1, 1), Pair(1, -1) + ) + + for ((dx, dy) in directions) { + val count = 1 + countStones(rowIndex, columnIndex, dx, dy) + + countStones(rowIndex, columnIndex, -dx, -dy) + if (count >= 5) { + return true + } + } + return false + } + + /** + * 플레이어를 전환하는 메소드. + */ + fun changePlayer() { + currentPlayer = if (currentPlayer == Player.BLACK) Player.WHITE else Player.BLACK + } + + /** + * 보드를 초기화하는 메소드. + */ + fun resetBoard() { + boardState = Array(boardSize) { Array(boardSize) { Player.NONE } } + findViewById(R.id.board).children .filterIsInstance() - .flatMap { it.children } - .filterIsInstance() - .forEach { view -> view.setOnClickListener { view.setImageResource(R.drawable.black_stone) } } + .forEach { tableRow -> + tableRow.children.filterIsInstance().forEach { imageView -> + imageView.apply { + setImageDrawable(null) + isEnabled = true + } + } + } + currentPlayer = Player.BLACK } -} + + /** + * 게임 종료를 알리는 메소드. + * 게임 결과를 메시지로 띄우고 게임을 초기화한다. + */ + fun endGame() { + Toast.makeText(this, "${currentPlayer.name} 승리", Toast.LENGTH_LONG).show() + resetBoard() + } + +} \ No newline at end of file From 0be7d7e570895383310d56d1a6cca0af466886f7 Mon Sep 17 00:00:00 2001 From: settle54 Date: Mon, 10 Jun 2024 06:22:49 +0900 Subject: [PATCH 2/4] MainActivity Completion --- .../main/java/nextstep/omok/MainActivity.kt | 132 +++++++++++++++++- 1 file changed, 126 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index e6cc7b8..f03199a 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -4,20 +4,140 @@ import android.os.Bundle import android.widget.ImageView import android.widget.TableLayout import android.widget.TableRow +import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.view.children +enum class Player { + BLACK, WHITE, NONE +} + class MainActivity : AppCompatActivity() { + var currentPlayer = Player.BLACK + val boardSize = 15 + var boardState = Array(boardSize) { Array(boardSize) { Player.NONE } } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + setupBoard() + } + /** + * 보드를 설정하는 메소드. + */ + fun setupBoard() { val board = findViewById(R.id.board) - board - .children + for (rowIndex in 0 until boardSize) { + val tableRow = board.getChildAt(rowIndex) as TableRow + for (columnIndex in 0 until boardSize) { + val imageView = tableRow.getChildAt(columnIndex) as ImageView + imageView.setOnClickListener { putStones(rowIndex, columnIndex) } + } + } + } + + /** + * 돌을 놓을 때 이미지를 표시하는 메소드. + * putStones() 메소드에서 사용된다. + */ + fun updateImage(rowIndex: Int, columnIndex: Int) { + val cell = (findViewById(R.id.board).getChildAt(rowIndex) as TableRow) + .getChildAt(columnIndex) as ImageView + val resource = when (currentPlayer) { + Player.BLACK -> R.drawable.black_stone + Player.WHITE -> R.drawable.white_stone + else -> return + } + cell.setImageResource(resource) + cell.isEnabled = false + } + + /** + * 돌을 놓는 메소드. + * 돌을 놓을 때마다 승리 여부를 확인한 후, + * 한 쪽이 승리하면 메시지를 띄우고 게임을 다시 시작한다. + */ + fun putStones(rowIndex: Int, columnIndex: Int) { + if (boardState[rowIndex][columnIndex] == Player.NONE) { + boardState[rowIndex][columnIndex] = currentPlayer + updateImage(rowIndex, columnIndex) + if (checkWin(rowIndex, columnIndex)) { + endGame() + } else { + changePlayer() + } + } + } + + /** + * 주어진 방향으로 연속된 돌의 개수를 세는 메소드. + * checkWin() 메소드에서 사용된다. + */ + fun countStones(row: Int, col: Int, dRow: Int, dCol: Int): Int { + var count = 0 + var r = row + dRow + var c = col + dCol + while (r in 0 until boardSize && c in 0 until boardSize && boardState[r][c] == currentPlayer) { + count++ + r += dRow + c += dCol + } + return count + } + + /** + * 돌을 놓은 위치에서 승리 여부를 확인하는 메소드. + * 수평, 수직, 대각선 방향으로 연속된 돌의 개수를 구한 후, + * 한 방향에서 연속된 돌의 개수가 5 이상이면 승리로 간주한다. + */ + fun checkWin(rowIndex: Int, columnIndex: Int): Boolean { + val directions = arrayOf( + Pair(1, 0), Pair(0, 1), Pair(1, 1), Pair(1, -1) + ) + + for ((dx, dy) in directions) { + val count = 1 + countStones(rowIndex, columnIndex, dx, dy) + + countStones(rowIndex, columnIndex, -dx, -dy) + if (count >= 5) { + return true + } + } + return false + } + + /** + * 플레이어를 전환하는 메소드. + */ + fun changePlayer() { + currentPlayer = if (currentPlayer == Player.BLACK) Player.WHITE else Player.BLACK + } + + /** + * 보드를 초기화하는 메소드. + */ + fun resetBoard() { + boardState = Array(boardSize) { Array(boardSize) { Player.NONE } } + findViewById(R.id.board).children .filterIsInstance() - .flatMap { it.children } - .filterIsInstance() - .forEach { view -> view.setOnClickListener { view.setImageResource(R.drawable.black_stone) } } + .forEach { tableRow -> + tableRow.children.filterIsInstance().forEach { imageView -> + imageView.apply { + setImageDrawable(null) + isEnabled = true + } + } + } + currentPlayer = Player.BLACK } -} + + /** + * 게임 종료를 알리는 메소드. + * 게임 결과를 메시지로 띄우고 게임을 초기화한다. + */ + fun endGame() { + Toast.makeText(this, "${currentPlayer.name} 승리", Toast.LENGTH_LONG).show() + resetBoard() + } + +} \ No newline at end of file From c020e82377d80bb63a99315ddb53b5eb9ab9f6d7 Mon Sep 17 00:00:00 2001 From: settle54 Date: Mon, 10 Jun 2024 06:45:12 +0900 Subject: [PATCH 3/4] Modifying Readme --- README.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 08a8c8a..203ed33 100644 --- a/README.md +++ b/README.md @@ -1 +1,45 @@ -# android-omok-precourse \ No newline at end of file +# android-omok-precourse + +--- + +## 게임 설명 + +- 15x15 바둑판에 돌을 놓아 가로, 세로, 대각선으로 5개 이상을 연속으로 놓으면 승리하는 게임. + +- 흑돌이 먼저 시작하며, 흑돌과 백돌이 번갈아가며 착수한다. + +- 한 게임이 종료되면 바로 게임이 초기화된다. + +--- + +## 기능 목록 + +### setupBoard() +- 보드를 설정하는 메소드. + +### updateImage(Int, Int) +- 돌을 놓을 때 이미지를 표시하는 메소드. +- putStones() 메소드에서 사용된다. + +### putStones(Int, Int) +- 돌을 놓는 메소드. +- 돌을 놓을 때마다 승리 여부를 확인한 후, 한 쪽이 승리하면 메시지를 띄우고 게임을 다시 시작한다. + +### countStone(Int, Int, Int, Int) +- 주어진 방향으로 연속된 돌의 개수를 세는 메소드. +- checkWin() 메소드에서 사용된다. + +### checkWin(Int, Int) +- 돌을 놓은 위치에서 승리 여부를 확인하는 메소드. +- 수평, 수직, 대각선 방향으로 연속된 돌의 개수를 구한 후, +- 한 방향에서 연속된 돌의 개수가 5 이상이면 승리로 간주한다. + +### changePlayer() +- 플레이어를 전환하는 메소드. + +### resetBoard() +- 보드를 초기화하는 메소드. + +### endGame() +- 게임 종료를 알리는 메소드. +- 게임 결과를 메시지로 띄우고 게임을 초기화한다. \ No newline at end of file From d5c764fc0c6be5338829c0fa3c1a180b2c6c8b88 Mon Sep 17 00:00:00 2001 From: settle54 Date: Mon, 10 Jun 2024 14:01:15 +0900 Subject: [PATCH 4/4] feat: MainActivityTest --- .../java/nextstep/omok/MainTest.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 app/src/androidTest/java/nextstep/omok/MainTest.kt diff --git a/app/src/androidTest/java/nextstep/omok/MainTest.kt b/app/src/androidTest/java/nextstep/omok/MainTest.kt new file mode 100644 index 0000000..aa02b86 --- /dev/null +++ b/app/src/androidTest/java/nextstep/omok/MainTest.kt @@ -0,0 +1,28 @@ +package nextstep.omok + +import android.graphics.drawable.VectorDrawable +import android.widget.ImageView +import android.widget.TableLayout +import android.widget.TableRow +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.ext.junit.rules.ActivityScenarioRule +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +class MainTest { + + @get:Rule + var activityScenarioRule = ActivityScenarioRule(MainActivity::class.java) + + @Test + fun checkChangePlayer() { + activityScenarioRule.scenario.onActivity { activity -> + assertEquals(Player.BLACK, activity.currentPlayer) + activity.changePlayer() + assertEquals(Player.WHITE, activity.currentPlayer) + } + } + +} \ No newline at end of file