diff --git a/README.md b/README.md
index 08a8c8a..64ee9ac 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,40 @@
-# android-omok-precourse
\ No newline at end of file
+# android-omok-precourse
+
+## 1. 기능 목록
+---
+### 1. 리소스 파일 추가
+- [x] 로고 리소스 파일 추가하기
+- [x] 폰트 리소스 파일 추가하기
+- [x] 커스텀 버튼 드로우블 제작하기
+- [x] 커스텀 컬러 추가하기
+
+### 2. 모델 구현
+- [x] 게임 모델 구현
+- [x] 플레이어 모델 구현
+
+### 3. 뷰 구성
+- [x] 메인 화면 뷰 구성하기
+- [x] 오목판 뷰 구성하기
+- [x] 승리 시 팝업 뷰 구성
+
+### 4. 기능 구현
+- [x] 메인 화면에서 오목판으로 화면 전환 기능 추가
+- [x] 게임 초기화 기능 추가
+- [x] 오목판에 돌 놓기 기능 추가
+- [x] 플레이어 전환 기능 추가
+- [x] 승리 조건 확인 기능 추가
+- [x] 승리 시 팝업 표시 기능 추가
+
+
+### 5. 단위 테스트 추가
+- [x] 단위 테스트 추가
+---
+
+## 2. 스크린샷
+
+
+
+
+
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 41a5486..3ea3dae 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -60,4 +60,4 @@ dependencies {
androidTestImplementation("io.kotest:kotest-runner-junit5:5.8.0")
androidTestImplementation("de.mannodermaus.junit5:android-test-core:1.3.0")
androidTestRuntimeOnly("de.mannodermaus.junit5:android-test-runner:1.3.0")
-}
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 250f3db..d1c706e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,6 +12,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.Omok"
tools:targetApi="31">
+
@@ -23,4 +26,4 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/java/nextstep/omok/BoardActivity.kt b/app/src/main/java/nextstep/omok/BoardActivity.kt
new file mode 100644
index 0000000..8dd8711
--- /dev/null
+++ b/app/src/main/java/nextstep/omok/BoardActivity.kt
@@ -0,0 +1,88 @@
+package nextstep.omok
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.activity.enableEdgeToEdge
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+
+class BoardActivity : AppCompatActivity() {
+ private lateinit var turnImage: ImageView
+ private lateinit var newGame: TextView
+ private lateinit var gameBoardFragment: GameBoardFragment
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_board)
+
+ turnImage = findViewById(R.id.turnImage)
+ newGame = findViewById(R.id.newGameButton)
+
+ // 프래그먼트 추가
+ if (savedInstanceState==null){
+ gameBoardFragment = GameBoardFragment()
+ supportFragmentManager.beginTransaction()
+ .add(R.id.fragment_container, gameBoardFragment)
+ .commit()
+ } else {
+ gameBoardFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as GameBoardFragment
+ }
+
+ GameModel.resetGame()
+ updateTurnImage()
+
+ newGame.setOnClickListener {
+ resetGame()
+ }
+
+ }
+
+ // 턴 이미지 업데이트
+ fun updateTurnImage() {
+ turnImage.setImageResource(GameModel.getCurrentPlayerStoneResId())
+ }
+
+ // 새 게임 버튼 클릭시 게임 초기화
+ fun resetGame() {
+ GameModel.resetGame()
+ gameBoardFragment.resetBoard()
+ updateTurnImage()
+ }
+
+ // 승리 다이얼로그 표시
+ fun showWinDialog() {
+ val dialogView = layoutInflater.inflate(R.layout.popup_victory , null)
+ // 다이얼로그 생성 및 표시
+ val dialog = androidx.appcompat.app.AlertDialog.Builder(this).setView(dialogView).create()
+ dialog.show()
+
+ setWinnerImage(dialog)
+
+ dialog.findViewById(R.id.newGameButton)?.setOnClickListener {
+ resetGame()
+ dialog.dismiss()
+ }
+ dialog.findViewById(R.id.mainMenuButton)?.setOnClickListener {
+ // 메인 메뉴로 이동
+ navigateToMainMenu()
+ }
+ }
+
+ // 승자 이미지 설정
+ private fun setWinnerImage(dialog: androidx.appcompat.app.AlertDialog) {
+ val winnerImageView = dialog.findViewById(R.id.winner)
+ GameModel.winner?.let {
+ winnerImageView?.setImageResource(it.stoneResId)
+ }
+ }
+ // 메인 메뉴로 이동
+ private fun navigateToMainMenu() {
+ val intent = Intent(this, MainActivity::class.java)
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
+ startActivity(intent)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/nextstep/omok/GameBoardFragment.kt b/app/src/main/java/nextstep/omok/GameBoardFragment.kt
new file mode 100644
index 0000000..3a8e631
--- /dev/null
+++ b/app/src/main/java/nextstep/omok/GameBoardFragment.kt
@@ -0,0 +1,64 @@
+package nextstep.omok
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TableLayout
+import android.widget.TableRow
+import androidx.core.view.children
+import androidx.fragment.app.Fragment
+
+class GameBoardFragment: Fragment() {
+ private lateinit var board: TableLayout
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val view = inflater.inflate(R.layout.board, container, false)
+ setupBoard(view)
+ return view
+ }
+
+ private fun setupBoard(view: View) {
+ board = view.findViewById(R.id.board)
+ board.children.filterIsInstance().forEachIndexed { rowIndex, row ->
+ row.children.filterIsInstance().forEachIndexed { colIndex, cell ->
+ cell.setOnClickListener {
+ Log.d("testt", "${rowIndex}행 ${colIndex}눌림")
+ handleCellClick(rowIndex, colIndex)
+ }
+ }
+ }
+ }
+
+ private fun handleCellClick(x: Int, y: Int) {
+ if (GameModel.placeStone(x, y)) {
+ updateCell(x, y, GameModel.currentPlayer)
+ if (GameModel.checkWinCondition(x, y)) {
+ GameModel.handelWin()
+ (activity as? BoardActivity)?.showWinDialog()
+ } else {
+ GameModel.switchPlayer()
+ (activity as? BoardActivity)?.updateTurnImage()
+ }
+ }
+ }
+
+ fun updateCell(x: Int, y: Int, player: Player) {
+ val row = board.getChildAt(x) as? TableRow
+ val cell = row?.getChildAt(y) as? ImageView
+ cell?.setImageResource(player.stoneResId)
+ }
+
+ // 보드 초기화
+ fun resetBoard() {
+ board.children.filterIsInstance().forEach { row ->
+ row.children.filterIsInstance().forEach { cell ->
+ cell.setImageResource(0) // 이미지를 초기화
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/nextstep/omok/GameModel.kt b/app/src/main/java/nextstep/omok/GameModel.kt
new file mode 100644
index 0000000..6c28633
--- /dev/null
+++ b/app/src/main/java/nextstep/omok/GameModel.kt
@@ -0,0 +1,86 @@
+package nextstep.omok
+
+import android.util.Log
+
+// 싱글톤 패턴을 위해 object로 선언
+object GameModel {
+ var currentPlayer: Player = Player.BLACK // 우선 흑돌로 현재 플레이어 초기화
+ var board: Array> = Array(15) { arrayOfNulls(15) } // 15x15 보드, null로 초기화
+ var winner: Player? = null // 승리한 플레이어를 저장
+
+ // 방향 체크할 때 쓰기 위한 변수
+ private val directions = mapOf(
+ "Horizontal" to Pair(1, 0), // 가로
+ "Vertical" to Pair(0, 1), // 세로
+ "PositiveDiagonal" to Pair(1, 1), // 대각선 \
+ "NegativeDiagonal" to Pair(1, -1) // 대각선 /
+ )
+
+ fun resetGame() {
+ // NOTE: 게임 초기화 로직
+ for (i in board.indices) {
+ for (j in board[i].indices) {
+ board[i][j] = null // 보드의 각 위치를 null로 초기화
+ }
+ }
+ currentPlayer = Player.BLACK // 흑돌로 초기화
+ }
+ fun switchPlayer() {
+ // NOTE: 플레이어 전환 로직
+ currentPlayer = if (currentPlayer == Player.BLACK) Player.WHITE else Player.BLACK
+ }
+
+ fun checkWinCondition(x: Int, y: Int):Boolean{
+ // NOTE: 승리 조건 확인 로직
+ return checkDirection(x, y, directions["Horizontal"]!!) || // 가로
+ checkDirection(x, y, directions["Vertical"]!!) || // 세로
+ checkDirection(x, y, directions["PositiveDiagonal"]!!) || // 대각선 \
+ checkDirection(x, y, directions["NegativeDiagonal"]!!) // 대각선 /
+ }
+
+ // 각 방향 넣으면 해당 방향으로 5개 이상의 돌이 있는지 확인
+ private fun checkDirection(x: Int, y: Int, direction: Pair): Boolean {
+ val (dx, dy) = direction
+ val count = countStones(x, y, dx, dy) + countStones(x, y, -dx, -dy) + 1
+ return count >= 5
+ }
+
+ // 해당 방향으로 돌이 몇개 있는지 확인
+ private fun countStones(x: Int, y: Int, dx: Int, dy: Int): Int {
+ var count = 0
+ var nx = x + dx
+ var ny = y + dy
+
+ while (nx in board.indices && ny in board[nx].indices && board[nx][ny] == currentPlayer) {
+ count++
+ nx += dx
+ ny += dy
+ }
+
+ return count
+ }
+
+
+
+ fun placeStone(x: Int, y: Int): Boolean {
+ // NOTE: 현재 플레이어가 돌을 놓는 로직
+ if (board[x][y] == null) {
+ board[x][y] = currentPlayer // 현재 플레이어가 돌을 놓음
+ return true
+ }
+ return false
+ }
+
+ fun handelWin(): Player? {
+ // NOTE : 승리 조건이 만족되었을 때 winner 를 현재 플레이어로 초기화
+ winner = currentPlayer
+ return winner
+ }
+
+ fun getCurrentPlayerStoneResId(): Int {
+ // 현재 플레이어의 돌 리소스 파일 ID를 반환
+ return currentPlayer.stoneResId
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/nextstep/omok/MainActivity.kt b/app/src/main/java/nextstep/omok/MainActivity.kt
index e6cc7b8..b1b04ab 100644
--- a/app/src/main/java/nextstep/omok/MainActivity.kt
+++ b/app/src/main/java/nextstep/omok/MainActivity.kt
@@ -1,9 +1,12 @@
package nextstep.omok
+import android.annotation.SuppressLint
+import android.content.Intent
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
@@ -12,12 +15,12 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
- val board = findViewById(R.id.board)
- board
- .children
- .filterIsInstance()
- .flatMap { it.children }
- .filterIsInstance()
- .forEach { view -> view.setOnClickListener { view.setImageResource(R.drawable.black_stone) } }
+ val startGameButton = findViewById(R.id.startGameButton)
+ startGameButton.setOnClickListener {
+ val intent = Intent(this, BoardActivity::class.java)
+ startActivity(intent)
+ }
+
+
}
}
diff --git a/app/src/main/java/nextstep/omok/Player.kt b/app/src/main/java/nextstep/omok/Player.kt
new file mode 100644
index 0000000..b6fe49a
--- /dev/null
+++ b/app/src/main/java/nextstep/omok/Player.kt
@@ -0,0 +1,6 @@
+package nextstep.omok
+
+enum class Player(val color: String, val stoneResId: Int) {
+ BLACK("black", R.drawable.black_stone),
+ WHITE("white", R.drawable.white_stone)
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/custom_button.xml b/app/src/main/res/drawable/custom_button.xml
new file mode 100644
index 0000000..1e7e0bf
--- /dev/null
+++ b/app/src/main/res/drawable/custom_button.xml
@@ -0,0 +1,34 @@
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png
new file mode 100644
index 0000000..7475ecc
Binary files /dev/null and b/app/src/main/res/drawable/logo.png differ
diff --git a/app/src/main/res/font/seoulhangangeb.ttf b/app/src/main/res/font/seoulhangangeb.ttf
new file mode 100644
index 0000000..2903f6a
Binary files /dev/null and b/app/src/main/res/font/seoulhangangeb.ttf differ
diff --git a/app/src/main/res/layout/activity_board.xml b/app/src/main/res/layout/activity_board.xml
new file mode 100644
index 0000000..2334442
--- /dev/null
+++ b/app/src/main/res/layout/activity_board.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index d809fc8..99252fc 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,1183 +1,43 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ android:layout_height="match_parent">
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/board.xml b/app/src/main/res/layout/board.xml
new file mode 100644
index 0000000..d809fc8
--- /dev/null
+++ b/app/src/main/res/layout/board.xml
@@ -0,0 +1,1183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/popup_victory.xml b/app/src/main/res/layout/popup_victory.xml
new file mode 100644
index 0000000..5f3129c
--- /dev/null
+++ b/app/src/main/res/layout/popup_victory.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index ca1931b..0db4102 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,4 +7,11 @@
#FF018786
#FF000000
#FFFFFFFF
+
+ #F7DA91
+ #FFF5DA
+ #EEEEEE
+
+
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index e19adf7..01c48df 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -12,5 +12,7 @@
- ?attr/colorPrimaryVariant
+ - @font/seoulhangangeb
+
diff --git a/app/src/test/java/nextstep/omok/GameModelTest.kt b/app/src/test/java/nextstep/omok/GameModelTest.kt
new file mode 100644
index 0000000..7633d45
--- /dev/null
+++ b/app/src/test/java/nextstep/omok/GameModelTest.kt
@@ -0,0 +1,117 @@
+package nextstep.omok
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+class GameModelTest {
+
+ @BeforeEach
+ fun setUp() {
+ // 각 테스트 전에 게임을 초기화
+ GameModel.resetGame()
+ }
+
+ @Test
+ fun `resetGame should initialize the board and currentPlayer`() {
+ // 게임이 초기화되면 보드와 현재 플레이어를 확인
+ GameModel.resetGame()
+ assertThat(GameModel.board.all { row -> row.all { it == null } }).isTrue
+ assertThat(GameModel.currentPlayer).isEqualTo(Player.BLACK)
+ }
+
+ @Test
+ fun `placeStone should place stone and switch player B to W if valid`() {
+ // 돌을 놓을 수 있으면 돌을 놓고 플레이어를 전환 (블랙->화이트)
+ val x = 7
+ val y = 7
+ assertThat(GameModel.placeStone(x, y)).isTrue
+ assertThat(GameModel.board[x][y]).isEqualTo(Player.BLACK)
+ GameModel.switchPlayer()
+ assertThat(GameModel.currentPlayer).isEqualTo(Player.WHITE)
+ }
+
+ @Test
+ fun `placeStone should place stone and switch player W to B if valid`() {
+ // 돌을 놓을 수 있으면 돌을 놓고 플레이어를 전환 (화이트->블랙)
+ val x = 2
+ val y = 2
+ assertThat(GameModel.switchPlayer())
+ assertThat(GameModel.placeStone(x, y)).isTrue
+ assertThat(GameModel.board[x][y]).isEqualTo(Player.WHITE)
+ GameModel.switchPlayer()
+ assertThat(GameModel.currentPlayer).isEqualTo(Player.BLACK)
+ }
+
+ @Test
+ fun `placeStone should not place stone if already occupied`() {
+ // 이미 돌이 놓여진 위치에는 돌을 놓을 수 없음
+ val x = 7
+ val y = 7
+ GameModel.placeStone(x, y)
+ assertThat(GameModel.placeStone(x, y)).isFalse
+ }
+
+ @Test
+ fun `checkWinCondition should detect a win`() {
+ // 가로로 5개를 놓아서 승리 조건을 충족시킴
+ val x = 8
+ for (y in 0..4) {
+ GameModel.placeStone(x, y)
+ }
+ assertThat(GameModel.checkWinCondition(x, 4)).isTrue
+ }
+
+ @Test
+ fun `checkDirection should detect vertical win`() {
+ val y = 5
+ for (x in 0..4) {
+ GameModel.placeStone(x, y)
+ }
+ assertThat(GameModel.checkWinCondition(4, y)).isTrue
+ }
+
+ @Test
+ fun `checkDirection should detect positive diagonal win`() {
+ for (i in 0..4) {
+ GameModel.placeStone(i, i)
+ }
+ assertThat(GameModel.checkWinCondition(4, 4)).isTrue
+ }
+
+ @Test
+ fun `checkWinCondition should not detect a win incorrectly`() {
+ // 승리 조건을 충족하지 않도록 돌을 놓음
+ val x = 7
+ val y = 7
+ GameModel.placeStone(x, y)
+ GameModel.switchPlayer()
+ GameModel.placeStone(x, y + 1)
+ assertThat(GameModel.checkWinCondition(x, y)).isFalse
+ }
+
+ @Test
+ fun `switchPlayer should switch between black and white players`() {
+ // 플레이어 전환 로직 확인
+ assertThat(GameModel.currentPlayer).isEqualTo(Player.BLACK)
+ GameModel.switchPlayer()
+ assertThat(GameModel.currentPlayer).isEqualTo(Player.WHITE)
+ GameModel.switchPlayer()
+ assertThat(GameModel.currentPlayer).isEqualTo(Player.BLACK)
+ }
+
+ @Test
+ fun `getCurrentPlayerStoneResId should return correct resource id`() {
+ // 현재 플레이어의 돌 리소스 ID 확인
+ assertThat(GameModel.getCurrentPlayerStoneResId()).isEqualTo(Player.BLACK.stoneResId)
+ GameModel.switchPlayer()
+ assertThat(GameModel.getCurrentPlayerStoneResId()).isEqualTo(Player.WHITE.stoneResId)
+ }
+
+ @Test
+ fun `handleWin should set the winner correctly`() {
+ // 승리 처리가 정상적으로 수행되는지 확인
+ GameModel.handelWin()
+ assertThat(GameModel.winner).isEqualTo(Player.BLACK)
+ }
+}
diff --git a/build.gradle.kts b/build.gradle.kts
index 6465d17..bb93dab 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id("com.android.application") version "8.3.1" apply false
+ id("com.android.application") version "8.4.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
id("org.jlleitschuh.gradle.ktlint") version "12.1.0" apply false
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 3fa8f86..a80b22c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME