24. 簡單玩玩kotlin for android,隨機(jī)數(shù)字買彩票

現(xiàn)在 kotlin 用的較多的領(lǐng)域,應(yīng)該是 android 應(yīng)用開發(fā)了吧。最近開了個(gè)小差,有人買彩票不想自己預(yù)測了,也不想現(xiàn)場用彩票店的機(jī)器出號,太費(fèi)事兒。就用 kotlin 寫個(gè)手機(jī) apk 給他。要求也不高,只要隨機(jī)出數(shù)字就行。
需求搞清楚了,可以開工了。
首先要確定,他可能還要給自己的舊手機(jī)也裝上,為求萬千穩(wěn)妥,API 的最小版本選擇了 15。

選擇API版本

之后選擇空的 Activity 就開場了。
選擇空活動(dòng)

系統(tǒng)默認(rèn)給出一個(gè)界面。
我們不理他,因?yàn)椋€計(jì)劃著以后再繼續(xù)在這個(gè)項(xiàng)目中萬一增加其他小工具呢。
所以新建一個(gè)package,取名就用漢語拼音吧。CaiPiao
新建package

新建好的package

然后在這個(gè) package 下新建一個(gè)空活動(dòng)(Empty Activity)
新建空活動(dòng)

下面,我們要做的第一件事,就是讓第一個(gè)活動(dòng)(MainActivity)被應(yīng)用啟動(dòng)后,直接跳轉(zhuǎn)到我們這個(gè) CaiPiao 下的空活動(dòng)來。
主活動(dòng)和彩票的活動(dòng)

打開 MainActivity ,添加代碼。先寫一個(gè)函數(shù) OpenCaiPiao ,在函數(shù)內(nèi)實(shí)現(xiàn)需要的功能。

    //跳轉(zhuǎn)到彩票界面
    fun OpenCaiPiao(){//我要順順的來
        val intent = Intent()
        intent.setClass(this, CaipiaoActivity::class.java)
        startActivity(intent)
    }

把它放在 class MainActivity 內(nèi),并在 onCreate 函數(shù)內(nèi)添加調(diào)用語句 OpenCaiPiao()

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

        OpenCaiPiao()

    }

這時(shí)候,我們的注意力就可以專注到真正的業(yè)務(wù)模塊中了。
在 res>layout 中打開 activity_caipiao.xml,拖拽三個(gè) button 和 兩個(gè) textview。
一個(gè) button 對應(yīng)“雙色球”
一個(gè) button 對應(yīng)“大樂透”
一個(gè) button 對應(yīng)“清除”功能
一個(gè) textview 對應(yīng)給出的彩票號碼
一個(gè) textview 對應(yīng)給出彩票號碼的時(shí)間
現(xiàn)在流行最新的布局方式,也是默認(rèn)的ConstraintLayout。我就用這種了。


出號界面布局

這個(gè)布局中,為了保持“隨機(jī)號碼”和“出號時(shí)間”的左對齊,只設(shè)定了上邊和左邊的距離,它們字號不同,控制了右邊距離的話,文字內(nèi)容發(fā)生改變,會(huì)有對不齊的情況發(fā)生。
雙色球和大樂透兩個(gè)按鈕,略有不同,雙色球設(shè)置了上、左、右到邊沿,而大樂透的左邊是指在雙色球按鈕的右側(cè)控鍵上。這樣,兩個(gè)按鈕的位置就相對固定了。不論橫屏還是豎屏都不會(huì)變。
相似的“清除按鈕”的上邊constraint也控制到雙色球按鈕的下側(cè)控鍵上,這樣“清除按鈕”和“雙色球按鈕”的相對位置也就保持不變了。


界面設(shè)置完畢

下面就該填寫這個(gè)Activity中的代碼了。
界面中可以直接操作就是這三個(gè)按鈕了,先在 CaiPiaoActivity.kt 的 OnCreate 中增加這三個(gè)按鈕的 OnClick 事件的監(jiān)聽。
        //雙色球
        btnGetShuangSeQiu.setOnClickListener {
        }
        //大樂透
        btnDaLeTou.setOnClickListener {
        }
        //清除取消
        btnCancel.setOnClickListener {
        }

