如何在Kotlin中实现井字棋(XO Game)人机对战模式?
井字棋单人AI模式开发求助:随机落子实现方案
我是一名Kotlin开发者,已经完成了井字棋(XO Game)的双人对战模式,后续还计划开发在线对战模式。目前我不清楚需要创建哪些函数来实现AI的随机落子功能,希望得到技术帮助来完成单人对战AI模式。
以下是我已经实现的双人对战代码:
import android.content.Intent import android.os.Bundle import android.view.View import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.AppCompatButton import androidx.core.content.ContextCompat class TwoPlayers : AppCompatActivity() { private var playerone = ArrayList<Int>() private var playertwo = ArrayList<Int>() private lateinit var xwinstxt: TextView private lateinit var owinstxt: TextView var activeplayer = 1 var attemptsCount = 9 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_two_players) xwinstxt = findViewById(R.id.xwinstxt) owinstxt = findViewById(R.id.owinstxt) val intent = intent val nameone = intent.getStringExtra("firstplayername") val nametwo = intent.getStringExtra("secondplayername") xwinstxt.text = nameone owinstxt.text = nametwo } fun buttonClicked(view: View) { val buttonClicked = view as AppCompatButton var num = 0 when (buttonClicked.id) { R.id.button1 -> num = 1 R.id.button2 -> num = 2 R.id.button3 -> num = 3 R.id.button4 -> num = 4 R.id.button5 -> num = 5 R.id.button6 -> num = 6 R.id.button7 -> num = 7 R.id.button8 -> num = 8 R.id.button9 -> num = 9 } playGame(num, buttonClicked) } private fun playGame(num: Int, buttonClicked: AppCompatButton) { attemptsCount -= 1 if (activeplayer == 1) { buttonClicked.background = ContextCompat.getDrawable(this, R.drawable.x_icon) playerone.add(num) activeplayer = 2 } else { buttonClicked.background = ContextCompat.getDrawable(this, R.drawable.o_icon) playertwo.add(num) activeplayer = 1 } buttonClicked.isEnabled = false checkwinner() } private fun checkwinner() { var winner = -1 if (attemptsCount == 0) { val intent = Intent(this, WinnerPage::class.java) WinnerPage.winnerPlayertxt = "Draw Game !" startActivity(intent) finish() } if (playerone.contains(1) && playerone.contains(2) && playerone.contains(3)) winner = 1 if (playertwo.contains(1) && playertwo.contains(2) && playertwo.contains(3)) winner = 2 if (playerone.contains(4) && playerone.contains(5) && playerone.contains(6)) winner = 1 if (playertwo.contains(4) && playertwo.contains(5) && playertwo.contains(6)) winner = 2 if (playerone.contains(7) && playerone.contains(8) && playerone.contains(9)) winner = 1 if (playertwo.contains(7) && playertwo.contains(8) && playertwo.contains(9)) winner = 2 if (playerone.contains(1) && playerone.contains(4) && playerone.contains(7)) winner = 1 if (playertwo.contains(1) && playertwo.contains(4) && playertwo.contains(7)) winner = 2 if (playerone.contains(2) && playerone.contains(5) && playerone.contains(8)) winner = 1 if (playertwo.contains(2) && playertwo.contains(5) && playertwo.contains(8)) winner = 2 if (playerone.contains(3) && playerone.contains(6) && playerone.contains(9)) winner = 1 if (playertwo.contains(3) && playertwo.contains(6) && playertwo.contains(9)) winner = 2 if (playerone.contains(1) && playerone.contains(5) && playerone.contains(9)) winner = 1 if (playertwo.contains(1) && playertwo.contains(5) && playertwo.contains(9)) winner = 2 if (playerone.contains(3) && playerone.contains(5) && playerone.contains(7)) winner = 1 if (playertwo.contains(3) && playertwo.contains(5) && playertwo.contains(7)) winner = 2 if (winner == 1) { val intent = Intent(this, WinnerPage::class.java) WinnerPage.winnerPlayertxt = "X Wins" startActivity(intent) finish() } if (winner == 2) { val intent = Intent(this, WinnerPage::class.java) WinnerPage.winnerPlayertxt = "O Wins" startActivity(intent) finish() } } }
实现AI随机落子的核心函数与修改步骤
1. 获取所有空位的函数
先实现一个函数,筛选出当前棋盘上未被占用的位置,这是AI落子的可选范围:
private fun getEmptyPositions(): List<Int> { val allPositions = (1..9).toList() val takenPositions = playerone + playertwo return allPositions.filter { !takenPositions.contains(it) } }
2. AI随机落子的核心函数
从空位中随机挑选一个位置,找到对应按钮后调用现有playGame函数完成落子:
private fun aiMakeMove() { val emptyPositions = getEmptyPositions() if (emptyPositions.isEmpty()) return // 无空位时直接返回 // 禁用所有按钮,防止玩家在AI落子过程中点击 disableAllButtons() // 随机选择一个空位 val randomPosition = emptyPositions.random() // 根据位置编号找到对应按钮 val aiButton = when(randomPosition) { 1 -> findViewById<AppCompatButton>(R.id.button1) 2 -> findViewById<AppCompatButton>(R.id.button2) 3 -> findViewById<AppCompatButton>(R.id.button3) 4 -> findViewById<AppCompatButton>(R.id.button4) 5 -> findViewById<AppCompatButton>(R.id.button5) 6 -> findViewById<AppCompatButton>(R.id.button6) 7 -> findViewById<AppCompatButton>(R.id.button7) 8 -> findViewById<AppCompatButton>(R.id.button8) 9 -> findViewById<AppCompatButton>(R.id.button9) else -> null } aiButton?.let { playGame(randomPosition, it) // 若游戏未结束,恢复可点击的空位按钮 if (attemptsCount > 0 && checkWinnerStatus() == -1) { enableAllButtons() } } }
3. 新增辅助函数
为了优化交互体验,需要添加几个辅助函数:
// 禁用所有棋盘按钮 private fun disableAllButtons() { findViewById<AppCompatButton>(R.id.button1).isEnabled = false findViewById<AppCompatButton>(R.id.button2).isEnabled = false findViewById<AppCompatButton>(R.id.button3).isEnabled = false findViewById<AppCompatButton>(R.id.button4).isEnabled = false findViewById<AppCompatButton>(R.id.button5).isEnabled = false findViewById<AppCompatButton>(R.id.button6).isEnabled = false findViewById<AppCompatButton>(R.id.button7).isEnabled = false findViewById<AppCompatButton>(R.id.button8).isEnabled = false findViewById<AppCompatButton>(R.id.button9).isEnabled = false } // 启用所有未被占用的棋盘按钮 private fun enableAllButtons() { val allButtons = listOf( findViewById<AppCompatButton>(R.id.button1), findViewById<AppCompatButton>(R.id.button2), findViewById<AppCompatButton>(R.id.button3), findViewById<AppCompatButton>(R.id.button4), findViewById<AppCompatButton>(R.id.button5), findViewById<AppCompatButton>(R.id.button6), findViewById<AppCompatButton>(R.id.button7), findViewById<AppCompatButton>(R.id.button8), findViewById<AppCompatButton>(R.id.button9) ) allButtons.forEach { button -> val buttonNum = when(button.id) { R.id.button1 -> 1 R.id.button2 -> 2 R.id.button3 -> 3 R.id.button4 -> 4 R.id.button5 -> 5 R.id.button6 -> 6 R.id.button7 -> 7 R.id.button8 -> 8 R.id.button9 -> 9 else -> 0 } if (!playerone.contains(buttonNum) && !playertwo.contains(buttonNum)) { button.isEnabled = true } } } // 检查当前胜负状态,避免重复调用checkwinner的跳转逻辑 private fun checkWinnerStatus(): Int { var winner = -1 if (playerone.contains(1) && playerone.contains(2) && playerone.contains(3)) winner = 1 if (playertwo.contains(1) && playertwo.contains(2) && playertwo.contains(3)) winner = 2 if (playerone.contains(4) && playerone.contains(5) && playerone.contains(6)) winner = 1 if (playertwo.contains(4) && playertwo.contains(5) && playertwo.contains(6)) winner = 2 if (playerone.contains(7) && playerone.contains(8) && playerone.contains(9)) winner = 1 if (playertwo.contains(7) && playertwo.contains(8) && playertwo.contains(9)) winner = 2 if (playerone.contains(1) && playerone.contains(4) && playerone.contains(7)) winner = 1 if (playertwo.contains(1) && playertwo.contains(4) && playertwo.contains(7)) winner = 2 if (playerone.contains(2) && playerone.contains(5) && playerone.contains(8)) winner = 1 if (playertwo.contains(2) && playertwo.contains(5) && playertwo.contains(8)) winner = 2 if (playerone.contains(3) && playerone.contains(6) && playerone.contains(9)) winner = 1 if (playertwo.contains(3) && playertwo.contains(6) && playertwo.contains(9)) winner = 2 if (playerone.contains(1) && playerone.contains(5) && playerone.contains(9)) winner = 1 if (playertwo.contains(1) && playertwo.contains(5) && playertwo.contains(9)) winner = 2 if (playerone.contains(3) && playerone.contains(5) && playerone.contains(7)) winner = 1 if (playertwo.contains(3) && playertwo.contains(5) && playertwo.contains(7)) winner = 2 return winner }
4. 修改现有playGame函数,触发AI回合
在玩家(activeplayer=1)落子完成后,延迟触发AI落子,让玩家有时间看到自己的操作:
private fun playGame(num: Int, buttonClicked: AppCompatButton) { attemptsCount -= 1 if (activeplayer == 1) { buttonClicked.background = ContextCompat.getDrawable(this, R.drawable.x_icon) playerone.add(num) activeplayer = 2 // 延迟500ms触发AI落子,提升交互体验 buttonClicked.postDelayed({ aiMakeMove() }, 500) } else { buttonClicked.background = ContextCompat.getDrawable(this, R.drawable.o_icon) playertwo.add(num) activeplayer = 1 } buttonClicked.isEnabled = false checkwinner() }
额外说明
- 确保布局文件中按钮ID与代码中的
button1至button9完全匹配 - 延迟AI落子的时间可根据需求调整,500ms是兼顾体验和响应速度的合理值
- 若后续想升级AI难度(比如实现 minimax 最优算法),只需替换
aiMakeMove中的随机选择逻辑即可
内容的提问来源于stack exchange,提问作者onlyforquestions
相关产品推荐
相关产品推荐

