想不到能这样摸鱼

介绍

想不到有一天我也能在写代码的同时还能斗一把小地主!

这种休闲 摸鱼 模式想法来自逛掘金时看到这篇文章 高端程序员上班摸鱼指南 介绍的Ratel。有兴趣的小伙伴可以直接搜索Ratel具体了解。本着一个探索瞎折腾的心,决定仿照Ratel实现自己的Fish项目。

这款游戏基于Golang实现,目前仅支持PVP模式,后续有时间再支持更多的模式。

项目地址

github.com/yangchen5710/fish_clien...

技术栈

  • Golang
  • SocketIO

安装

首先下载编译,确保本地安装有Golang环境

git clone git@github.com:yangchen5710/fish_client.git
cd fish_client
go build fish_client

接下来在终端下执行可执行文件

  • windows

    client.exe 47.101.212.202 8096
  • linux/macos

    ./client 47.101.212.202 8096

玩法

为啥论坛不能上传gif了?
想不到能这样摸鱼

出牌规则

所有牌型:

┌──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐
│3 |4 |5 |6 |7 |8 |9 |10|J |Q |K |A |2 |S |X |
│♦ |||||||||||||  |  |
└──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘
  • 王炸: sx
  • 顺子: 34567
  • 三带一: 3334
  • 三带二: 33344
  • 飞机: 333444a2
  • 单张10: t
  • 单张A: a
  • 封顶顺子: 3456789tjqka
  • 不想出牌: pass

算法实现

首先我们先定义相关结构和接口以及相关常量

 const (
    Rocket            = 12
    Bomb              = 11
    Pair              = 10
    Three             = 9
    ThreeWithOne      = 8
    ThreeWithTwo      = 7
    SingleStraight    = 6
    DoubleStraight    = 5
    ThreeStraight     = 4
    AircraftWithWings = 3
    FourWithTwo       = 2
    Single            = 1
)


 type Poker struct {
    Level string //牌的数值
    Type  string //牌的类型
}

type PokerMath struct {
    PokerType   int
    MinValue    int
    PokerLength int
}

type PokerAlgorithm interface {
    IsRocket(Poker, Poker) (bool, PokerMath)       //火箭 即大小王
    IsBomb([]Poker) (bool, PokerMath)              //炸弹 四张同数值牌
    IsPair([]Poker) (bool, PokerMath)              //对牌 数值相同的两张牌
    IsThree([]Poker) (bool, PokerMath)             //三张牌 数值相同的三张牌
    IsThreeWithOne([]Poker) (bool, PokerMath)      //三带一 数值相同的三张牌 + 一张单牌
    IsThreeWithTwo([]Poker) (bool, PokerMath)      //三带二 数值相同的三张牌 + 一张对牌
    IsSingleStraight([]Poker) (bool, PokerMath)    //单顺 五张或更多的连续单牌(如:45678 或 789tJQK)。不包括 2 点和双王
    IsDoubleStraight([]Poker) (bool, PokerMath)    //双顺 三对或更多的连续对牌(如:334455 、77 88 99 1010 JJ)。不包括 2 点和双王
    IsThreeStraight([]Poker) (bool, PokerMath)     //三顺:二个或更多的连续三张牌(如:333444 、 555 666 777 888)。不包括 2 点和双王
    IsAircraftWithWings([]Poker) (bool, PokerMath) //飞机带翅膀:三顺+同数量的单牌(或同数量的对牌)
    IsFourWithTwo([]Poker) (bool, PokerMath)       //四带二:四张牌+两手牌(注意:四带二不是炸弹)。
    IsSingle(Poker) (bool, PokerMath)              //单牌
    ComparePokers(PokerMath, PokerMath) bool       //比较牌型和大小
}

然后去实现相关的接口算法

func (pm PokerMath) IsRocket(poker1, poker2 Poker) (boolean bool, pokerMath PokerMath) {
    boolean = (poker1.Level == "LEVEL_SMALL_KING" && poker2.Level == "LEVEL_BIG_KING") ||
        (poker1.Level == "LEVEL_BIG_KING" && poker2.Level == "LEVEL_SMALL_KING")
    if boolean {
        pokerMath = PokerMath{PokerType: Rocket, MinValue: 0, PokerLength: 2}
    }
    return
}

