Rumah  >  Artikel  >  Java  >  如何用代码实现扎金花游戏

如何用代码实现扎金花游戏

零下一度
零下一度asal
2017-06-26 14:10:302363semak imbas

扎金花这种小游戏,我想作为一名程序员。大部分小时候都玩过吧!现在我们一起来看看搜狐这道面试题吧!看看如何用代码实现扎金花。


Q题目

事因

两个搜狐的程序员加了一个月班,终于放假了,于是他们决定扎金花渡过愉快的假期 。

游戏规则:

共52张普通牌,牌面为2,3,4,5,6,7,8,9,10,J,Q,K,A之一,大小递增,各四张; 每人抓三张牌。两人比较手中三张牌大小,大的人获胜。

对于牌型的规则如下:

  • 1.三张牌一样即为豹子

  • 2.三张牌相连为顺子(A23不算顺子)

  • 3.有且仅有两张牌一样为对子 豹子>顺子>对子>普通牌型 在牌型一样时,比较牌型数值大小(如AAA>KKK,QAK>534,QQ2>10104) 在二人均无特殊牌型时,依次比较三张牌中最大的。大的人获胜,如果最大的牌一样,则比较第二大,以此类推(如37K>89Q) 如二人牌面相同,则为平局。

输入描述:

输入两个字符串代表两个玩家的牌(如”10KQ” “354”),
先输入的作为玩家1,后输入的作为玩家2

输出描述:

 1 代表 玩家1赢     
 0 代表 平局   
 -1 代表 玩家2赢 
 -2 代表不合法的输入

输入例子:

KQ3 3Q9
10QA 6102
5810 7KK
632 74J
10102 K77
JKJ 926
68K 27A

输出例子:

1
1
-1
-1
1
1
-1

A解法

1.逻辑分析

  • (1)拿到玩家1和2输入的字符串,判断是否合法

  • (2)合法后,拆分字符串为字符串数组

  • (3)将字符串数组转化为int数组,并排序

  • (4)判断3张牌的相等情况

  • (5)比较大小,谁输谁赢

2.难点分析

  • 存在10时,字符串的拆分问题:可以根据字符串长度来判断拆分

  • 将字母转为数字:先将拿到的字符串都转为大写,这样小写和大写字母都一样了,然后直接用if判断return就可以了

  • 比较谁输谁赢:采用从大到小的方式比较,先判断是否有豹子,在判断顺子,再判断对子,最后判断无牌型的

  • 对顺子的处理问题

3.代码实现

package 搜狐面试2016;

