再探设计模式之状态模式(纸牌游戏的开发)

状态模式主要用于检测和切换状态,在状态模式下状态的转化对于客户端是透明的,常用场合比如公文的流转,游戏的角色升级

package com.linewell.modeldesign.state

import scala.util.Random

/**
* 某软件公司欲开发一款纸牌游戏软件,在该软件中用户角色具有入门级、熟练级、高手级和骨灰级
* 角色的等级和积分对应,游戏胜利增加积分,游戏失败扣除积分
* 入门级具有最基本的功能play() 0 - 20
* 熟练级在呢家了游戏胜利积分加倍功能doubleScore() 20 -40
* 高手级在熟练级的基础上增加了换牌的功能changeCards() 40 -80
* 骨灰级在高手级的基础上增加了偷看系统牌的机会peekCards() 80
*
* Created by ctao on 2015/9/3.
*/

/**
* 环境类
* @param score 积分
* @param level 等级
*/
case class Role(var score: Double = 1, var level: Level = null) {
    /**
     * 自己可交换的牌
     */
    var visibleCard = 0
    /**
     * 自己不可交换的牌
     */
    var invisibleCard = 0
    /**
     * 系统可交换的牌
     */
    var systemVisibleCard = 0
    /**
     * 系统不可交换的牌
     */
    var systemInvisibleCard = 0

    /**
     * 设置初始等级
     */
    level = Primary(this)

    /**
     * 进行纸牌游戏,从控制台读入数据
     */
    private def check(point: Double): Unit = {

        /**
         * 初始化牌组
         */
        initCard()

        /**
         * 检测状态
         */
        checkState()


        println(s"自己的可交换牌${visibleCard}自己的不可交换牌${invisibleCard}系统的可交换牌${systemVisibleCard}系统不可交换牌$systemInvisibleCard")

        /**
         * 选择等级对应的玩法
         */
        level.play(point)


    }

    /**
     * 检测状态,如果积分在0-20则将level设置为入门级
     * 如果积分在20-40则将level设置为熟练级
     * 如果积分在40-80则将level设置为高手级
     * 如果积分在80以上在将level设置为骨灰级
     */
    private def checkState(): Unit = score match {
        case s if s >= 0 && s < 20 => level = Primary(this)
        case s if s >= 20 && s < 40 => level = Secondary(this)
        case s if s >= 40 && s < 80 => level = Professional(this)
        case s if s >= 80 => level = Final(this)
    }

    /**
     * 初始化牌,每一次play的时候洗牌
     */
    private def initCard(): Unit = {
        visibleCard = Random.nextInt(10)
        invisibleCard = Random.nextInt(10)
        systemVisibleCard = Random.nextInt(10)
        systemInvisibleCard = Random.nextInt(10)
    }

    /**
     * 模版方法
     * 玩游戏,从控制台读入
     */
    def play(): Unit = {
        println(s"当前积分为$score,请输入您本次游戏的筹码,0退出本游戏")
        var point = io.StdIn.readDouble()
        while (point != 0) {
            check(point)
            println(s"当前积分为$score,请输入您本次游戏的筹码,0退出本游戏")
            point = io.StdIn.readDouble()
        }
        println("感谢您的使用,下次再见")
    }
}



package com.linewell.modeldesign.state

import scala.util.Random

/**
* 等级,抽象状态
* Created by ctao on 2015/9/3.
*/
sealed abstract class Level(role: Role) {
    /**
     * 是否翻倍
     */
    var isDoubleScore = false

    /**
     * 是否偷看别人牌
     */
    var isPeekCard = false

    /**
     * 是否交换牌
     */
    var isChangeCard = false


    /**
     * 玩牌,模版方法
     * @param point 押注大小
     */
    def play(point: Double) = {
        /**
         * 先判断是否看对方牌
         */
        isPeekCard match {
            case true => peekCards()
            case false => isChangeCard match {
                /**
                 * 判断是否交换牌
                 */
                case true => changeCards()
                case false =>
            }
        }

        /**
         * 筹码如果大于积分,则积分不够,如果筹码小于0,则输出筹码不够
         * 进入游戏
         * 判断自己的可交换牌和自己不可交换牌之和与系统可交换牌与不可交换牌之和的大小
         * 如果大则胜出,如果有翻倍卡,则筹码*2加到自己积分上
         * 如果小则输掉,则积分减去本次筹码
         */
        point match {
            case p if p > role.score => println("积分不够")
            case p if p < 0 => println("请选择大于0的筹码")
            case _ => println("玩纸牌游戏")
                if ((role.systemInvisibleCard + role.systemVisibleCard) > (role.invisibleCard + role.visibleCard)) {
                    role.score -= point
                    println(s"你输了您现在还有${role.score}积分")

                } else {
                    print("你赢了")
                    if (isDoubleScore) {
                        doubleScore(point)
                    } else {
                        role.score += point
                    }
                    println(s"您现在还有${role.score}积分")
                }
        }

    }


    /**
     * 筹码翻倍方法
     * @param point 筹码
     */
    private def doubleScore(point: Double): Unit = {
        println("筹码翻倍")
        role.score += (point * 2)
    }

    /**
     * 交换手牌
     */
    private def changeCards() = {
        role.visibleCard = role.systemVisibleCard + role.visibleCard
        role.systemVisibleCard = role.visibleCard - role.systemVisibleCard
        role.visibleCard = role.visibleCard - role.systemVisibleCard
        println("换牌")
        println(s"交换后自己的可交换牌${role.visibleCard}自己的不可交换牌${role.invisibleCard}系统的可交换牌${role.systemVisibleCard}系统不可交换牌${role.systemInvisibleCard}")
    }

    /**
     * 偷看系统可交换牌
     * 如果自己可交换牌小于系统的,则交换
     */
    private def peekCards(): Unit = {
        println("偷看系统的牌")
        if (role.systemVisibleCard > role.visibleCard) {
            changeCards()
        }
    }

}


/**
* 入门级
* @param role 角色
*/
case class Primary(role: Role) extends Level(role)

/**
* 熟练级
* @param role 角色
*/
case class Secondary(role: Role) extends Level(role) {
    /**
     * 积分翻倍
     */
    isDoubleScore = true
}

/**
* 高手级
* @param role 角色
*/
case class Professional(role: Role) extends Level(role) {
    /**
     * 积分翻倍
     */
    isDoubleScore = true

    /**
     * 换牌
     */
    isChangeCard = Random.nextBoolean()
}

/**
* 骨灰级
* @param role 角色
*/
case class Final(role: Role) extends Level(role) {
    /**
     * 积分翻倍
     */
    isDoubleScore = true

    /**
     * 换牌
     */
    isChangeCard = true

    /**
     * 偷看系统牌
     */
    isPeekCard = true
}


package com.linewell.modeldesign.state

/**
* 状态模式测试客户端
* Created by ctao on 2015/9/4.
*/
object Client extends App {
    val role = Role(40)
    role play()



}

猜你喜欢

转载自cjuexuan.iteye.com/blog/2240586