android - 我正在尝试制作井字游戏应用程序
问题描述
我正在尝试制作井字游戏应用程序,我已经实现了“播放器与播放器”部分,但在实现播放器与计算机时遇到了麻烦。我有一个名为 playgame 的功能。对于 update_player,我是手动执行的,对于更新计算机,我是随机执行的,我认为这是导致问题的原因,因为我正在检查我的 boardStatus 是否已填充,如果已填充,我将再次调用我的函数。我在网上读到所有计算都应该在线程上完成,我尝试实现它,但我认为我做错了。请帮忙!
这是我的代码供参考:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import kotlinx.android.synthetic.main.activity_computer.*
import java.util.*
class ComputerActivity : AppCompatActivity() {
var player = true
var turnCount = 0
var boardStatus = Array(3) { IntArray(3) }
lateinit var board: Array<Array<Button>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_computer)
board = arrayOf(
arrayOf(First, Second, Third),
arrayOf(Fourth, Fifth, Sixth),
arrayOf(Seventh, Eighth, Ninth)
)
playGame()
}
private fun playGame(){
Status.text = "Player's Turn"
for (i in 0..2) {
var flag: Boolean = false
for (j in 0..2) {
if (player) {
Status.text = "Player's Turn"
update_player(player)
Thread.sleep(2000)
player = false
turnCount++
checkWinner()
if (turnCount == 9) {
Status.text = "Game Draw"
flag = true;
}
} else {
Status.text = "Computer's Turn"
update_computer(player)
Thread.sleep(2000)
player = true
turnCount++
checkWinner()
if (turnCount == 9){
Status.text = "Game Draw"
flag = true
}
}
}
if(flag == true)
break
}
changeBoard()
resetBtn.setOnClickListener{
player = true;
turnCount = 0
changeBoard()
}
}
private fun update_player(player:Boolean){
for(i in board){
for(button in i){
button.setOnClickListener{
when(it.id){
R.id.First->{
updateBoardStatus(row = 0, column = 0,player)
}
R.id.Second->{
updateBoardStatus(row = 0, column = 1,player)
}
R.id.Third->{
updateBoardStatus(row = 0, column = 2,player)
}
R.id.Fourth->{
updateBoardStatus(row = 1, column = 0,player)
}
R.id.Fifth->{
updateBoardStatus(row = 1, column = 1,player)
}
R.id.Sixth->{
updateBoardStatus(row = 1, column = 2,player)
}
R.id.Seventh->{
updateBoardStatus(row = 2, column = 0,player)
}
R.id.Eighth->{
updateBoardStatus(row = 2, column = 1,player)
}
R.id.Ninth->{
updateBoardStatus(row = 2, column = 2,player)
}
}
}
}
}
}
private fun update_computer(player:Boolean){
var row:Int = 0
var column:Int = 0
Thread {
row = (0..2).random()
column = (0..2).random()
}.start()
if(boardStatus[row][column] == 0 || boardStatus[row][column]==1)
update_computer(player)
else
updateBoardStatus(row, column, player)
}
private fun updateBoardStatus(row:Int, column:Int, player:Boolean){
val text = if (player) "X" else "0"
val value = if (player) 1 else 0
board[row][column].apply {
isEnabled = false
setText(text)
}
boardStatus[row][column] = value
}
private fun checkWinner(){
//Horizontal --- rows
for (i in 0..2) {
if (boardStatus[i][0] == boardStatus[i][1] && boardStatus[i][0] == boardStatus[i][2]) {
if (boardStatus[i][0] == 1) {
result("Player Won!!")
break
} else if (boardStatus[i][0] == 0) {
result("Computer Won")
break
}
}
}
//Vertical --- columns
for (i in 0..2) {
if (boardStatus[0][i] == boardStatus[1][i] && boardStatus[0][i] == boardStatus[2][i]) {
if (boardStatus[0][i] == 1) {
result("Player Won!!")
break
} else if (boardStatus[0][i] == 0) {
result("Computer Won!!")
break
}
}
}
//First diagonal
if (boardStatus[0][0] == boardStatus[1][1] && boardStatus[0][0] == boardStatus[2][2]) {
if (boardStatus[0][0] == 1) {
result("Player Won!!")
} else if (boardStatus[0][0] == 0) {
result("Computer won!!")
}
}
//Second diagonal
if (boardStatus[0][2] == boardStatus[1][1] && boardStatus[0][2] == boardStatus[2][0]) {
if (boardStatus[0][2] == 1) {
result("Player Won!!")
} else if (boardStatus[0][2] == 0) {
result("Computer Won!!")
}
}
}
private fun result(res:String){
Status.text = res
if(res.contains("Won")){
disableButton()
}
else{
}
}
private fun disableButton(){
for(i in board){
for(button in i){
button.isEnabled = false
}
}
}
private fun changeBoard(){
for (i in 0..2) {
for (j in 0..2) {
boardStatus[i][j] = -1
}
}
for (i in board) {
for (button in i) {
button.isEnabled = true
button.text = ""
}
}
}
}
解决方案
您的代码试图将游戏的整个动作序列放在一个函数中,该函数被调用一次,然后期望玩家按键在内部发生。按钮侦听器将在函数返回后的某个时间触发。您需要考虑每次按下按钮以执行游戏的下一阶段时都会调用一个函数。
要解决这个问题:
删除该playGame()
功能。
删除player
参数,update_player()
因为它始终为真。并将函数名称更改为initializeButtons
. 调用一次onCreate()
。您只需向按钮添加一次侦听器,它们就会重复工作。
出于与上述相同的原因,也从中删除player
参数。update_computer()
并删除线程,使其看起来像:
private fun update_computer() {
val row = (0..2).random()
val column = (0..2).random()
if (boardStatus[row][column] == 0 || boardStatus[row][column] == 1)
update_computer()
else
updateBoardStatus(row, column, player)
}
然后在updateBoardStatus
函数调用结束时checkWinner()
。checkWinner()
应该返回一个布尔值,所以在 中updateBoardStatus()
,如果没有找到获胜条件并且player
为真,它应该调用update_computer()
.
因此,您现在拥有的不是尝试从一个函数运行游戏,而是设置了一次按钮侦听器来启动游戏。当一个按钮被按下时,它需要玩家轮流,然后触发updateBoardStatus
,然后触发计算机轮流,然后updateBoardStatus
再次触发,如果没有人获胜,则什么也不做。所有这些都在主线程上同步/即时发生,所以现在游戏回到等待用户按下按钮以重复事件序列。
此外,status
文本视图的用处有限。由于计算机会立即轮流,因此不可能看到“轮到计算机”这个词。如果你想这样做,你将不得不创造一个人为的延迟,所以你必须禁用所有按钮,然后做一些类似 callpostRunnable({ startPlayerTurn() }, 1000L)
的事情,startPlayerTurn()
重新启用适当的按钮并让它说,“Player turn”再次。
推荐阅读
- r - 尝试在 Kaggle 内核上运行 Rmd 文件时出错
- ibm-information-server - IBM 证书存储在 Information Server 中的什么位置?
- javascript - 通过我的扩展在 Chrome 中设置代理
- javascript - Angular 类不是 Angular 模块
- d3.js - 如何阻止 d3 工具提示离开页面?
- linux - 在没有父终止的情况下处理和传播 SIGHUP 信号到子进程
- python - 如何提取 zip 文件夹并查找特定文件名 Python 2
- sql - 仅在值匹配时识别
- javascript - 捆绑 React-native android 版本不接受代码更改
- php - 通过 json 请求的 Chartjs 数据未填充