func (pm PokerMath) IsBomb(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers) != 4 {
        return
    }

    valueMap := make(map[string]int)
    for _, poker := range pokers {
        valueMap[poker.Level]++
    }

    for pokerLevel, count := range valueMap {
        if count == 4 {
            boolean = true
            pokerMath = PokerMath{PokerType: Bomb, MinValue: convertToValueInit(pokerLevel), PokerLength: 4}
            return
        }
    }
    return
}

func (pm PokerMath) IsPair(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers) != 2 {
        return
    }

    valueMap := make(map[string]int)
    for _, poker := range pokers {
        valueMap[poker.Level]++
    }

    for pokerLevel, count := range valueMap {
        if count == 2 {
            boolean = true
            pokerMath = PokerMath{PokerType: Pair, MinValue: convertToValueInit(pokerLevel), PokerLength: 2}
            return
        }
    }

    return
}

func (pm PokerMath) IsThree(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers) != 3 {
        return
    }

    valueMap := make(map[string]int)
    for _, poker := range pokers {
        valueMap[poker.Level]++
    }

    for pokerLevel, count := range valueMap {
        if count == 3 {
            boolean = true
            pokerMath = PokerMath{PokerType: Three, MinValue: convertToValueInit(pokerLevel), PokerLength: 3}
            return
        }
    }

    return
}

func (pm PokerMath) IsThreeWithOne(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers) != 4 {
        return
    }

    sort.Slice(pokers, func(i, j int) bool {
        return pokers[i].Level < pokers[j].Level
    })

    // 判断是否是三带一,即第一个三张牌点数相同,且第四张牌与其中一张牌的点数不同
    if pokers[0].Level == pokers[1].Level && pokers[1].Level == pokers[2].Level &&
        pokers[2].Level != pokers[3].Level {
        boolean = true
        pokerMath = PokerMath{PokerType: ThreeWithOne, MinValue: convertToValueInit(pokers[0].Level), PokerLength: 4}
        return
    }

    // 也可以判断最后三张牌是否相同点数
    if pokers[1].Level == pokers[2].Level && pokers[2].Level == pokers[3].Level &&
        pokers[0].Level != pokers[1].Level {
        boolean = true
        pokerMath = PokerMath{PokerType: ThreeWithOne, MinValue: convertToValueInit(pokers[1].Level), PokerLength: 4}
        return
    }

    return
}

func (pm PokerMath) IsThreeWithTwo(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers) != 5 {
        return
    }

    sort.Slice(pokers, func(i, j int) bool {
        return pokers[i].Level < pokers[j].Level
    })

    // 判断是否是三带二
    if pokers[0].Level == pokers[1].Level && pokers[1].Level == pokers[2].Level &&
        pokers[3].Level == pokers[4].Level && pokers[2].Level != pokers[3].Level {
        boolean = true
        pokerMath = PokerMath{PokerType: ThreeWithTwo, MinValue: convertToValueInit(pokers[0].Level), PokerLength: 5}
        return
    }

    // 也可以判断三张和两张的位置对调
    if pokers[0].Level == pokers[1].Level && pokers[2].Level == pokers[3].Level &&
        pokers[3].Level == pokers[4].Level && pokers[1].Level != pokers[2].Level {
        boolean = true
        pokerMath = PokerMath{PokerType: ThreeWithTwo, MinValue: convertToValueInit(pokers[2].Level), PokerLength: 5}
        return
    }

    return
}

func (pm PokerMath) IsSingleStraight(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers) < 5 {
        return
    }

    sort.Slice(pokers, func(i, j int) bool {
        // 将牌的值转换为对应的数值进行比较
        val1 := convertToValue(pokers[i].Level)
        val2 := convertToValue(pokers[j].Level)
        return val1 < val2
    })

    // 检查牌是否连续
    for i := 0; i < len(pokers)-1; i++ {
        if convertToValue(pokers[i+1].Level)-convertToValue(pokers[i].Level) != 1 {
            return // 如果有间断,不是单顺
        }
    }
    boolean = true
    pokerMath = PokerMath{PokerType: SingleStraight, MinValue: convertToValueInit(pokers[0].Level), PokerLength: len(pokers)}
    return
}

