算法--2016搜狐面試:員工一塊兒玩扎金花

扎金花這種小遊戲,我想做爲一名程序員。大部分小時候都玩過吧!如今咱們一塊兒來看看搜狐這道面試題吧!看看如何用代碼實現扎金花。java


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輸入的字符串,判斷是否合法code

  • (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,兩個順子
這裏寫圖片描述

都無牌型,直接比大小
這裏寫圖片描述

相關文章
相關標籤/搜索