From 432594df16a04f7b3b39d77b9ceec5bf70bd38fe Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 20:15:16 +0900 Subject: [PATCH 01/12] docs: Update README.md --- README.md | 19 ++++++++++++++++++- .../main/java/nextstep/omok/MainActivity.kt | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 08a8c8a..7e0518b 100644 --- a/README.md +++ b/README.md @@ -1 +1,18 @@ -# android-omok-precourse \ No newline at end of file +# android-omok-precourse + +## 프로젝트 설명 +이 프로젝트는 카카오테크캠퍼스 2기 2회차 미니과제로, Kotlin으로 작성한 오목 게임입니다. 두 사람이 번갈아 돌을 놓아 가로나 세로, 대각선으로 다섯 개의 연속된 돌을 먼저 만들면 승리하는 게임입니다. + +## 게임 규칙 +- 6목 이상의 장목도 착수 가능하며 승리 조건으로 인정합니다. +- 렌주 룰과 같은 복잡한 룰은 고려하지 않습니다. + +## 구현 기능 목록 +1. 보드 초기화 및 플레이어 초기화 +2. 각 셀에 클릭 리스너 설정 +3. 돌 위치 선정 + - 유효한 자리 -> 돌 위치 확정 + - 유효하지 않은 자리 -> 돌 위치 재선정 메시지 출력 +4. 우승 조건 확인 + - O -> 우승 메시지 출력 및 초기화 + - X -> 플레이어 변경 diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index e6cc7b8..9c205ec 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -20,4 +20,4 @@ class MainActivity : AppCompatActivity() { .filterIsInstance() .forEach { view -> view.setOnClickListener { view.setImageResource(R.drawable.black_stone) } } } -} +} \ No newline at end of file From dd8b16ae14bb1f36064fe6eb6998d16e6ebb9151 Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 20:24:18 +0900 Subject: [PATCH 02/12] feat: Add initializeBoard function --- .../main/java/nextstep/omok/MainActivity.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 9c205ec..e3025f3 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -12,12 +12,20 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + initializeBoard() + } + + private fun initializeBoard() { val board = findViewById(R.id.board) - board - .children + board.children .filterIsInstance() - .flatMap { it.children } - .filterIsInstance() - .forEach { view -> view.setOnClickListener { view.setImageResource(R.drawable.black_stone) } } + .forEach { row -> + row.children + .filterIsInstance() + .forEach { view -> + view.setImageResource(0) + view.tag = null + } + } } } \ No newline at end of file From c723d8c605a5172828e0700a44f858ae990a5905 Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 20:30:38 +0900 Subject: [PATCH 03/12] feat: Add initializePlayer function --- app/src/main/java/nextstep/omok/MainActivity.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index e3025f3..b6249b0 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -7,12 +7,16 @@ import android.widget.TableRow import androidx.appcompat.app.AppCompatActivity import androidx.core.view.children +const val PLAYER_BLACK = 'B' +const val PLAYER_WHITE = 'W' + class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initializeBoard() + initializePlayer() } private fun initializeBoard() { @@ -28,4 +32,8 @@ class MainActivity : AppCompatActivity() { } } } + + private fun initializePlayer() { + var currentPlayer = PLAYER_BLACK + } } \ No newline at end of file From 90ecd028d6bab9a3054cf283589d9b8cad330f80 Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 20:35:20 +0900 Subject: [PATCH 04/12] feat: Add setCellClickListener function --- .../main/java/nextstep/omok/MainActivity.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index b6249b0..3838d28 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -4,6 +4,7 @@ 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 @@ -17,6 +18,7 @@ class MainActivity : AppCompatActivity() { initializeBoard() initializePlayer() + setCellClickListener() } private fun initializeBoard() { @@ -36,4 +38,21 @@ class MainActivity : AppCompatActivity() { private fun initializePlayer() { var currentPlayer = PLAYER_BLACK } + + private fun setCellClickListener() { + val board = findViewById(R.id.board) + board.children + .filterIsInstance() + .forEachIndexed { rowIndex, row -> + row.children + .filterIsInstance() + .forEachIndexed { colIndex, view -> + view.setOnClickListener { processClickedCell(rowIndex, colIndex) } + } + } + } + + private fun processClickedCell(row: Int, col: Int) { + Toast.makeText(this, "clicked", Toast.LENGTH_SHORT).show() + } } \ No newline at end of file From 80229a8ca625f0d442edeacc43b590f15d80907c Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 20:51:17 +0900 Subject: [PATCH 05/12] feat: Add processClickedCell function --- .../main/java/nextstep/omok/MainActivity.kt | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 3838d28..713ad37 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -12,6 +12,8 @@ const val PLAYER_BLACK = 'B' const val PLAYER_WHITE = 'W' class MainActivity : AppCompatActivity() { + + private var currentPlayer = PLAYER_BLACK override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -36,7 +38,7 @@ class MainActivity : AppCompatActivity() { } private fun initializePlayer() { - var currentPlayer = PLAYER_BLACK + currentPlayer = PLAYER_BLACK } private fun setCellClickListener() { @@ -53,6 +55,22 @@ class MainActivity : AppCompatActivity() { } private fun processClickedCell(row: Int, col: Int) { - Toast.makeText(this, "clicked", Toast.LENGTH_SHORT).show() + val board = findViewById(R.id.board) + val cell = (board.getChildAt(row) as TableRow).getChildAt(col) as ImageView + if (cell.drawable == null) { + if (currentPlayer == PLAYER_BLACK) { + cell.setImageResource(R.drawable.black_stone) + cell.tag = PLAYER_BLACK + currentPlayer = PLAYER_WHITE + } + else { + cell.setImageResource(R.drawable.white_stone) + cell.tag = PLAYER_WHITE + currentPlayer = PLAYER_BLACK + } + } + else { + Toast.makeText(this, "해당 위치에는 돌이 이미 존재합니다.\n다른 위치를 선택하세요.", Toast.LENGTH_SHORT).show() + } } } \ No newline at end of file From d66a993629d66dd517625bd7c627f546292cf705 Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 21:03:52 +0900 Subject: [PATCH 06/12] refactor: Divide set stone function into placeStone and togglePlayer functions --- .../main/java/nextstep/omok/MainActivity.kt | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 713ad37..5fea230 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -58,19 +58,31 @@ class MainActivity : AppCompatActivity() { val board = findViewById(R.id.board) val cell = (board.getChildAt(row) as TableRow).getChildAt(col) as ImageView if (cell.drawable == null) { - if (currentPlayer == PLAYER_BLACK) { - cell.setImageResource(R.drawable.black_stone) - cell.tag = PLAYER_BLACK - currentPlayer = PLAYER_WHITE - } - else { - cell.setImageResource(R.drawable.white_stone) - cell.tag = PLAYER_WHITE - currentPlayer = PLAYER_BLACK - } + placeStone(cell) + togglePlayer() } else { Toast.makeText(this, "해당 위치에는 돌이 이미 존재합니다.\n다른 위치를 선택하세요.", Toast.LENGTH_SHORT).show() } } + + private fun placeStone(cell: ImageView) { + if (currentPlayer == PLAYER_BLACK) { + cell.setImageResource(R.drawable.black_stone) + cell.tag = PLAYER_BLACK + } + else { + cell.setImageResource(R.drawable.white_stone) + cell.tag = PLAYER_WHITE + } + } + + private fun togglePlayer() { + if (currentPlayer == PLAYER_BLACK) { + currentPlayer = PLAYER_WHITE + } + else { + currentPlayer = PLAYER_BLACK + } + } } \ No newline at end of file From 931b6487d183c9e7483c33f9edf0da318b7a1a2c Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 21:14:13 +0900 Subject: [PATCH 07/12] feat: Add function to check win condition --- .../main/java/nextstep/omok/MainActivity.kt | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 5fea230..fd73c81 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -10,6 +10,7 @@ import androidx.core.view.children const val PLAYER_BLACK = 'B' const val PLAYER_WHITE = 'W' +const val BOARD_SIZE = 15 class MainActivity : AppCompatActivity() { @@ -85,4 +86,45 @@ class MainActivity : AppCompatActivity() { currentPlayer = PLAYER_BLACK } } + + private fun checkWin(row: Int, col: Int): Boolean { + val board = findViewById(R.id.board) + val cell = (board.getChildAt(row) as TableRow).getChildAt(col) as ImageView + val directions = listOf( + listOf(0 to 1, 0 to -1), + listOf(1 to 0, -1 to 0), + listOf(1 to 1, -1 to -1), + listOf(1 to -1, -1 to 1) + ) + for (direction in directions) { + var count = 1 + for ((dr, dc) in direction) { + count += countStonesInDirection(row, col, dr, dc, cell.tag as Char) + } + if (count >= 5) { + return true + } + } + return false + } + + private fun countStonesInDirection(row: Int, col: Int, dr: Int, dc: Int, player: Char): Int { + val board = findViewById(R.id.board) + var count = 0 + var r = row + dr + var c = col + dc + + while (r in 0 until BOARD_SIZE && c in 0 until BOARD_SIZE) { + val cell = (board.getChildAt(r) as TableRow).getChildAt(c) as ImageView + if (cell.tag == player) { + count ++ + r += dr + c += dc + } + else { + break + } + } + return count + } } \ No newline at end of file From b156e9d452cb532666252052e47825d5a8f6cb56 Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 21:20:01 +0900 Subject: [PATCH 08/12] feat: Add handleWin function --- app/src/main/java/nextstep/omok/MainActivity.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index fd73c81..5a5a127 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -60,7 +60,12 @@ class MainActivity : AppCompatActivity() { val cell = (board.getChildAt(row) as TableRow).getChildAt(col) as ImageView if (cell.drawable == null) { placeStone(cell) - togglePlayer() + if (checkWin(row, col)) { + handleWin() + } + else { + togglePlayer() + } } else { Toast.makeText(this, "해당 위치에는 돌이 이미 존재합니다.\n다른 위치를 선택하세요.", Toast.LENGTH_SHORT).show() @@ -78,6 +83,12 @@ class MainActivity : AppCompatActivity() { } } + private fun handleWin() { + Toast.makeText(this, "${currentPlayer}가 승리하였습니다.", Toast.LENGTH_LONG).show() + initializePlayer() + initializeBoard() + } + private fun togglePlayer() { if (currentPlayer == PLAYER_BLACK) { currentPlayer = PLAYER_WHITE From 39806037c5c978d17a2f2565e45fb6bab96552dd Mon Sep 17 00:00:00 2001 From: jooiss Date: Fri, 7 Jun 2024 21:29:05 +0900 Subject: [PATCH 09/12] refactor: Divide show toast message function --- app/src/main/java/nextstep/omok/MainActivity.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 5a5a127..3721c61 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -68,10 +68,13 @@ class MainActivity : AppCompatActivity() { } } else { - Toast.makeText(this, "해당 위치에는 돌이 이미 존재합니다.\n다른 위치를 선택하세요.", Toast.LENGTH_SHORT).show() + showInvalidMoveMessage() } } + private fun showInvalidMoveMessage() { + Toast.makeText(this, "해당 위치에는 돌이 이미 존재합니다.\n다른 위치를 선택하세요.", Toast.LENGTH_SHORT).show() + } private fun placeStone(cell: ImageView) { if (currentPlayer == PLAYER_BLACK) { cell.setImageResource(R.drawable.black_stone) @@ -84,11 +87,15 @@ class MainActivity : AppCompatActivity() { } private fun handleWin() { - Toast.makeText(this, "${currentPlayer}가 승리하였습니다.", Toast.LENGTH_LONG).show() + showWinMessage() initializePlayer() initializeBoard() } + private fun showWinMessage() { + Toast.makeText(this, "${currentPlayer}가 승리하였습니다.", Toast.LENGTH_LONG).show() + } + private fun togglePlayer() { if (currentPlayer == PLAYER_BLACK) { currentPlayer = PLAYER_WHITE From f153c36a79ec5cfe6246193f22445d8b84e29e3f Mon Sep 17 00:00:00 2001 From: jooiss Date: Sat, 8 Jun 2024 18:21:14 +0900 Subject: [PATCH 10/12] refactor: Divide OmokGame class --- .../main/java/nextstep/omok/MainActivity.kt | 132 ++++-------------- app/src/main/java/nextstep/omok/OmokGame.kt | 61 ++++++++ 2 files changed, 87 insertions(+), 106 deletions(-) create mode 100644 app/src/main/java/nextstep/omok/OmokGame.kt diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 3721c61..2a83707 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -8,141 +8,61 @@ import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.view.children -const val PLAYER_BLACK = 'B' -const val PLAYER_WHITE = 'W' -const val BOARD_SIZE = 15 - class MainActivity : AppCompatActivity() { - private var currentPlayer = PLAYER_BLACK + private val game = OmokGame() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - initializeBoard() - initializePlayer() - setCellClickListener() } private fun initializeBoard() { - val board = findViewById(R.id.board) - board.children - .filterIsInstance() - .forEach { row -> - row.children - .filterIsInstance() - .forEach { view -> - view.setImageResource(0) - view.tag = null - } - } - } - - private fun initializePlayer() { - currentPlayer = PLAYER_BLACK - } - - private fun setCellClickListener() { val board = findViewById(R.id.board) board.children .filterIsInstance() .forEachIndexed { rowIndex, row -> row.children .filterIsInstance() - .forEachIndexed { colIndex, view -> - view.setOnClickListener { processClickedCell(rowIndex, colIndex) } + .forEachIndexed { colIndex, cell -> + cell.setImageResource(0) + cell.tag = null + cell.setOnClickListener { onCellClicked(rowIndex, colIndex, cell) } } } } - private fun processClickedCell(row: Int, col: Int) { - val board = findViewById(R.id.board) - val cell = (board.getChildAt(row) as TableRow).getChildAt(col) as ImageView - if (cell.drawable == null) { - placeStone(cell) - if (checkWin(row, col)) { - handleWin() - } - else { - togglePlayer() + private fun onCellClicked(row: Int, col: Int, cell: ImageView) { + if (game.placeStone(row, col)) { + placeStone(cell, game.currentPlayer) + if (game.checkWin(row, col)) { + showWinMessage() + resetBoard() + } else { + game.togglePlayer() } - } - else { + } else { showInvalidMoveMessage() } } - private fun showInvalidMoveMessage() { - Toast.makeText(this, "해당 위치에는 돌이 이미 존재합니다.\n다른 위치를 선택하세요.", Toast.LENGTH_SHORT).show() - } - private fun placeStone(cell: ImageView) { - if (currentPlayer == PLAYER_BLACK) { - cell.setImageResource(R.drawable.black_stone) - cell.tag = PLAYER_BLACK - } - else { - cell.setImageResource(R.drawable.white_stone) - cell.tag = PLAYER_WHITE - } + private fun placeStone(cell: ImageView, player: Char) { + val resource = if (player == PLAYER_BLACK) R.drawable.black_stone else R.drawable.white_stone + cell.setImageResource(resource) + cell.tag = player } - private fun handleWin() { - showWinMessage() - initializePlayer() - initializeBoard() + private fun showInvalidMoveMessage() { + Toast.makeText(this, "해당 위치에는 돌이 이미 존재합니다.\n다른 위치를 선택하세요.", Toast.LENGTH_SHORT).show() } private fun showWinMessage() { - Toast.makeText(this, "${currentPlayer}가 승리하였습니다.", Toast.LENGTH_LONG).show() - } - - private fun togglePlayer() { - if (currentPlayer == PLAYER_BLACK) { - currentPlayer = PLAYER_WHITE - } - else { - currentPlayer = PLAYER_BLACK - } - } - - private fun checkWin(row: Int, col: Int): Boolean { - val board = findViewById(R.id.board) - val cell = (board.getChildAt(row) as TableRow).getChildAt(col) as ImageView - val directions = listOf( - listOf(0 to 1, 0 to -1), - listOf(1 to 0, -1 to 0), - listOf(1 to 1, -1 to -1), - listOf(1 to -1, -1 to 1) - ) - for (direction in directions) { - var count = 1 - for ((dr, dc) in direction) { - count += countStonesInDirection(row, col, dr, dc, cell.tag as Char) - } - if (count >= 5) { - return true - } - } - return false + Toast.makeText(this, "${game.currentPlayer}가 승리하였습니다.", Toast.LENGTH_LONG).show() } - private fun countStonesInDirection(row: Int, col: Int, dr: Int, dc: Int, player: Char): Int { - val board = findViewById(R.id.board) - var count = 0 - var r = row + dr - var c = col + dc - - while (r in 0 until BOARD_SIZE && c in 0 until BOARD_SIZE) { - val cell = (board.getChildAt(r) as TableRow).getChildAt(c) as ImageView - if (cell.tag == player) { - count ++ - r += dr - c += dc - } - else { - break - } - } - return count + private fun resetBoard() { + game.resetGame() + initializeBoard() } -} \ No newline at end of file +} diff --git a/app/src/main/java/nextstep/omok/OmokGame.kt b/app/src/main/java/nextstep/omok/OmokGame.kt new file mode 100644 index 0000000..1fcd1d1 --- /dev/null +++ b/app/src/main/java/nextstep/omok/OmokGame.kt @@ -0,0 +1,61 @@ +package nextstep.omok + +const val PLAYER_BLACK = 'B' +const val PLAYER_WHITE = 'W' +const val BOARD_SIZE = 15 + +class OmokGame { + var currentPlayer = PLAYER_BLACK + + private val board = Array(BOARD_SIZE) { Array(BOARD_SIZE) { null } } + + fun placeStone(row: Int, col: Int): Boolean { + if (board[row][col] == null) { + board[row][col] = currentPlayer + return true + } + return false + } + + fun checkWin(row: Int, col: Int): Boolean { + val directions = listOf( + listOf(0 to 1, 0 to -1), listOf(1 to 0, -1 to 0), listOf(1 to 1, -1 to -1), listOf(1 to -1, -1 to 1) + ) + for (direction in directions) { + var count = 1 + for ((dr, dc) in direction) { + count += countStonesInDirection(row, col, dr, dc) + } + if (count >= 5) { + return true + } + } + return false + } + + private fun countStonesInDirection(row: Int, col: Int, dr: Int, dc: Int): Int { + var count = 0 + var r = row + dr + var c = col + dc + + while (r in 0 until BOARD_SIZE && c in 0 until BOARD_SIZE && board[r][c] == currentPlayer) { + count++ + r += dr + c += dc + } + return count + } + + fun togglePlayer() { + currentPlayer = if (currentPlayer == PLAYER_BLACK) PLAYER_WHITE else PLAYER_BLACK + } + + fun resetGame() { + for (row in 0 until BOARD_SIZE) { + for (col in 0 until BOARD_SIZE) { + board[row][col] = null + } + } + currentPlayer = PLAYER_BLACK + } +} From c7f730d5f91dde8791c959e5e637c747abdc1480 Mon Sep 17 00:00:00 2001 From: jooiss Date: Sat, 8 Jun 2024 18:24:40 +0900 Subject: [PATCH 11/12] test: Add test code --- app/src/main/java/nextstep/omok/OmokGame.kt | 4 ++ app/src/test/java/OmokGameTest.kt | 50 +++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 app/src/test/java/OmokGameTest.kt diff --git a/app/src/main/java/nextstep/omok/OmokGame.kt b/app/src/main/java/nextstep/omok/OmokGame.kt index 1fcd1d1..581c753 100644 --- a/app/src/main/java/nextstep/omok/OmokGame.kt +++ b/app/src/main/java/nextstep/omok/OmokGame.kt @@ -58,4 +58,8 @@ class OmokGame { } currentPlayer = PLAYER_BLACK } + + fun getStone(row: Int, col: Int): Char? { + return board[row][col] + } } diff --git a/app/src/test/java/OmokGameTest.kt b/app/src/test/java/OmokGameTest.kt new file mode 100644 index 0000000..a4c6b2d --- /dev/null +++ b/app/src/test/java/OmokGameTest.kt @@ -0,0 +1,50 @@ +package nextstep.omok + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class OmokGameTest { + + private lateinit var game: OmokGame + + @BeforeEach + fun setUp() { + game = OmokGame() + } + + @Test + fun testPlaceStone() { + assertTrue(game.placeStone(0, 0)) + assertEquals(PLAYER_BLACK, game.getStone(0, 0)) + assertFalse(game.placeStone(0, 0)) + } + + @Test + fun testTogglePlayer() { + game.togglePlayer() + assertEquals(PLAYER_WHITE, game.currentPlayer) + game.togglePlayer() + assertEquals(PLAYER_BLACK, game.currentPlayer) + } + + @Test + fun testCheckWin() { + for (i in 0 until 5) { + game.placeStone(0, i) + } + assertTrue(game.checkWin(0, 4)) + assertFalse(game.checkWin(1, 2)) + } + + @Test + fun testResetGame() { + game.placeStone(0, 0) + game.resetGame() + assertNull(game.getStone(0, 0)) + assertEquals(PLAYER_BLACK, game.currentPlayer) + } +} \ No newline at end of file From 05a4048841526fe818a04a60de3b37851f4402af Mon Sep 17 00:00:00 2001 From: jooiss Date: Sat, 8 Jun 2024 19:07:21 +0900 Subject: [PATCH 12/12] feat: Add checkDraw function --- README.md | 3 +++ app/src/main/java/nextstep/omok/MainActivity.kt | 7 +++++++ app/src/main/java/nextstep/omok/OmokGame.kt | 4 ++++ app/src/test/java/OmokGameTest.kt | 11 +++++++++++ 4 files changed, 25 insertions(+) diff --git a/README.md b/README.md index 7e0518b..03b5b10 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,6 @@ 4. 우승 조건 확인 - O -> 우승 메시지 출력 및 초기화 - X -> 플레이어 변경 +5. 무승부 조건 확인 + - O -> 무승부 메시지 출력 및 초기화 + - X -> 플레이어 변경 diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt index 2a83707..c442f5b 100644 --- a/app/src/main/java/nextstep/omok/MainActivity.kt +++ b/app/src/main/java/nextstep/omok/MainActivity.kt @@ -39,6 +39,9 @@ class MainActivity : AppCompatActivity() { if (game.checkWin(row, col)) { showWinMessage() resetBoard() + } else if (game.isBoardFull()) { + showDrawMessage() + resetBoard() } else { game.togglePlayer() } @@ -61,6 +64,10 @@ class MainActivity : AppCompatActivity() { Toast.makeText(this, "${game.currentPlayer}가 승리하였습니다.", Toast.LENGTH_LONG).show() } + private fun showDrawMessage() { + Toast.makeText(this, "더 이상 돌을 놓을 위치가 존재하지 않습니다.\n무승부입니다.", Toast.LENGTH_LONG).show() + } + private fun resetBoard() { game.resetGame() initializeBoard() diff --git a/app/src/main/java/nextstep/omok/OmokGame.kt b/app/src/main/java/nextstep/omok/OmokGame.kt index 581c753..e1eb933 100644 --- a/app/src/main/java/nextstep/omok/OmokGame.kt +++ b/app/src/main/java/nextstep/omok/OmokGame.kt @@ -62,4 +62,8 @@ class OmokGame { fun getStone(row: Int, col: Int): Char? { return board[row][col] } + + fun isBoardFull(): Boolean { + return board.all { row -> row.all { cell -> cell != null }} + } } diff --git a/app/src/test/java/OmokGameTest.kt b/app/src/test/java/OmokGameTest.kt index a4c6b2d..0f2f768 100644 --- a/app/src/test/java/OmokGameTest.kt +++ b/app/src/test/java/OmokGameTest.kt @@ -40,6 +40,17 @@ class OmokGameTest { assertFalse(game.checkWin(1, 2)) } + @Test + fun testIsBoardFull() { + for (row in 0 until BOARD_SIZE) { + for (col in 0 until BOARD_SIZE) { + game.placeStone(row, col) + game.togglePlayer() + } + } + assertTrue(game.isBoardFull()) + } + @Test fun testResetGame() { game.placeStone(0, 0)