func (pm PokerMath) IsDoubleStraight(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers)%2 != 0 || len(pokers) < 6 {
        return // 牌数必须是偶数且至少6张才可能是双顺
    }

    // 对牌进行排序
    sort.Slice(pokers, func(i, j int) bool {
        // 将牌的值转换为对应的数值进行比较
        val1 := convertToValue(pokers[i].Level)
        val2 := convertToValue(pokers[j].Level)
        return val1 < val2
    })

    fmt.Println(pokers)

    // 检查牌是否连续成对
    for i := 0; i < len(pokers)-1; i += 2 {
        if convertToValue(pokers[i].Level) != convertToValue(pokers[i+1].Level) ||
            (i > 0 && convertToValue(pokers[i].Level)-convertToValue(pokers[i-1].Level) != 1) {
            return // 如果不是成对连续,不是双顺
        }
    }

    boolean = true
    pokerMath = PokerMath{PokerType: DoubleStraight, MinValue: convertToValueInit(pokers[0].Level), PokerLength: len(pokers)}
    return
}

func (pm PokerMath) IsThreeStraight(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers)%3 != 0 || len(pokers) < 6 {
        return // 牌数必须是3的倍数且至少6张才可能是三顺
    }

    // 对牌进行排序
    sort.Slice(pokers, func(i, j int) bool {
        // 将牌的值转换为对应的数值进行比较
        val1 := convertToValue(pokers[i].Level)
        val2 := convertToValue(pokers[j].Level)
        return val1 < val2
    })

    // 检查牌是否连续三张
    for i := 0; i < len(pokers)-2; i += 3 {
        if convertToValue(pokers[i].Level) != convertToValue(pokers[i+1].Level) ||
            convertToValue(pokers[i].Level) != convertToValue(pokers[i+2].Level) ||
            (i > 0 && convertToValue(pokers[i].Level)-convertToValue(pokers[i-1].Level) != 1) {
            return
        }
    }

    boolean = true
    pokerMath = PokerMath{PokerType: ThreeStraight, MinValue: convertToValueInit(pokers[0].Level), PokerLength: len(pokers)}
    return
}

func (pm PokerMath) IsAircraftWithWings(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers)%4 != 0 || len(pokers) < 8 {
        return // 牌数必须是4的倍数且至少8张才可能是飞机带翅膀
    }

    // 对牌进行排序
    sort.Slice(pokers, func(i, j int) bool {
        // 将牌的值转换为对应的数值进行比较
        val1 := convertToValue(pokers[i].Level)
        val2 := convertToValue(pokers[j].Level)
        return val1 < val2
    })

    // 计算连续三张的数量
    tripleCount := 0
    minValue := ""
    for i := 0; i < len(pokers)-2; i++ {
        if convertToValue(pokers[i].Level) == convertToValue(pokers[i+1].Level) &&
            convertToValue(pokers[i].Level) == convertToValue(pokers[i+2].Level) {
            tripleCount++
            if minValue == "" {
                minValue = pokers[i].Level
            }
        }
    }

    // 检查是否有连续三张的数量大于等于2
    if tripleCount < 2 {
        return // 如果连续三张的数量不足2组,不是飞机带翅膀
    }

    boolean = true
    pokerMath = PokerMath{PokerType: AircraftWithWings, MinValue: convertToValueInit(minValue), PokerLength: len(pokers)}
    return
}