import java.util.Arrays;
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        // 2,3,4,5,6,7,8,9,10,J,Q,K,A
        Scanner scanner = new Scanner(System.in);
        boolean isContinue=true;
        while (isContinue) {
            //1.游戏规则
            System.out.println("游戏规则:共52张普通牌,牌面为2,3,4,5,6,7,8,9,10,J,Q,K,A之一,大小递增,各四张; 每人抓三张牌。两人比较手中三张牌大小,大的人获胜。");
            System.out.println("对于牌型的规则如下:");
            System.out.println("1.三张牌一样即为豹子");
            System.out.println("2.三张牌相连为顺子(A23不算顺子)");
            System.out.println("3.有且仅有两张牌一样为对子 豹子>顺子>对子>普通牌型 在牌型一样时,比较牌型数值大小");
            System.out.println("谁输谁赢:1 --代表玩家1赢;0 --代表 平局   ;-1 --代表玩家2赢 ;-2 --代表不合法的输入");
             
            //2.分别出牌
            System.out.println("请玩家1出牌:");
            String num1 = scanner.next();
            System.out.println("请玩家2出牌:");
            String num2 = scanner.next();
            
            //3.判断是否合法
            boolean flag=isValid(num1, num2);
            if(!flag){
                //不合法
                System.out.println("-2");
            }else {
                //输入合法---先拆分字符串---再转化为int数组
                //4.拆分字符串
                String[] nums1=getStrArray(num1);
                String[] nums2=getStrArray(num2);
                System.out.println("拆分后的字符串数组A:"+Arrays.toString(nums1));
                System.out.println("拆分后的字符串数组B:"+Arrays.toString(nums2));
                
                //5.转化为int数组
                int[] nums11=strToNumber(nums1);
                int[] nums22=strToNumber(nums2);
                System.out.println("转化为int后的数组A:"+Arrays.toString(nums11));
                System.out.println("转化为int后的数组B:"+Arrays.toString(nums22));
                
                //6.获得三张牌的相等情况
                int[] equalNum11=equalNum(nums11);
                int[] equalNum22=equalNum(nums22);
                System.out.println("三张牌的相等情况--数组A:"+Arrays.toString(equalNum11));
                System.out.println("三张牌的相等情况--数组B:"+Arrays.toString(equalNum22));
                
                //7.判断输赢
                int whoWin=whoWin(equalNum11, nums11, equalNum22, nums22);
                System.out.println(""+whoWin);
                
            }
            
            //是否继续
            System.out.println("是否继续?输入N或n退出,其他任意键继续!");
            String string = scanner.next();
            string=string.toUpperCase();
            if("N".equals(string)){
                isContinue=false;
            }
        }

    }

    /*1.判断输入的内容是否合法
     *          不合法两种情况:(1)出现的字符不是2,3,4,5,6,7,8,9,10,J,Q,K,A
                                (2)每种牌只有4张,超过4张则不合法了
     *方法说明:
     *该方法只处理情况(1),情况(2)放在判断输赢的时候处理,因为第二种情况涉及牌面转化后计算的问题*/
    public static boolean isValid(String num1, String num2) {
        String reg = "([2-9JQKA]|10){3}";// 正则匹配,只能出现2,3,4,5,6,7,8,9,10,J,Q,K,A,并且一共只能出现3次
        boolean a = num1.matches(reg);
        boolean b = num2.matches(reg);

        // 有一方不合法就返回false
        if (a == false || b == false) {
            return false;
        } else {
            // 都合法
            return true;
        }
    }

    // 1.拆分字符串,得到三个数字
    public static String[] getStrArray(String num) {
        // 字符串的长度和拆分后的数组
        int length = num.length();
        String[] nums = new String[3];
        // 无论输入的J,Q,K,A是否为大写,都改为大写
        num.toUpperCase();

        // 字符串不含10时,长度都为3
        if (length == 3) {
            // nums=num.split("");//使用该方法拆分会多出一个空格位--比如33a-->[,3,3,1]
            for (int i = 0; i < nums.length; i++) {
                nums[i] = num.substring(i, i + 1);
            }
        } else if (length == 4) {
            // 字符串含一个10
            int index = num.indexOf("1");

            // 10在首位:10XX
            if (index == 0) {
                nums[0] = "10";
                nums[1] = num.substring(2, 3);
                nums[2] = num.substring(3);
            } else if (index == 1) {
                // 10在中位:X10X
                nums[0] = num.substring(0, 1);
                nums[1] = "10";
                nums[2] = num.substring(3);
            } else {
                // 10在末位:XX10
                nums[0] = num.substring(0, 1);
                nums[1] = num.substring(1, 2);
                nums[2] = "10";
            }
        } else if (length == 5) {
            // 字符串2个10----1010X 或 10X10 或 X1010
            int first = num.indexOf("1");// 第一个10
            int second = num.lastIndexOf("1");// 第二个10
            int cha = second - first;

            // 两个1距离大于2时,说明X在中间
            if (cha > 2) {
                nums[0] = nums[2] = "10";
                nums[1] = num.substring(2, 3);
            } else {
                // 两个1距离等于2时,说明两个10是挨在一起的
                if (first == 0) {
                    nums[0] = nums[1] = "10";
                    nums[2] = num.substring(4);
                } else {
                    nums[0] = num.substring(0, 1);
                    nums[1] = nums[2] = "10";
                }
            }

        } else {
            // 字符串为3个10
            for (int i = 0; i < nums.length; i++) {
                nums[i] = "10";
            }
        }

        return nums;
    }

    // 2.将字符串数组转为int数组
    public static int[] strToNumber(String[] nums) {
        int[] arr = new int[3];
        for (int i = 0; i < nums.length; i++) {
            arr[i] = letterToNumber(nums[i]);
        }
        Arrays.sort(arr);
        return arr;
    }

    /*
     * 3.比较拆分后的三个数字相等情况,并返回数组--[参数1,参数2] 
     * 
     * 参数1:数字相同的个数;
     * 参数2:若有相同数字,参数2表示相同的是哪个数字;-------此时参数2只可能为2-14中的一个 
     *      若没有相同数字--参数2表示是否有顺子--有顺子为1,没顺子为0----此时参数2只可能是0或1
     * 
     * 例如: 
     * 若有两个相同,则返回[2,相同的数字]; 
     * 若三个都相同,则返回[3,相同的数字];
     * 若三个数字都不同,且不是顺子,则返回[0,0];若是顺子则返回[0,1]
     */
    public static int[] equalNum(int[] nums) {
        int[] arr = new int[2];

        // 判断相等的个数
        if (nums[0] == nums[1] && nums[0] == nums[2]) {
            // 三个数相等
            arr[0] = 3;
            arr[1] = nums[0];
        } else if (nums[0] != nums[1] && nums[0] != nums[2] && nums[1] != nums[2]) {
            // 三个数均不相等--此时有一个顺子的问题要处理
            arr[0] = 0;

            // 因为A23不算顺子,所以只能出现2-14间的顺子,即234,345,...,121314
            // 此时相邻两个数差为1
            if (nums[1] - nums[0] == 1 && nums[2] - nums[1] == 1) {
                // 为顺子
                arr[1] = 1;
            } else {
                arr[1] = 0;
            }
        } else {
            // 两个数相等
            arr[0] = 2;
            
            // 若数组中两个数差值为0,说明就是这个数为对子
            if(nums[0]-nums[1]==0){
                arr[1]=nums[0];
            }else if (nums[0]-nums[2]==0) {
                arr[1]=nums[0];
            }else {
                arr[1]=nums[2];
            }
        }

        return arr;
    }

    /*
     * 4.判断谁输谁赢 参数说明:a,primaryA--玩家1 b,primaryB--玩家2
     * 
     * 参数a,b:判断数字相等情况后返回的数组----即方法isEqual()处理后的结果
     * 参数primaryA,primaryB:原始数组(备注:转化为int后的数组---即方法strToNumber()处理后的结果)
     * 
     * 
     * 备注:该方法太长,可以将豹子,顺子,对子,普通牌型分别提取为一个方法
     *     那么需要再创建一个方法用于判断玩家1和2的牌中出现是豹子,顺子,对子,普通牌型中的哪一种
     *     将返回值做为if的条件,再分别去调用对应的豹子,顺子,对子,普通牌型方法
     *     
     *     因为这样方法太多,笔者就不单独提出来封装了
     */
    public static int whoWin(int[] a, int[] primaryA, int[] b, int[] primaryB) {
        // 1)判断是否为豹子
        if (a[0] == 3 && b[0] == 3) {
            // 都是豹子则比大小
            if (a[1] > b[1]) {
                return 1;
            } else if (a[1] < b[1]) {
                return -1;
            } else {
                // 玩家1和2豹子相同是不可能的,每种牌只有4张
                return -2;
            }
        } else if (a[0] == 3 && b[0] != 3) {
            // 只有玩家1是豹子--处理可能出现5张相同牌的情况--需要判断玩家2是否有对子,有,那么是否与豹子是相同的牌

            // 玩家2有对子,并且与玩家1的豹子牌面相同
            if (b[0] == 2 && a[1] == b[1]) {
                return -2;
            }

            return 1;
        } else if (a[0] != 3 && b[0] == 3) {
            // 只有玩家2是豹子--同理上面

            // 玩家1有对子,并且与玩家2的豹子牌面相同
            if (a[0] == 2 && a[1] == b[1]) {
                return -2;
            }
            return -1;
        } else {
            // 2)都没豹子,判断是否为顺子--利用非顺子时a[1]和b[1]不可能出现1,只会为2-14
            if (a[1] == 1 && b[1] == 1) {
                // 都为顺子,则比大小--因为是顺子,所以比较第一个数值即可
                if (primaryA[0] > primaryB[0]) {
                    return 1;
                } else if (primaryA[0] < primaryB[0]) {
                    return -1;
                } else {
                    return 0;
                }
            } else if (a[1] == 1 && b[1] != 1) {
                // 只有玩家1是顺子
                return 1;
            } else if (a[1] != 1 && b[1] == 1) {
                // 只有玩家2是顺子
                return -1;
            } else {
                // 3)都不是顺子,判断是否有对子
                if (a[0] == 2 && b[0] == 2) {
                    // 都有对对子,则比大小
                    if (a[1] > b[1]) {
                        return 1;
                    } else if (a[1] < b[1]) {
                        return -1;
                    } else {
                        // 对子相同,则比较单个的那个数
                        int thirdA = 0;// 玩家1,单独的牌
                        int thirdB = 0;// 玩家2,单独的牌
                        for (int i = 0; i < primaryA.length; i++) {
                            if (primaryA[i] != a[1]) {
                                thirdA = primaryA[i];
                            }
                            if (primaryB[i] != b[1]) {
                                thirdB = primaryB[i];
                            }
                        }

                        // 比较单个数字
                        if (thirdA > thirdB) {
                            return 1;
                        } else if (thirdA < thirdB) {
                            return -1;
                        } else {
                            return 0;
                        }
                    }
                } else if (a[0] == 2 && b[0] != 2) {
                    // 只有玩家1有对子
                    return 1;
                } else if (a[0] != 2 && b[0] == 2) {
                    // 只有玩家2有对子
                    return -1;
                } else {
                    // 4)都没豹子,顺子,对子,直接比大小
                    if (primaryA[2] > primaryB[2]) {
                        return 1;
                    } else if (primaryA[2] < primaryB[2]) {
                        return -1;
                    } else {
                        // 最大值相等,比较第二大的
                        if (primaryA[1] > primaryB[1]) {
                            return 1;
                        } else if (primaryA[1] < primaryB[1]) {
                            return -1;
                        } else {
                            // 最大值和第二大值都相等
                            if (primaryA[0] > primaryB[0]) {
                                return 1;
                            } else if (primaryA[0] < primaryB[0]) {
                                return -1;
                            } else {
                                return 0;
                            }
                        }
                    }

                }
            }

        }

    }

    // 5.将字符转为数字----------将非数字的J,Q,K,A转换为数字11,12,13,14--并将本身数字的字符串转为int类型
    public static int letterToNumber(String letter) {
        if (letter.equals("J")) {
            return 11;
        } else if (letter.equals("Q")) {
            return 12;
        } else if (letter.equals("K")) {
            return 13;
        } else if (letter.equals("A")) {
            return 14;
        }

        return Integer.parseInt(letter);
    }
}

运行测试

长度不合法
这里写图片描述

单个牌6出现了5次,不合法
这里写图片描述

豹子
这里写图片描述

顺子和对子
这里写图片描述

都是字母,顺子和对子
这里写图片描述

出现10,两个顺子
这里写图片描述

都无牌型,直接比大小
这里写图片描述

Atas ialah kandungan terperinci 如何用代码实现扎金花游戏. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn