使用Kotlin在Android Studio中创建井字游戏

井字游戏也被称为"Noughts和crosses"。它是两个玩家最普遍的纸笔游戏之一。

它主要由年幼的孩子放置,但很多时候,你也可以看到成年人玩这个来切断无聊。这个游戏非常方便,可以在任何地方玩,只有两个玩家。每个玩家必须在 X 和 O 之间选择一个符号。游戏在3×3网格中进行。每个玩家每回合只能放置一个符号,然后该回合被传递给另一个玩家。

游戏范式:

  • 优胜: 每个玩家都尝试将他们的三个符号放置在三个相邻的水平,垂直或对角线单元格中。更早实现这种一致性的人是赢家。当第二个玩家试图通过在玩家1的符号之间放置自己的符号来中断玩家1的对齐时。
  • 失去: 如果您的竞争对手首先获得所需的符号对齐方式,那么您将失败。
  • 画: 如果抓地力的所有九个单元格都已标记,并且没有一个玩家,则可实现所需的对齐。条件是平局或平局。在这种情况下,没有一个球员得到一分。这种情况在游戏过程中发生了无数次,实际上很有趣。

由于其简单性,井字棋被认为是向儿童教授逻辑构建和体育精神的完美教学工具。从技术上讲,还有更多功能,您可以使用人工智能创建一个游戏树,向您展示符号和单元格的所有组合的可能性。如果游戏由两个玩家以最佳方式进行,则游戏将以平局结束。这使得井字棋成为一种徒劳的游戏。

刻板的3 x 3双色井字棋可以修改为p,q,d颜色游戏,其中两个玩家交替将他们的符号放在p x q板上,目标是在垂直,水平或对角线上获得自己颜色的d。

让我们学习使用Kotlin类在Android Studio中创建井字游戏应用的步骤

第一阶段设计:

图片来源:截图来自Android Emulator

步骤 1:创建网格布局

在属性 rowCount 和 columnCount 中,输入值 3,这样网格中就有三行和三列。在>>可绘制文件夹中添加方形网格的图像资产。将图像另存为 tictac。在背景属性中,指定图像的位置。

用于创建网格
图像的示例图像 来源:Google

网格布局的 XML 代码:

<GridLayout
        android:layout_width="350dp"
        android:layout_height="350dp"
        android:layout_marginLeft="30dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="49dp"
        android:background="@drawable/tictac"
        android:columnCount="3"
        android:rowCount="3"
        android:id="@+id/gridLayout">
</GridLayout>

步骤 2:处理交易品种

在应用程序中添加两个图像资产,>>可绘制文件夹。您可以将它们另存为 circle1 和 circle2。最终,图像资源设置为 0,这意味着 null。每个图像视图都是在网格的单元格中创建的,这意味着总共需要九个图像视图。

玩家 1 的符号

玩家 1 的符号(您可以使用十字架代替)

要点:

  • 确保使它们可点击。在单击图像视图时调用方法"dropIn"android:onClick="dropIn"
  • 为每个行号和列号指定它们。android:layout_row="2" android:layout_column="1"
  • 向每个图像视图添加唯一的标记。安卓:标签="7"

当玩家点击单元格时,圆圈被放置在单元格中。
图片来源:截图来自Android Emulator

步骤 3:显示结果

一旦两个玩家中的任何一个获胜,文本视图变得可见,我们就可以将文本设置为"绿色获胜"或"红色获胜"。如果没有玩家获胜,并且网格的所有九个单元格都被标记,则将TextView的文本设置为"Draw"。

只有在进入三种情况中的任何一种情况后,文本视图才会设置为可见,并且与此一起,"再次播放"按钮也变得可见。"再次播放"按钮调用"重玩"功能;它清除网格单元格的图像,并将所有变量重置为其初始值。

这是图像中提到的UI设计的完整XML代码;此代码以 activity_main.xml 编写:<?xml version="1.0" encodi

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <GridLayout
        android:layout_width="350dp"
        android:layout_height="350dp"
        android:layout_marginLeft="30dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="49dp"
        android:background="@drawable/tictac"
        android:columnCount="3"
        android:rowCount="3"
        android:id="@+id/gridLayout">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_marginLeft="25dp"
            android:layout_marginTop="25dp"
            android:layout_row="0"
            android:layout_column="0"
            android:onClick="dropIn"
            android:tag="0"
            />

        <ImageView
            android:id="@+id/imageView2"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_column="1"
            android:layout_marginLeft="35dp"
            android:layout_marginTop="25dp"
            android:layout_row="0"
            android:onClick="dropIn"
            android:tag="1"
            />

        <ImageView
            android:id="@+id/imageView3"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_column="2"
            android:layout_marginLeft="35dp"
            android:onClick="dropIn"
            android:layout_marginTop="25dp"
            android:layout_row="0"
            android:tag="2"
            />

        <ImageView
            android:id="@+id/imageView4"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_column="0"
            android:layout_marginLeft="25dp"
            android:onClick="dropIn"
            android:layout_marginTop="40dp"
            android:layout_row="1"
            android:tag="3"
            />

        <ImageView
            android:id="@+id/imageView5"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_column="1"
            android:layout_marginLeft="35dp"
            android:onClick="dropIn"
            android:layout_marginTop="40dp"
            android:layout_row="1"
            android:tag="4"
            />

        <ImageView
            android:id="@+id/imageView6"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_column="2"
            android:onClick="dropIn"
            android:layout_marginLeft="35dp"
            android:layout_marginTop="40dp"
            android:layout_row="1"
            android:tag="5"
            />

        <ImageView
            android:id="@+id/imageView7"
            android:layout_width="70dp"
            android:layout_row="2"
            android:layout_column="0"
            android:layout_height="70dp"
            android:onClick="dropIn"
            android:layout_marginLeft="25dp"
            android:layout_marginTop="45dp"
            android:tag="6"
            />

        <ImageView
            android:id="@+id/imageView8"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_row="2"
            android:layout_column="1"
            android:onClick="dropIn"
            android:layout_marginLeft="40dp"
            android:layout_marginTop="40dp"
            android:tag="7"
            />

        <ImageView
            android:id="@+id/imageView9"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_row="2"
            android:layout_column="2"
            android:onClick="dropIn"
            android:layout_marginLeft="35dp"
            android:layout_marginTop="45dp"
            android:tag="8" />
    </GridLayout>

    <LinearLayout
        android:id="@+id/winner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:orientation="vertical"
        android:padding="20dp"
        android:visibility="invisible">

        <TextView
            android:id="@+id/winner1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="Winner"
            android:layout_gravity="center"
            android:textSize="24sp"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="PLAY Again?"
            android:onClick="playAgain"/>

    </LinearLayout>
</RelativeLayout>
</code></span></span>

第二阶段:Kotlin 类

构成变量:

状态:我们将每个单元格的状态存储在称为gameState的变量中。最初,每个单元格的状态为 2。如果单元格由绿色圆圈标记,即玩家 1 的移动,则该单元格的 gameState 为 1。而如果单元格由红色圆圈标记,则这是玩家 2 的移动,则该单元格的游戏状态为 0。gameState是一个整数数组,它可以存储所有9个单元格的状态。用户无法标记已标记的单元格;在 gameState 变量的帮助下检查此条件。

活跃玩家:变量activePlayer指示谁的回合正在进行中。每次移动后,该值在0和1之间切换,因为不允许任何玩家在游戏中连续移动两次。

游戏处于活动状态:它是一个布尔变量,表示游戏处于活动状态或休眠状态。如果任何玩家获胜或平局,则 gameIsActive 变量将设置为 false。当单击"再次播放"按钮时,它将再次设置为 true。

计数变量:它存储已标记的单元格数量的值。当没有一个玩家获胜并且计数变为九时,游戏是平局比赛。单击"再次播放"按钮时,计数变量的值将变为零。在每个玩家的每次后续移动之后,计数变量都会递增一。

获胜仓位:我们创建一个由九个整数数组组成的数组。这些子整数数组包含获胜仓位的索引组合。垂直行、水平行和对角线行的所有可能组合都存在于获胜位置中。因此,如果这三个单元格中的任何一个被两个玩家中的任何一个标记,他或她就赢了。

获胜位置集: (0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6).

Kotlin类中编写了两个主要函数:

