티스토리 뷰

Android/Kotlin

[Kotlin]  Tic-tac-toe 게임으로 보는 MVC 패턴

혀가 길지 않은 개발자 2020. 9. 18. 12:40

MVC (Model  +  View  Controller)


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="30dp"
    tools:context=".MainActivity">

    <GridLayout
        android:id="@+id/btnGrid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:rowCount="3"
        android:columnCount="3">

        <Button
            android:tag="00"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

        <Button
            android:tag="01"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

        <Button
            android:tag="02"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

        <Button
            android:tag="10"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

        <Button
            android:tag="11"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

        <Button
            android:tag="12"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

        <Button
            android:tag="20"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

        <Button
            android:tag="21"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

        <Button
            android:tag="22"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:onClick="onClickCell"
            android:textSize="30sp"/>

    </GridLayout>

    <LinearLayout
        android:id="@+id/winnerPlayerViewGroup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone"
        tools:visibility="visible">

        <TextView
            android:id="@+id/tvWinnerPlayer"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="40sp"
            android:layout_margin="20dp"
            tools:text="X"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Winner"
            android:textSize="40sp"/>

    </LinearLayout>

    <Button
        android:id="@+id/btnReset"
        android:layout_width="200dp"
        android:layout_height="70dp"
        android:layout_marginTop="40dp"
        android:textAllCaps="false"
        android:text="Reset"
        android:textSize="20dp"/>

</LinearLayout>

View 역할

 

activity_main.xml

 

 

 

 

 

 

model/Player.kt

package com.jwsoft.model

enum class Player {
    O,
    X,
    NULL
}

 

 

 

 

 

model/Cell.kt

package com.jwsoft.model

data class Cell (
    var player: Player
)

 

 

 

 

 

model/Board.kt

package com.jwsoft.model

class Board {
    var currentPlayer: Player = Player.X
    var winnerPlayer: Player = Player.NULL
    var cells: Array<Array<Cell>> = Array<Array<Cell>>(3) {
        Array<Cell>(3) {
            Cell(Player.NULL)
        }
    }

    fun mark(row: Int, col: Int, player: Player): Boolean {      // 셀 선점 플로우
        return if (!isValid(row, col)) {        // 선점 돼 있으면
            false
        } else {
            cells[row][col].player = currentPlayer
            winnerPlayer = getWinner(row, col, player)
            true
        }
    }

    private fun isValid(row: Int, col: Int): Boolean {
        return cells[row][col].player == Player.NULL
    }

    fun flipCurrentPlayer() {
        currentPlayer = if(currentPlayer == Player.X) Player.O else Player.X
    }


    fun clear() {
        currentPlayer = Player.X
        winnerPlayer = Player.NULL
        cells = Array(3) { Array(3) { Cell(Player.NULL) } }
    }


    private fun getWinner(row: Int, col: Int, player: Player): Player {
        if (cells[row][0].player == player &&
            cells[row][1].player == player &&
            cells[row][2].player == player ||
            cells[0][col].player == player &&
            cells[1][col].player == player &&
            cells[2][col].player == player ||
            row == col &&
            cells[0][0].player == player &&
            cells[1][1].player == player &&
            cells[2][2].player == player ||
            row + col == 2 &&
            cells[0][2].player == player &&
            cells[1][1].player == player &&
            cells[2][0].player == player)
        {
            return player
        } else {
            return Player.NULL
        }
    }

}

Model 역할

 

 

 

 

 

 

 

 

MainActivity.kt

package com.jwsoft.kotlinproject

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.core.view.size
import com.jwsoft.model.Board
import com.jwsoft.model.Player
import kotlinx.android.synthetic.main.activity_main.*


// Controller 역할
class MainActivity : AppCompatActivity() {

    var model: Board = Board()      // Model 역할


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btnReset.setOnClickListener {
            model.clear()

            for (i in 0 until btnGrid.childCount) {
                (btnGrid.getChildAt(i) as Button).text = ""
            }

            winnerPlayerViewGroup.visibility = View.GONE
        }

    }


    fun onClickCell(view: View) {       // 셀 클릭 이벤트
        var row = view.tag.toString().substring(0, 1).toInt()   // 행 인덱스
        var col = view.tag.toString().substring(1, 2).toInt()   // 열 인덱스

        if (model.mark(row, col, model.currentPlayer)) {     // 셀 선점 플로우
            (view as Button).text = model.currentPlayer.toString()
            model.flipCurrentPlayer()     // 다음 차례 플레이어 설정
        }

        if (model.winnerPlayer != Player.NULL) {
            tvWinnerPlayer.text = model.winnerPlayer.toString()
            winnerPlayerViewGroup.visibility = View.VISIBLE
        }

    }

}

Controller 역할 

 

실행 결과

 

 

 

 

 

참고.

academy.realm.io/kr/posts/eric-maxwell-mvc-mvp-and-mvvm-on-android/

 

안드로이드의 MVC, MVP, MVVM 종합 안내서

안드로이드 앱을 만드는 개발자를 위한 MVC, MVP, MVVM 패턴 사용법과 장단점에 대한 안내서입니다.

academy.realm.io

github.com/ericmaxwell2003/ticTacToe

 

ericmaxwell2003/ticTacToe

A simple tic tac toe app, to illustrate the use of MVC, MVP, and MVVM architectures to organize the application. - ericmaxwell2003/ticTacToe

github.com

 

 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함