首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android Tic-Tac-Toe

Android Tic-Tac-Toe
EN

Code Review用户
提问于 2021-04-25 08:56:47
回答 2查看 399关注 0票数 3

我已经做了一个Android Tac脚趾适应作为一个周末项目。

这是科特林密码。

MainActivity:

代码语言:javascript
复制
package com.mizech.tictactoe

import android.content.DialogInterface
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import com.mizech.tictactoe.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private var gameState = mutableListOf<FeasibleState>()
    private var isPlayerOne = true
    private var fieldsUsed = 0
    private val imageViews = mutableListOf<ImageView>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        var i = 0
        while (i < 9) {
            gameState.add(FeasibleState.NOT_SET)
            i++
        }
        // Add the imageViews to the List
        imageViews.add(binding.imageView0)
        imageViews.add(binding.imageView1)
        imageViews.add(binding.imageView2)
        imageViews.add(binding.imageView3)
        imageViews.add(binding.imageView4)
        imageViews.add(binding.imageView5)
        imageViews.add(binding.imageView6)
        imageViews.add(binding.imageView7)
        imageViews.add(binding.imageView8)
        // Iterate the list and attach an Listener to each.
        imageViews.forEach {
            it.setOnClickListener {
                processStateChange(it)
            }
        }

        binding.resetGame.setOnClickListener {
            val intent = Intent(this, MainActivity::class.java)
            val snackbar = Snackbar.make(it, "Game Reset cancelled",
                    Snackbar.LENGTH_LONG)
            val dialog = AlertDialog.Builder(this)
            dialog.apply {
                setIcon(R.drawable.ic_baseline_priority_high_24)
                setTitle("Game Reset")
                setMessage("Do you want to continue?")
                setPositiveButton("Yes", DialogInterface.OnClickListener { dialog, which ->
                    startActivity(intent)
                })
                setNegativeButton("No", DialogInterface.OnClickListener { dialog, which ->
                    snackbar.show()
                })
            }.show()
        }
    }

    private fun checkGameState(currentPlayer: FeasibleState): Boolean {
        if (gameState[0] === currentPlayer && gameState[1] === currentPlayer
                && gameState[2] === currentPlayer) {
            return true
        }

        if (gameState[3] === currentPlayer && gameState[4] === currentPlayer
                && gameState[5] === currentPlayer) {
            return true
        }

        if (gameState[6] === currentPlayer && gameState[7] === currentPlayer
                && gameState[8] === currentPlayer) {
            return true
        }

        if (gameState[0] === currentPlayer && gameState[3] === currentPlayer
                && gameState[6] === currentPlayer) {
            return true
        }

        if (gameState[1] === currentPlayer && gameState[4] === currentPlayer
                && gameState[7] === currentPlayer) {
            return true
        }

        if (gameState[2] === currentPlayer && gameState[5] === currentPlayer
                && gameState[8] === currentPlayer) {
            return true
        }

        if (gameState[0] === currentPlayer && gameState[4] === currentPlayer
                && gameState[8] === currentPlayer) {
            return true
        }

        if (gameState[2] === currentPlayer && gameState[4] === currentPlayer
                && gameState[6] === currentPlayer) {
            return true
        }

        return false
    }

    private fun processStateChange(it: View) {
        val imgView = it as ImageView
        if (isPlayerOne) {
            imgView.setImageResource(R.drawable.player_one)
            fieldsUsed++
            gameState[imgView.tag.toString().toInt()] = FeasibleState.PLAYER_ONE

            checkResult(FeasibleState.PLAYER_ONE, R.string.one_won_message, "#64FF64")
        } else {
            imgView.setImageResource(R.drawable.player_two)
            fieldsUsed++
            gameState[imgView.tag.toString().toInt()] = FeasibleState.PLAYER_TWO

            checkResult(FeasibleState.PLAYER_TWO, R.string.two_won_message, "#FF6464")
        }

        isPlayerOne = !isPlayerOne
        imgView.isEnabled = false
    }

    private fun checkResult(currentPlayer: FeasibleState, message: Int, winnerColor: String) {
        if (checkGameState(currentPlayer)) {
            setFinalResult(message, winnerColor)
        } else if (fieldsUsed == 9) {
            setFinalResult(R.string.tie_message, "#ff00ff")
        }
    }

    private fun setFinalResult(winnerString: Int, winnerColor: String) {
        imageViews.forEach {
            it.isEnabled = false
        }
        binding.currentMessage.text = getString(winnerString)
        binding.currentMessage.setTextColor(Color.parseColor(winnerColor))
    }
}

枚举类:

代码语言:javascript
复制
package com.mizech.tictactoe

enum class FeasibleState {
  NOT_SET,
  PLAYER_ONE,
  PLAYER_TWO
}

完整的源代码和GitHub上的其他图片.

如何才能使我的实现得到改善?你会有什么不同的做法,为什么?

有更好的可能性来重置游戏吗?而不是触发MainActivity .

的意图

期待阅读你的答案和评论。

EN

回答 2

Code Review用户

回答已采纳

发布于 2021-05-08 16:53:55

复位

每次重置游戏时,调用MainActivity就会创建一个活动堆栈,因此,如果用户玩了几个游戏并试图通过按后退按钮退出游戏,他们将不得不在每次游戏中完成之前的游戏,直到他们退出为止。

更好的方法可能是在用户确认后调用一个reset方法,而不是启动一个新的活动。实际上,您需要重置游戏状态和UI,这应该如下所示:

代码语言:javascript
复制
private fun resetGame() {
    for (idx in 0..8) {
        gameState[idx] = FeasibleState.NOT_SET
    }
    imageViews.forEach { view ->
        view.setImageResource(R.drawable.not_set)
        view.isEnabled = true
    }
    binding.currentMessage.text = ""
    fieldsUsed = 0
    isPlayerOne = true
}

checkGameState

您的checkGameState函数有许多重复的行,所有这些行本质上都是在执行相同的操作。您正在检查三个游戏状态,以确定它们是否与当前的玩家匹配。另一种方法是创建一个有效的获胜组合列表。然后,您可以遍历列表来检查组合。就像这样:

代码语言:javascript
复制
private fun checkGameState(currentPlayer: FeasibleState): Boolean {
    val winningCombo = arrayOf(
        intArrayOf(0,1,2),
        intArrayOf(3,4,5),
        intArrayOf(6,7,8),
        intArrayOf(0,3,6),
        intArrayOf(1,4,7),
        intArrayOf(2,5,8),
        intArrayOf(0,4,8),
        intArrayOf(2,4,6)
    )

    return winningCombo.filter { it.all { idx-> gameState[idx] == currentPlayer }}.any()
}
票数 3
EN

Code Review用户

发布于 2021-05-07 20:34:37

免责声明:我远不是专家,但因为还没有人对你做出回应,而且已经过了几个星期了。我想我可以试着给你一些反馈。

您的函数checkGameState包含大量重复的代码。尝试使用助手函数来消除这种重复。

gameState指的是网格中的9个方格。也许您应该将其重命名为squaresgridStates。而且,我也不认为它是可变的。所以我使用一个数组,而不是写这个:

代码语言:javascript
复制
    private var gameState = mutableListOf<FeasibleState>()
    ...
    var i = 0
    while (i < 9) {
        gameState.add(FeasibleState.NOT_SET)
        i++
    }

我会同时声明和初始化这个数组。

代码语言:javascript
复制
    var gridStates = Array(9, {FeasibleState.NOT_SET})

现在,这可能是我的挑剔,但在我的例子中,我会使用一个循环来执行imageViews.add(binding.imageViewx),并使用一个数组来存储这些图像名(或者我会用一个字符串模板生成名称)。一旦我有了这个循环,我就会在同一个循环中完成onClickListener的设置。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/259971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档