kotlin之二维数组的翻转思路和实现

  • 前言
    • 构建数组中的实体Blob
    • 创建二维数组
    • 打印二维数组
    • 生成并打印二维数组
    • 主入口方法改造
    • 数组翻转的逻辑实现
      • 顺时针旋转的思路以及实现
      • 逆时针旋转的实现
      • 左右对调的实现
    • 代码实现

 

前言

最近在研究和学习kotlin,无意间看到一个Android的2048小游戏的kotlin的实现,在做这个小游戏的过程中,发现了一个很有意思的东西,那就是二维数组,2048这个小游戏是用一个44的二维数组来进行实现的,但是当我们屏幕向上、向下、向左移动的时候我们要如何实现我们的2048小游戏的数组的想加,也许大家的想法就是向上的时候处理向上的逻辑、向下的时候处理向下的逻辑,当时我的第一思路也是这么想的,可是当我写完向上的逻辑的时候,我发现再写一个向下、向左和向右的逻辑实在是一个太复杂的事情,那我们是否有一种简单的实现方式呢,这时候想到既然是一个44的二维数组,那我们是不是可以翻转我们的数组到某一个方向,然后实现相加以后,再将我们的二维数组回转回来。

构建数组中的实体Blob

class ArrDemo {
   class Blob(
        var x: Int,
        var y: Int,
        var value: Int,
        var pX: Int = x,
        var pY: Int = y
    )
}

创建二维数组

在我们的ArrDemo类中添加以下的二维数组创建的实现方式

    /**
     * 功能描述: 构建二维数组
     */
    fun createArray() = Array(4) { y -> Array(4) { x -> Blob(x, y, 0) } }

打印二维数组

在我们的ArrDemo类中添加以下的打印二维数组的实现方式

    /**
     * 功能描述: 实现显示的加载数组数据
     */
    fun dumpArray(array: Array<Array<Blob>>, msg: String) {
        println("============$msg============")
        for (y in 0 until array.size) {
            for (x in 0 until array.size) {
                print("${array[y][x].value}(${array[y][x].pX},${array[y][x].pY}) ")
            }
            println()
        }
    }

生成并打印二维数组

这时候我们在ArrDemo类中添加以下的代码来调用我们的生成二维数组和打印二维数组:

    companion object {
         /**
         * 主入口函数
         * @JvmStatic
         */
        @JvmStatic
        fun main(args: Array<String>) {
            var arrDemo = ArrDemo()
            var array = arrDemo.createArray()
            arrDemo.dumpArray(array, "初始化以后数组情况")
        }
    }

执行主入口函数完成以后数组的打印情况如下:

============初始化以后数组情况============
0(0,0) 0(1,0) 0(2,0) 0(3,0) 
0(0,1) 0(1,1) 0(2,1) 0(3,1) 
0(0,2) 0(1,2) 0(2,2) 0(3,2) 
0(0,3) 0(1,3) 0(2,3) 0(3,3) 

大家也许注意到了我们创建二维数组的时候是用y开头的,我们遍历二维数组的时候也是用y开头的,这是为什么呢?很简单如果用x开头那么我们生成以后的二维数组的打印情况如下:

============初始化以后数组情况============
0(0,0) 0(0,1) 0(0,2) 0(0,3) 
0(1,0) 0(1,1) 0(1,2) 0(1,3) 
0(2,0) 0(2,1) 0(2,2) 0(2,3) 
0(3,0) 0(3,1) 0(3,2) 0(3,3) 

大家注意到了没有呢,这里面的xy的值是对调的,也许有人会说这样也是没有影响的呢,可是当我们需要进行数组翻转的时候你会发现这样的形式我们很难进行翻转,因为这并不是一个真正的坐标体系,而我们最开始的以y打头的才是真正的坐标体系,比如(1,0)这代表这x轴上值为1,y轴上值为0。

主入口方法改造

为了翻转我们的数组的时候我们需要有一个直观的认识,我们这边在数组初始化以后我们给数组中某两个坐标赋值:

    companion object {
         /**
         * 主入口函数
         * @JvmStatic
         */
        @JvmStatic
        fun main(args: Array<String>) {
            var arrDemo = ArrDemo()
            var array = arrDemo.createArray()
            array[3][2].value = 8
            array[2][2].value = 4
            arrDemo.dumpArray(array, "初始化以后数组情况")
        }
    }

这时候我们的数组打印的情况如下:

============初始化以后数组情况============
0(0,0) 0(1,0) 0(2,0) 0(3,0) 
0(0,1) 0(1,1) 0(2,1) 0(3,1) 
0(0,2) 0(1,2) 4(2,2) 0(3,2) 
0(0,3) 0(1,3) 8(2,3) 0(3,3) 

数组翻转的逻辑实现

首先我们默认所有的方向旋转以后都是变为右侧方向

顺时针旋转的思路以及实现

以我们刚刚初始化好的数组的情况为例子我们来说明下我们该如何发现数组里面的规律,现在我们先开始顺时针翻转一个角度,就是把上面的这个数据进行翻转,翻转以后需要实现的效果如下:

============旋转以后数组情况============
0(0,3) 0(0,2) 0(0,1) 0(0,0) 
0(1,3) 0(1,2) 0(1,1) 0(1,0) 
8(2,3) 4(2,2) 0(2,1) 0(2,0) 
0(3,3) 0(3,2) 0(3,1) 0(3,0) 

大家会发现(0,3)、(0,2)、(0,1)、(0,0)这一列的数据变成了第一行的数据,那这说明了(0,3)的值替换到了(0,0),(0,2)替换到了(1,0),(0,1)替换到了(2,0),(0,0)替换到了(3,0),这时候大家是不是有发现一个规律他们替换的规则是y1 = 3 -x,x1 = y,我们可以把上面的值做一个带入运算,例如:

(0,3)的值替换到了(0,0),将(0,0)带入运算结果为(0,3 - 0)
(0,2)的值替换到了(1,0),将(1,0)带入运算结果为(0,3 - 1)
(0,1)的值替换到了(2,0),将(2,0)带入运算结果为(0,3 - 2)
(0,0)的值替换到了(3,0),将(3,0)带入运算结果为(0,3 - 3)

逆时针旋转的实现

上面的例子我们已经实现了顺时针的旋转,那么我们接下来要实现的就是逆时针旋转,旋转好的效果如下:

============旋转回来数组情况============
0(3,0) 0(3,1) 0(3,2) 0(3,3) 
0(2,0) 0(2,1) 4(2,2) 8(2,3) 
0(1,0) 0(1,1) 0(1,2) 0(1,3) 
0(0,0) 0(0,1) 0(0,2) 0(0,3) 

通过观察我们会发现以下的公式:x1 = 3 - y ,y1 = x,将该公司代入运算:

(3,0)的值替换到了(0,0),将(0,0)带入运算结果为(3 - 0,0)
(3,1)的值替换到了(1,0),将(1,0)带入运算结果为(3 - 0,1)
(3,2)的值替换到了(2,0),将(2,0)带入运算结果为(3 - 0,2)
(3,3)的值替换到了(3,0),将(3,0)带入运算结果为(3 - 0,3)

左右对调的实现

上面的例子我们已经实现了逆时针的旋转,那么我们接下来要实现的就是左边向右边针旋转,旋转好的效果如下:

============旋转以后数组情况============
0(3,0) 0(2,0) 0(1,0) 0(0,0) 
0(3,1) 0(2,1) 0(1,1) 0(0,1) 
0(3,2) 4(2,2) 0(1,2) 0(0,2) 
0(3,3) 8(2,3) 0(1,3) 0(0,3) 

通过观察我们会发现以下的公式:x1 = 3 - x ,y1 = y,将该公司代入运算:

(3,0)的值替换到了(0,0),将(0,0)带入运算结果为(3 - 0,0)
(2,0)的值替换到了(1,0),将(1,0)带入运算结果为(3 - 1,0)
(1,0)的值替换到了(2,0),将(2,0)带入运算结果为(3 - 2,0)
(0,0)的值替换到了(3,0),将(3,0)带入运算结果为(3 - 3,0)

