Skip to content

Commit

Permalink
[둘리] 3, 4단계 오목 제출합니다. (#34)
Browse files Browse the repository at this point in the history
* rebase: step2

* feat: set up the android project

* feat: domain 이동

* feat: add main activity and resources

* refactor(Omok, Controller): run 함수 삭제 및 컨트롤러로 이동

* feat(activity_main): TextView 추가

* feat(GameEventListener): GameEventListener 구현

* refactor(Omok): 필요없는 주석 삭제

* feat(Listener): 이벤트 리스너 구현 및 strings.xml에 string 정의

* feat(MainActivity): MainActivity 구현

* refactor(Activity, Listener): 패키지 이동

* refactor(Omok): endGame 함수 수정

* refactor(OmokTest): OmokTest 테스트 재구현

* refactor(InputView, OutputView): InputView OutputView 인터페이스 삭제

* refactor(TurnResult): TurnResult 생성, 점진적인 리팩터링

* refactor(MainActivity, PlayersTest): 필요없는 테스트 삭제, 도메인 변경에 따른 MainActivity 변경

* refactor(Players, Omok, Controller): Players 위치 Omok 안으로 변경, 안드로이드 TurnEventListener 삭제

* refactor(MainActivity, GameEventListener): 버그 수정

* refactor(OmokTest, PlayersTest): 리팩터링에 따른 테스트 수정

* feat(MainActivity, Omok, OmokConstract, OmokDBHelper, Players): 데이터베이스를 이용한 오목판 저장

* refactor(gitignore): gitignore 추가

* feat(DBManager): DB로부터 원하는 정보를 뽑아주는 DBManager 생성

* refactor(MainActivity): 메인 액티비티 리팩터링

* refactor(OmokDBManager): 필요없는 코드 삭제

* refactor(xml): 오목판 커스텀

* refactor(MainActivity): 오목판 세팅 함수 분리

* refactor(MainActivity): 필요없는 코드 삭제

* fix(WhitePlayerTest): 테스트 코드 수정

* refactor(xml): 필요없는 파일 삭제

* refactor(Players, Player): 놓은 돌의 개수를 반환하는 함수 작성

* refactor(PlayerState): points 변수 protected 삭제

* refactor(PlayerState): points 변수 protected 복구, getAllPoints 깊은 복사

* refactor(Black,WhitePlayerTest): 필요없는 정보 숨기기

* refactor(Points): Point List 깊은 복사

* refactor(PlayersTest): 테스트 코드 수정

* refactor(MainActivity): 코드 다이어트 및 by lazy 적용

* refactor(all): ktlintFormatting

* refactor(Players): latestPlayer 불변으로 변경

* refactor(Players, WhitePlayer, BlackPlayer): stone -> point로 명칭 변경, 최근 플레이어를 구하는 책임 이동

* refactor(OmokGameEventListener): InputView의 인터페이스 삭제, GameEventListener을 TurnEventListener로 명칭 변경

* fix(BlackPlayer, WhitePlayer): 오류 수정

* refactor(TurnResult): 턴의 결과를 모두 포함하도록 수정

* refactor(Omok): 필요없는 함수 삭제

* refactor(MainActivity, TurnEventListener): 도메인 변경에 따른 코드 변경

* refactor(Players, MainActivity): 필요없는 코드 삭제, 변수 네이밍 변경

* refactor(MainActivity, Controller, DBHelper, OutputView): 리스너, DB매니저 삭제, 뷰 설정 코드 메인 액티비티로 이동, DBHelper에 함수 추가

* refactor(ktlintFormat): ktlintformatting

* refactor(DBHelper): db를 변수로 가지도록 변경

* refactor(Players): Players 팩토리 함수 생성

* refactor(MainActivity): applicationContext -> this 변경

* refactor(MainActivity): 많은 if문 when문 사용하여 정리

* refactor(PlayersTest): 팩토리 함수 구현으로 인한 변경

* refactor(OmokDBHelper): 오목 도메인을 가질 수 있도록 수정

* refactor(MainActivity): onCreate에서 onClickListener 내용 분리

---------

Co-authored-by: woowahan-pjs <[email protected]>
  • Loading branch information
hyemdooly and woowahan-pjs committed Mar 29, 2023
1 parent 5ccb0b3 commit 50e7c2f
Show file tree
Hide file tree
Showing 101 changed files with 3,760 additions and 58 deletions.
Binary file added .DS_Store
Binary file not shown.
53 changes: 27 additions & 26 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
HELP.md
.gradle
# Gradle files
.gradle/
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**
!**/src/test/**

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
# Local configuration file (sdk path, etc)
local.properties

### IntelliJ IDEA ###
.idea
*.iws
# Log/OS Files
*.log

# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json

# IntelliJ
*.iml
*.ipr
out/
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml

# Keystore files
*.jks
*.keystore

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
# Google Services (e.g. APIs or Firebase)
google-services.json

### VS Code ###
.vscode/
# Android Profiling
*.hprof
Binary file added app/.DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
47 changes: 47 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}

android {
namespace = "woowacourse.omok"
compileSdk = 33

defaultConfig {
applicationId = "woowacourse.omok"
minSdk = 26
targetSdk = 33
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}

dependencies {
implementation(project(":domain"))
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.0")
implementation("com.google.android.material:material:1.7.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http:https://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Binary file added app/src/.DS_Store
Binary file not shown.
Empty file.
Binary file added app/src/main/.DS_Store
Binary file not shown.
23 changes: 23 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http:https://schemas.android.com/apk/res/android"
xmlns:tools="http:https://schemas.android.com/tools">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Oomok"
tools:targetApi="31">
<activity
android:name=".activity.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
123 changes: 123 additions & 0 deletions app/src/main/java/woowacourse/omok/activity/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package woowacourse.omok.activity

import android.os.Bundle
import android.widget.ImageView
import android.widget.TableLayout
import android.widget.TableRow
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.children
import domain.game.Omok
import domain.game.Omok.Companion.OMOK_BOARD_SIZE
import domain.player.BlackPlayer
import domain.player.WhitePlayer
import domain.point.Point
import domain.point.Points
import domain.result.TurnResult
import domain.rule.BlackRenjuRule
import domain.rule.WhiteRenjuRule
import domain.state.PlayingState
import domain.stone.StoneColor
import view.mapper.toPresentation
import woowacourse.omok.R
import woowacourse.omok.db.OmokDBHelper

class MainActivity : AppCompatActivity() {
private val boards: List<ImageView> by lazy { getBoardViews() }
private val descriptionView: TextView by lazy { findViewById(R.id.description) }
private val dbHelper: OmokDBHelper by lazy { OmokDBHelper(this) }
private val omok: Omok by lazy { initOmok() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

onStartGame()
onStartTurn(omok.players.curPlayerColor)
var result: TurnResult = TurnResult.Playing(false, omok.players)

boards.forEachIndexed { index, view ->
view.setOnClickListener { result = onClick(result, index, view) }
}
}

override fun onStop() {
super.onStop()
if (!omok.players.isPlaying) dbHelper.deleteAll()
}

override fun onDestroy() {
super.onDestroy()
dbHelper.close()
}

private fun initOmok(): Omok {
val blackIndexs = dbHelper.getIndexsByColor(StoneColor.BLACK)
val whiteIndexs = dbHelper.getIndexsByColor(StoneColor.WHITE)

blackIndexs.forEach {
setStone(boards[it], StoneColor.BLACK)
}
whiteIndexs.forEach {
setStone(boards[it], StoneColor.WHITE)
}

val blackPlayer = BlackPlayer(PlayingState(indexsToPoints(blackIndexs)), rule = BlackRenjuRule())
val whitePlayer = WhitePlayer(PlayingState(indexsToPoints(whiteIndexs)), rule = WhiteRenjuRule())
return Omok(blackPlayer, whitePlayer)
}

private fun onStartGame() {
Toast.makeText(this, R.string.start_game, Toast.LENGTH_LONG).show()
}

private fun onClick(result: TurnResult, index: Int, view: ImageView): TurnResult {
if (result !is TurnResult.Playing) return result
val nextResult = omok.takeTurn(calculateIndexToPoint(index))
onEndTurn(view, index, nextResult)
onEndGame(nextResult)
return nextResult
}

private fun onEndGame(result: TurnResult) {
val descriptionView = findViewById<TextView>(R.id.description)
when (result) {
is TurnResult.Playing -> return
is TurnResult.Foul -> descriptionView.text = this.getString(R.string.is_forbidden).plus(this.getString(R.string.who_is_winner).format(result.winColor.toPresentation().text))
is TurnResult.Win -> descriptionView.text = this.getString(R.string.who_is_winner).format(result.winColor.toPresentation().text)
}
Toast.makeText(this, R.string.end_game, Toast.LENGTH_LONG).show()
}

private fun onStartTurn(stoneColor: StoneColor) {
descriptionView.text = this.getString(R.string.who_is_turn).format(stoneColor.toPresentation().text)
}

private fun setStone(view: ImageView, color: StoneColor) {
when (color) {
StoneColor.BLACK -> view.setImageResource(R.drawable.pink_bear)
StoneColor.WHITE -> view.setImageResource(R.drawable.white_bear)
}
}

private fun onEndTurn(view: ImageView, index: Int, result: TurnResult) {
if (result is TurnResult.Playing && result.isExistPoint) Toast.makeText(this, R.string.already_exist, Toast.LENGTH_LONG).show()
if (result !is TurnResult.Playing || !result.isExistPoint) {
setStone(view, omok.players.curPlayerColor.next())
dbHelper.insert(index, omok.players.curPlayerColor.next())
}
descriptionView.text = this.getString(R.string.who_is_turn).format(result.players.curPlayerColor.toPresentation().text)
}

private fun getBoardViews(): List<ImageView> = findViewById<TableLayout>(R.id.board)
.children
.filterIsInstance<TableRow>()
.flatMap { it.children }
.filterIsInstance<ImageView>().toList()

private fun calculateIndexToPoint(index: Int): Point =
Point(index / OMOK_BOARD_SIZE + 1, index % OMOK_BOARD_SIZE + 1)

private fun indexsToPoints(indexs: List<Int>): Points =
Points(indexs.map { calculateIndexToPoint(it) })
}
9 changes: 9 additions & 0 deletions app/src/main/java/woowacourse/omok/db/OmokConstract.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package woowacourse.omok.db

import android.provider.BaseColumns

object OmokConstract : BaseColumns {
const val TABLE_NAME = "game_info"
const val TABLE_COLUMN_POSITION = "position"
const val TABLE_COLUMN_COLOR = "color"
}
61 changes: 61 additions & 0 deletions app/src/main/java/woowacourse/omok/db/OmokDBHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package woowacourse.omok.db

import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import domain.stone.StoneColor

class OmokDBHelper(context: Context?) : SQLiteOpenHelper(context, DATABASE_NAME, null, 1) {
private val db = writableDatabase
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(
"CREATE TABLE ${OmokConstract.TABLE_NAME} (" +
" ${OmokConstract.TABLE_COLUMN_POSITION} int not null," +
" ${OmokConstract.TABLE_COLUMN_COLOR} varchar(50) not null" +
");"
)
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
db?.execSQL("DROP TABLE IF EXISTS ${OmokConstract.TABLE_NAME}")
onCreate(db)
}

fun getIndexsByColor(color: StoneColor): List<Int> {
val indexs = mutableListOf<Int>()
if (!db.isOpen) throw IllegalAccessException()
val cursor = db.query(
OmokConstract.TABLE_NAME,
arrayOf(OmokConstract.TABLE_COLUMN_POSITION),
"${OmokConstract.TABLE_COLUMN_COLOR} = ?",
arrayOf(color.name),
null,
null,
null
)

while (cursor.moveToNext()) indexs.add(cursor.getInt(0))
return indexs.toList()
}

fun insert(index: Int, color: StoneColor) {
if (!db.isOpen) throw IllegalAccessException()
db.insert(OmokConstract.TABLE_NAME, null, values(index, color))
}

private fun values(position: Int, color: StoneColor): ContentValues {
val values = ContentValues()
values.put(OmokConstract.TABLE_COLUMN_POSITION, position)
values.put(OmokConstract.TABLE_COLUMN_COLOR, color.name)
return values
}

fun deleteAll() {
db.execSQL("DELETE FROM ${OmokConstract.TABLE_NAME}")
}

companion object {
private val DATABASE_NAME = "omok"
}
}
Binary file added app/src/main/res/.DS_Store
Binary file not shown.
30 changes: 30 additions & 0 deletions app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<vector xmlns:android="http:https://schemas.android.com/apk/res/android"
xmlns:aapt="http:https://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
Binary file added app/src/main/res/drawable/.DS_Store
Binary file not shown.
Loading

0 comments on commit 50e7c2f

Please sign in to comment.