dropIn:当用户单击网格的九个单元格中的任何一个时,将调用它。之后,每一步棋,玩家的标记位置都会与获胜组合的集合进行比较,如果任何条件匹配,则该玩家被宣布为获胜者。添加了其他动画,用于平滑网格视图中红色和绿色圆圈的滑动。

平局条件:如果没有一个玩家能够标记任何获胜位置,并且还标记了单元格,则游戏是平局。如果计数变量达到 9 并且游戏仍处于活动状态,则由计数变量的值指示。游戏已停止,因此布尔变量设置为 false,显示的结果是 DRAW,因此文本视图也变得可见。

if (gameIsActive && count == 9) {
            txt.text = "DRAW"
            layout.visibility = View.VISIBLE
            gameIsActive = false
        }

重玩:当用户单击"再次播放"按钮时,将调用它。此功能的主要目的是在玩完一轮游戏后重置所有变量。此函数将 count 的值设置为零,将玩家 1 设置为活动玩家,使游戏处于活动状态,将网格的所有单元格的状态设置为 2(既不是红色也不是绿色),并清除在上一个游戏中设置的所有图像资源。这是必要的,以便先前变量值的交替不会干扰当前的博弈。

fun playAgain(view: View?) 
{
        activePlayer = 1
        gameIsActive = true
        count= 0
        val linearLayout = findViewById<LinearLayout>(R.id.winner)
        val gridLayout =
            findViewById<GridLayout>(R.id.gridLayout)
        for (i in gameState.indices)
       {
            gameState[i] = 2
        }
        linearLayout.visibility = View.INVISIBLE
        for (i in 0 until gridLayout.childCount)
       {
            (gridLayout.getChildAt(i) as ImageView).setImageResource(0) 
   }
}

Tic-Tac-Toe应用程序的完整MainActivity.kt代码:

package com.example.tic_tac_toe;
import android.os.Bundle
import android.view.View
import android.widget.GridLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity


class MainActivity : AppCompatActivity() {
    //1=green  0 =red
    var activePlayer = 1
    var gameIsActive = true
    var count = 0
    var gameState = intArrayOf(2, 2, 2, 2, 2, 2, 2, 2, 2)
    var winningPositions = 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)
    )

    fun dropIn(view: View) {
        val counter = view as ImageView
        val txt = findViewById<TextView>(R.id.winner1)
        val layout = findViewById<LinearLayout>(R.id.winner)
        //understand
        val tappedcounter = counter.tag.toString().toInt()
        if (gameState[tappedcounter] == 2 && gameIsActive) {
            if (activePlayer == 1) {
                counter.setImageResource(R.drawable.circle1)
                activePlayer = 0
                count++
                gameState[tappedcounter] = 1
            } else {
                counter.setImageResource(R.drawable.circle2)
                activePlayer = 1
                count++
                gameState[tappedcounter] = 0
            }
            counter.translationY = -1000f
            counter.animate().translationYBy(1000f).rotationY(1800f).duration = 1000
            for (winningposition in winningPositions) {
                if (gameState[winningposition[0]] == gameState[winningposition[1]] && gameState[winningposition[1]] == gameState[winningposition[2]] && gameState[winningposition[0]] != 2
                ) {
                    if (gameState[winningposition[0]] == 0) txt.text =
                        "Red Player Wins" else if (gameState[winningposition[0]] == 1
                    ) txt.text = "Green Player Wins"
                    layout.visibility = View.VISIBLE
                    gameIsActive = false
                }
            }
        }
        if (gameIsActive && count == 9) {
            txt.text = "DRAW"
            layout.visibility = View.VISIBLE
            gameIsActive = false
        }
    }

    fun playAgain(view: View?) {
        activePlayer = 1
        gameIsActive = true
        count= 0
        val linearLayout = findViewById<LinearLayout>(R.id.winner)
        val gridLayout =
            findViewById<GridLayout>(R.id.gridLayout)
        for (i in gameState.indices) {
            gameState[i] = 2
        }
        linearLayout.visibility = View.INVISIBLE
        for (i in 0 until gridLayout.childCount) {
            (gridLayout.getChildAt(i) as ImageView).setImageResource(0) //p t n
        }
    }

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

尝试自己实现代码。你练习得越多,你的概念就越完美。如果需要,可以通过更改网格布局的行和列计数来修改单元格数。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值