func (pm PokerMath) IsFourWithTwo(pokers []Poker) (boolean bool, pokerMath PokerMath) {
    boolean = false
    if len(pokers) != 6 {
        return // 必须是六张牌才可能是四带二
    }

    // 对牌进行排序
    sort.Slice(pokers, func(i, j int) bool {
        // 将牌的值转换为对应的数值进行比较
        val1 := convertToValue(pokers[i].Level)
        val2 := convertToValue(pokers[j].Level)
        return val1 < val2
    })

    // 计算四张牌的数量
    fourCount := 0
    minValue := ""
    for i := 0; i < len(pokers)-3; i++ {
        if convertToValue(pokers[i].Level) == convertToValue(pokers[i+1].Level) &&
            convertToValue(pokers[i].Level) == convertToValue(pokers[i+2].Level) &&
            convertToValue(pokers[i].Level) == convertToValue(pokers[i+3].Level) {
            fourCount++
            if minValue == "" {
                minValue = pokers[i].Level
            }
        }
    }

    // 检查是否有四张牌
    if fourCount != 1 {
        return // 如果不是四张牌,不是四带二
    }

    // 计算两张其他牌的数量
    otherCount := 0
    for i := 0; i < len(pokers)-1; i++ {
        if convertToValue(pokers[i].Level) != convertToValue(pokers[i+1].Level) {
            otherCount++
        }
    }
    if otherCount != 1 {
        return // 如果不是两张其他牌,不是四带二
    }

    boolean = true
    pokerMath = PokerMath{PokerType: FourWithTwo, MinValue: convertToValueInit(minValue), PokerLength: len(pokers)}
    return
}

func (pm PokerMath) IsSingle(poker Poker) (boolean bool, pokerMath PokerMath) {
    boolean = true
    pokerMath = PokerMath{PokerType: Single, MinValue: convertToValueInit(poker.Level), PokerLength: 1}
    return
}

func (pm PokerMath) ComparePokers(roomPokerMath, playerPokerMath PokerMath) bool {
    roomPokerType := roomPokerMath.PokerType
    roomPokerLength := roomPokerMath.PokerLength
    roomMinValue := roomPokerMath.MinValue

    if roomPokerType == playerPokerMath.PokerType &&
        roomPokerLength == playerPokerMath.PokerLength &&
        roomMinValue < playerPokerMath.MinValue {
        return true
    }

    if roomPokerType != playerPokerMath.PokerType {
        switch roomPokerType {
        case Bomb:
            if playerPokerMath.PokerType == Rocket {
                return true
            }
        case Pair, Three, ThreeWithOne, ThreeWithTwo, SingleStraight, DoubleStraight, ThreeStraight, AircraftWithWings, FourWithTwo, Single:
            if playerPokerMath.PokerType == Rocket || playerPokerMath.PokerType == Bomb {
                return true
            }
        }
    }

    return false
}

func (pm PokerMath) ConvertToValueString(cardValue string) string {
    valueMap := map[string]string{
        "3": "LEVEL_3", "4": "LEVEL_4", "5": "LEVEL_5", "6": "LEVEL_6",
        "7": "LEVEL_7", "8": "LEVEL_8", "9": "LEVEL_9",
        "0": "LEVEL_10", "t": "LEVEL_10", "T": "LEVEL_10",
        "j": "LEVEL_J", "J": "LEVEL_J",
        "q": "LEVEL_Q", "Q": "LEVEL_Q",
        "k": "LEVEL_K", "K": "LEVEL_K",
        "a": "LEVEL_A", "A": "LEVEL_A", "1": "LEVEL_A",
        "2": "LEVEL_2",
        "s": "LEVEL_SMALL_KING", "S": "LEVEL_SMALL_KING",
        "x": "LEVEL_BIG_KING", "X": "LEVEL_BIG_KING",
    }

    return valueMap[cardValue]
}

// 辅助函数:将牌的值转换为数值
func convertToValueInit(cardValue string) int {
    valueMap := map[string]int{
        "LEVEL_3": 3, "LEVEL_4": 4, "LEVEL_5": 5, "LEVEL_6": 6, "LEVEL_7": 7,
        "LEVEL_8": 8, "LEVEL_9": 9, "LEVEL_10": 10, "LEVEL_J": 11, "LEVEL_Q": 12,
        "LEVEL_K": 13, "LEVEL_A": 14, "LEVEL_2": 15, "LEVEL_SMALL_KING": 16, "LEVEL_BIG_KING": 17,
    }

    return valueMap[cardValue]
}

func convertToValue(cardValue string) int {
    value := convertToValueInit(cardValue)
    if value == 15 || value == 16 || value == 17 {
        value = -1
    }
    return value
}

计划

  • 支持PVE
  • 支持个人得分
本作品采用《CC 协议》,转载必须注明作者和本文链接
To live is to change the world
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!