到此处我们已经讲解好了我们的数组的相关翻转的是西安,那么接下来我们就来使用我们的代码来是实现以上的逻辑

代码实现

首先是我们的翻转逻辑的实现的代码:

    /**
     * 功能描述: 实现数组的旋转
     * @param array 待旋转的数组
     * @param coverX 实现x轴上的方法
     * @param coverY 实现y轴上的方法
     */
    fun covery(
        array: Array<Array<Blob>>,
        coverX: (x: Int, y: Int, size: Int) -> Int,
        coverY: (x: Int, y: Int, size: Int) -> Int
    ) {
        var changeArray = Array(4) { y -> Array(4) { 0 } }
        var size = array.size
        for (y in 0 until size) {
            for (x in 0 until size) {
                if (changeArray[y][x] == 1) {
                    continue
                }
                var temp = array[y][x]
                array[y][x] = array[coverY(x, y, size)][coverX(x, y, size)]
                array[coverY(x, y, size)][coverX(x, y, size)] = temp
                changeArray[coverY(x, y, size)][coverX(x, y, size)] = 1
            }
        }
    }

接着是我们的相应的操作来实现数组的翻转:

    /**
     * 功能描述: 实现数组方向的旋转
     * @param array 待旋转的数组
     * @param direction 当前移动的方向
     */
    fun rotateArray(array: Array<Array<Blob>>, direction: String) {
        when (direction) {
            "left" ->{
                covery(array, { x: Int, y: Int, size: Int -> size - 1 - x }, { x: Int, y: Int, size: Int -> y });
            }
            "top" -> {
                covery(array, { x: Int, y: Int, size: Int -> size - 1 - y }, { x: Int, y: Int, size: Int -> x })
            }
            "bottom" -> {
                covery(array, { x: Int, y: Int, size: Int -> y }, { x: Int, y: Int, size: Int -> size - 1 - x })
            }
        }
    }

最后我们改造我们的主入口函数,修改以后的代码如下:

        /**
         * 主入口函数
         * @JvmStatic
         */
        @JvmStatic
        fun main(args: Array<String>) {
            var arrDemo = ArrDemo()
            var array = arrDemo.createArray()
            array[3][2].value = 8
            array[2][2].value = 4
            arrDemo.dumpArray(array, "初始化以后数组情况")
            arrDemo.rotateArray(array, "top")
            arrDemo.dumpArray(array, "旋转以后数组情况")
            arrDemo.rotateArray(array, "bottom")
            arrDemo.dumpArray(array, "旋转回来数组情况")
            arrDemo.rotateArray(array, "left")
            arrDemo.dumpArray(array, "对调以后数组情况")

        }

最后我们执行我们的程序会看到如下的结果:

============初始化以后数组情况============
0(0,0) 0(1,0) 0(2,0) 0(3,0) 
0(0,1) 0(1,1) 0(2,1) 0(3,1) 
0(0,2) 0(1,2) 4(2,2) 0(3,2) 
0(0,3) 0(1,3) 8(2,3) 0(3,3) 
============旋转以后数组情况============
0(0,3) 0(0,2) 0(0,1) 0(0,0) 
0(1,3) 0(1,2) 0(1,1) 0(1,0) 
8(2,3) 4(2,2) 0(2,1) 0(2,0) 
0(3,3) 0(3,2) 0(3,1) 0(3,0) 
============旋转回来数组情况============
0(0,0) 0(1,0) 0(2,0) 0(3,0) 
0(0,1) 0(1,1) 0(2,1) 0(3,1) 
0(0,2) 0(1,2) 4(2,2) 0(3,2) 
0(0,3) 0(1,3) 8(2,3) 0(3,3) 
============对调以后数组情况============
0(3,0) 0(2,0) 0(1,0) 0(0,0) 
0(3,1) 0(2,1) 0(1,1) 0(0,1) 
0(3,2) 4(2,2) 0(1,2) 0(0,2) 
0(3,3) 8(2,3) 0(1,3) 0(0,3)