隨機(jī)出彩票號碼,那么核心功能是隨機(jī)了。先寫一個(gè)在指定的范圍內(nèi)出隨機(jī)數(shù)字的函數(shù)出來。

/**
 * 取得min到max之間的隨機(jī)整數(shù)(不包含max)
 * @min 最小取值
 * @max 最大取值邊界(此值不取)
 * */
fun cofoxRandom(min: Int = 0, max: Int): Int {
    var t_min = min
    var t_max = max
    if (t_min > t_max) {
        var temp: Int
        temp = t_min
        t_min = t_max
        t_max = temp
    }
    var random = (Math.floor(Math.random() * (t_max - t_min))).toInt() + t_min

    return random
}

這里要注意這個(gè)注釋的寫法

/**
 *
 * */

這樣標(biāo)準(zhǔn)的寫法能夠被 IDE 準(zhǔn)確的識別,才能有下面的效果。

標(biāo)準(zhǔn)的注釋寫法很重要,會(huì)讓你很方便。

我們要寫雙色球的隨機(jī)出號了
首先定義一個(gè)整數(shù)數(shù)組,先都賦值為 0 好了。

var ints = intArrayOf(0, 0, 0, 0, 0, 0, 0)

當(dāng)然你也可以這樣寫

var ints = Array(7,{0})

第一種寫法,是方便直接把所有的數(shù)組元素(不同值)都寫進(jìn)去。
第二種寫法,更簡潔一些,適合初始化時(shí)候都賦相同值的情況。
建立了數(shù)組,就該把隨機(jī)數(shù)字填寫進(jìn)去了。

    for (i in 1..6) {
        ints[i - 1] = cofoxRandom(1, 34)
    }

雙色球是 6 + 1 的出球方式。我們先出 6 個(gè)紅球,所以是 1..6。
由于 cofoxRandom 函數(shù)的max值是不包含在可選范圍內(nèi)的,所以1-33個(gè)紅球號碼,我們需要的參數(shù)是(1, 34)
至于 ints[i-1],是因?yàn)椋瑪?shù)組的下標(biāo)是從 0 開始的。
這樣就可以把 6 個(gè)球號得到了。
但是,還有個(gè)問題,數(shù)字是亂的。我們需要給這 6 個(gè)數(shù)字排序。這也是一個(gè)很常見的需求。

    //排序前六位,第七位當(dāng)臨時(shí)存儲(chǔ)位
    for (i in ints.indices) {
        for (j in ints.indices - i) {
            if (j < ints.size - 1) {
                if (ints[j] > ints[j + 1]) {
                    ints[ints.size - 1] = ints[j + 1]
                    ints[j + 1] = ints[j]
                    ints[j] = ints[ints.size - 1]
                }
            }
        }
    }

這里,我們?yōu)榱斯?jié)省內(nèi)存,就不再另外加變量了。先利用那個(gè)藍(lán)色號碼的位置,作為排序時(shí)的臨時(shí)存儲(chǔ)位。每次循環(huán),都把較大的一個(gè)數(shù)字往后移動(dòng)一位。于是,在第二層循環(huán),每次循環(huán)都可以少循環(huán)一個(gè)已經(jīng)確定了的較大數(shù)字。這就是

    for (i in ints.indices) {
        for (j in ints.indices - i) {

這個(gè)的來由。順便說一下,indices是取得ints下標(biāo)的意思。這樣i和j就能得到當(dāng)前循環(huán)的具體下標(biāo)了。
循環(huán)完,一個(gè)由小到大排列好的數(shù)組就出來了。
如果想完美,還有一個(gè)問題要解決,重復(fù)數(shù)字。隨機(jī)給出的數(shù)字經(jīng)常是重復(fù)的。只要再加一個(gè)邏輯,當(dāng)新的隨機(jī)數(shù)出來后,判斷一下在數(shù)組中是否存在這個(gè)數(shù)字了即可。如果存在,當(dāng)前循環(huán)內(nèi)再次取得隨機(jī)數(shù),直到取得了不在數(shù)組中的數(shù)字為止。
我們可以用 for 循環(huán)嵌套 while 循環(huán)實(shí)現(xiàn)。我們來修改剛才那個(gè) 隨機(jī)數(shù)字填寫 的 for 循環(huán)。

    for (i in 1..6) {
//        ints[i - 1] = cofoxRandom(1, 34)
        var temp = cofoxRandom(1, 34)
        while (temp in ints){
            temp = cofoxRandom(1, 34)
        }
        ints[i - 1] = temp
    }

現(xiàn)在,數(shù)組內(nèi)的號碼球數(shù)字不會(huì)重復(fù)了。
雙色球還有一個(gè)藍(lán)色號碼求哦,這個(gè)就直接出好了。

ints[ints.size-1] = cofoxRandom(1, 17)//藍(lán)色號碼球

數(shù)字都出完了。我們還可以來調(diào)一調(diào)數(shù)字格式。因?yàn)椋幸晃粩?shù)也有兩位數(shù)嘛,排列總是看起來有點(diǎn)不夠整齊。那就一位數(shù)的都在左側(cè)補(bǔ)0吧。不僅如此,每個(gè)數(shù)字之間用逗號(,)分隔開,再把紅球和藍(lán)球用短橫線(-)分隔開。

    //按格式書寫
    var str = "雙色球:"
    for (i in ints.indices) {
        if (ints[i].toString().length < 2){
            str += "0"+ints[i].toString()
        }else {
            str += ints[i]
        }

        if (i == ints.size-2){
            str += " - "
        }else if (i == ints.size -1){

        }else{
            str += ", "
        }
    }

好了。重要的代碼都寫完了。剩下就是把 str 賦值給界面控件了吧?
還可以再多做一點(diǎn)事情。不要把這么多的代碼都放進(jìn) onCreate ,獨(dú)立出一個(gè)函數(shù)來。讓代碼更整潔。于是,我們可以得到一個(gè)“福彩雙色球隨機(jī)猜想出號”函數(shù)了。

/**
 * 福彩雙色球隨機(jī)猜想出號
 * */
fun cofoxShuangSeQiu(ttvw:TextView){
//    var ints = intArrayOf(0, 0, 0, 0, 0, 0, 0)
    var ints = Array(7,{0})
    for (i in 1..6) {
//        ints[i - 1] = cofoxRandom(1, 34)
        var temp = cofoxRandom(1, 34)
        while (temp in ints){
            temp = cofoxRandom(1, 34)
        }
        ints[i - 1] = temp
    }
    //排序前六位,第七位當(dāng)臨時(shí)存儲(chǔ)位
    for (i in ints.indices) {
        for (j in ints.indices - i) {
            if (j < ints.size - 1) {
                if (ints[j] > ints[j + 1]) {
                    ints[ints.size - 1] = ints[j + 1]
                    ints[j + 1] = ints[j]
                    ints[j] = ints[ints.size - 1]
                }
            }
        }
    }

    ints[ints.size-1] = cofoxRandom(1, 17)//藍(lán)色號碼球

    //按格式書寫
    var str = "雙色球:"
    for (i in ints.indices) {
        if (ints[i].toString().length < 2){
            str += "0"+ints[i].toString()
        }else {
            str += ints[i]
        }

        if (i == ints.size-2){
            str += " - "
        }else if (i == ints.size -1){

        }else{
            str += ", "
        }
    }
    ttvw.text = str
}

而 onCreate 中對這個(gè)函數(shù)進(jìn)行調(diào)用。

cofoxShuangSeQiu(ttvwRandomNumber)

ttvwRandomNumber 就是 textview 的 id
在界面上為了更友好一些,我們增加了出號時(shí)間。現(xiàn)在就是添加這個(gè)功能代碼的時(shí)候了。

/**
 * 顯示當(dāng)前出號時(shí)間
 * */
fun cofoxGetNumberTime(ttvw: TextView){
    //出號時(shí)間
    var ver = android.os.Build.VERSION.SDK_INT
    if (ver >= 24){
        ttvw.text = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
    }else{
        val calendar = GregorianCalendar()
        ttvw.text = GregorianCalendar().get(Calendar.YEAR).toString() +"-"+ (GregorianCalendar().get(Calendar.MONTH)+1).toString() +"-"+ GregorianCalendar().get(Calendar.DAY_OF_MONTH).toString() +" "+ GregorianCalendar().get(Calendar.HOUR).toString() +":"+ GregorianCalendar().get(Calendar.MINUTE).toString() +":"+ GregorianCalendar().get(Calendar.SECOND).toString()
    }
}

好吧,這也是寫成了一個(gè)函數(shù)。并且其中用了兩種取得當(dāng)前時(shí)間的方法。因?yàn)椋覀冮_始的時(shí)候,希望這個(gè)應(yīng)用能支持到 API 15,而最簡潔最新的時(shí)間獲取的寫法是從 API 24 之后才開才是支持的。
那么先判斷一下當(dāng)前運(yùn)行的 android 系統(tǒng)的 API 是哪個(gè)版本,然后對癥下藥。
之后,我們再把調(diào)用語句寫入 onCreate 中。

        //雙色球
        btnGetShuangSeQiu.setOnClickListener {
            cofoxShuangSeQiu(ttvwRandomNumber)
            cofoxGetNumberTime(ttvwTime)    //出號時(shí)間

        }

雙色球的調(diào)用完成了。
大樂透只是稍有不同
大樂透的號碼球一共也是 7 個(gè),但是,大樂透的玩法是分前區(qū)和后區(qū)。是 5 + 2 的結(jié)構(gòu)。所以,在雙色球的代碼基礎(chǔ)上略微修改就可以獲得大樂透的寫法了。

/**
 * 體彩大樂透隨機(jī)猜想出號
 * */
fun cofoxDaLeTou(ttvw:TextView){
//    var ints = intArrayOf(0, 0, 0, 0, 0, 0, 0)
    var ints = Array(7,{0})
    for (i in 1..5) {
//        ints[i - 1] = cofoxRandom(1, 36)
        var temp = cofoxRandom(1, 36)
        while (temp in ints){
            temp = cofoxRandom(1, 36)
        }
        ints[i - 1] = temp
    }

    //排序前5位,第6位當(dāng)臨時(shí)存儲(chǔ)位
    for (i in ints.indices - 2) {
        for (j in ints.indices - i) {
            if (j < ints.size - 2) {
                if (ints[j] > ints[j + 1]) {
                    ints[ints.size - 2] = ints[j + 1]
                    ints[j + 1] = ints[j]
                    ints[j] = ints[ints.size - 2]
                }
            }
        }
    }

    ints[ints.size-2] = cofoxRandom(1, 13)//后區(qū)號碼球1
    ints[ints.size-1] = cofoxRandom(1, 13)//后區(qū)號碼球2

    //按格式書寫
    var str = "大樂透:"
    for (i in ints.indices) {
        if (ints[i].toString().length < 2){
            str += "0"+ints[i].toString()
        }else {
            str += ints[i]
        }

        if (i == ints.size-3){
            str += " - "
        }else if (i == ints.size -1){

        }else{
            str += ", "
        }
    }
    ttvw.text = str
}

這時(shí)候,在 onCreate 中修改大樂透的調(diào)用代碼就簡單多了。

        //大樂透
        btnDaLeTou.setOnClickListener {
            cofoxDaLeTou(ttvwRandomNumber)
            cofoxGetNumberTime(ttvwTime)    //出號時(shí)間

        }

還記得我們的“清除”按鈕嗎?是的,也要在 onCreate 中寫上監(jiān)聽代碼。

        //清除取消
        btnCancel.setOnClickListener {
            ttvwRandomNumber.text = resources.getString(R.string.txt_cnword_隨機(jī)號碼)
            ttvwTime.text = resources.getText(R.string.txt_出號時(shí)間)
        }

這里的 R.string 是什么?它們資源文件 res>values 下 strings.xml 內(nèi)的東西。
我們在這里實(shí)踐了一下編碼中對中文變量的支持。呵呵。


資源在這里

這下知道兩個(gè)textview上的文字從哪里來的了

編譯一下


我用真機(jī)編譯

Screenshot_2017-11-21-01-22-33-332_com.cofox.mykt.cst.png

Screenshot_2017-11-21-01-22-42-531_com.cofox.mykt.cst.png

Screenshot_2017-11-21-01-22-48-955_com.cofox.mykt.cst.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容