鬥地主Console顯示版
鬥地主:字串+正則的簡單實現
緣由:聽同學說學了集合後,就可以基本實現鬥地主功能,一開始聽到覺得不可能吧,後面就認真構想了一下,覺得如果加上正則匹配撲克牌出牌規則,實現鬥地主是可以的,只不過沒有圖形介面,只能在終端一個人玩,覺得寫出來了也挺有意思的,於是我就開始鬥地主的編寫(ps:寫了很久)。
自己測試很多次,沒有發現什麼bug。
如果有什麼邏輯沒考慮到,或者優化的地方希望評論告訴我,共同學習,共同進步(^_^)。
整體思路概述:
1:生成撲克牌,給玩家隨機發牌 1.1:利用撲克牌字串與索引一一對應關係,通過隨機給玩家發索引,然後根據玩家的索引獲取牌,來達到給玩家隨機發牌的效果。 2:輪流出牌 2.1利用迴圈實現玩家輪流出牌,對每個玩家的出牌進行校驗: a是否為撲克牌校驗, b是否是來自玩家自己手中的牌, c正則匹配是否符合出牌規則,記錄對應牌資料:牌的型別,和牌的大小 2.2下一個玩家出牌(玩家可選擇出牌或跳過),校驗成功後,對牌型別和大小比較,滿足出牌大小條件,則繼續下一個玩家。(注:玩家選擇跳過,跳過兩次表示其它玩家要不起,那麼則需要重置牌記錄的資料) 說明: 1:3帶1不能帶一對牌,下面的正則匹配時:一對牌當作2個單牌匹配 2:沒把連炸彈帶牌(333344445678)考慮進去 3:可以把正則匹配方法單獨提取出來測試牌
下面是程式碼:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class FightLandlord {
private static Scanner sc;
private static int skip = 0;// 記錄玩家跳過的次數
private static String name = "";// 玩家名字
public static void main(String[] args) {
playPoker();
}
// 修改:遍歷拼接時直接新增到Map集合中
public static void playPoker() {
ArrayList<String> p1 = new ArrayList<String>();// 玩家1集合
ArrayList<String> p2 = new ArrayList<String>();// 玩家2集合
ArrayList<String> p3 = new ArrayList<String>();// 玩家3集合
// -----------方法1: 根據字串索引給玩家發牌-----------
indexStringPoker(p1, p2, p3);
String beforeW = "beforeW";// 初始玩家先出牌字串
String afterW = "afterW";// 初始玩家:後出牌字串
System.out.println("出牌簡化:'0'代表 牌'10','小'='小☺',大='大☻',e代表跳過,忽略了大小寫.(注:輸入其它非撲克牌字元也是預設跳過:1,你...)");
while (true) {
// -----------方法2: 迴圈判斷玩家出牌是否合理-----------
name = "地主 p1_";// 玩家名提示
beforeW = loopSyso(p1, beforeW, afterW, name);// 4
name = "農民 p2_";
beforeW = loopSyso(p2, beforeW, afterW, name);
name = "農民 p3_";
beforeW = loopSyso(p3, beforeW, afterW, name);
}
}
// -------------------------------方法1-1:根據字串索引給玩家發牌-------------------------------
public static void indexStringPoker(ArrayList<String> p1, ArrayList<String> p2, ArrayList<String> p3) {
// 為了方便排序,臨時替換: a替換0 b=j c=q d=k e=A f=2 小=g 大=h;
String cards = "3♣3♠3♥3♦4♣4♠4♥4♦5♣5♠5♥5♦6♣6♠6♥6♦7♣7♠7♥7♦8♣8♠8♥8♦9♣9♠9♥9♦a♣a♠a♥a♦b♣b♠b♥b♦c♣c♠c♥c♦d♣d♠d♥d♦e♣e♠e♥e♦f♣f♠f♥f♦g☺h☻";
ArrayList<Integer> key = new ArrayList<Integer>();// key集合=對應牌索引
for (int i = 0; i < 54; i++) {// 給集合新增內容:(0-53)
key.add(i);
}
Collections.shuffle(key);// 打亂鍵(索引)=打亂牌
// 給玩家新增牌
for (int i = 0; i < 54; i++) {
int index = key.get(i);
if (i < 20)
p1.add(cards.substring(2 * index, 2 * (index + 1)));
if (20 <= i && i < 37)
p2.add(cards.substring(2 * index, 2 * (index + 1)));
if (i >= 37)
p3.add(cards.substring(2 * index, 2 * (index + 1)));
}
// -----------方法1-1-1: 替換回來-->a替換0 b=j c=q d=k e=A f=2-----------
replaceSort(p1);
replaceSort(p2);
replaceSort(p3);
System.out.println("p1: " + p1 + p1.size());
System.out.println("p2: " + p2 + p2.size());
System.out.println("p3: " + p3 + p3.size());
}
// ----------------------方法1-1-1:建字串替換回來,並轉換為陣列----------------------
public static void replaceSort(ArrayList<String> p) {
Collections.sort(p);// 對玩家牌排序
String ps = p.toString();// 轉換為字串
ps = ps.replaceAll("a", "0");
ps = ps.replaceAll("b", "J");
ps = ps.replaceAll("c", "Q");
ps = ps.replaceAll("d", "K");
ps = ps.replaceAll("e", "A");
ps = ps.replaceAll("f", "2");
// 必須完全排序,否則j索引跳過順序混亂的牌.---->大小-->遍歷時,j直接累加到了"大",最後的索引.當再依次遍歷到小的時候.在大之後索引查詢,找不到了
ps = ps.replaceAll("g", "小");
ps = ps.replaceAll("h", "大");
ps = ps.replaceAll("[\\[\\]]", "");// 去除前後大括號
String[] split = ps.split(",");// 轉化為陣列
for (int i = 0; i < split.length; i++) {
p.set(i, split[i]);
}
}
// ------------------------方法2:迴圈出牌-------------------------------
public static String loopSyso(ArrayList<String> p, String beforeW, String afterW, String name) {
sc = new Scanner(System.in);
// 接收玩家牌,判斷
w: while (true) {
System.out.print(name + p + "\n\t\t" + name + "出牌:");
afterW = sc.next();// 接收玩家的出牌
// -----------方法2-1: 對玩家輸入的牌進行排序-----------
afterW = diySortString(afterW);
if (afterW.contains("E")) {
skip++;
if (skip == 3) {
System.out.println("跳過一輪");
skip = 0;
}
System.out.print("_______________________________" + name + "跳過:" + skip + "次______________________\n");
return beforeW;// 返回上家的牌
}
// 遍歷玩家輸入的字串,記錄對應牌索引()
int[] pcopyI = new int[afterW.length()];// 預設為0
int j = -1;// 記錄上次遍歷到的索引位置
f: for (int i = 0; i < afterW.length(); i++) {// 遍歷玩家字串
String s1 = afterW.substring(i, i + 1);// 拿到玩家字串的每個字元
// 不回頭遍歷:必須有序
for (j++; j < p.size(); j++) {// 遍歷玩家p牌對應的字元陣列
String s = p.get(j);
if (s.contains(s1)) {// 對比是否有相同的牌: "3♣"包含3,匹配成功
pcopyI[i] = j;// 記錄牌中被替換對應的索引
continue f;// 跳轉到外迴圈,匹配下一個字元
}
}
System.out.println("你輸入的牌有不存在的,請重新輸入");
continue w;// 有不匹配字元,則跳轉到開始:提示玩家重新輸入
}
// ----------方法2-2:校驗比較牌大小------
int[] w1 = regexMatches(beforeW);// 獲取玩家"牌資料"(出牌型別,及對應出牌大小)
// 都跳過,玩家可自定義出牌---位置必須放在w1=後用於重置array"牌資料"
if (skip == 2) {// 跳過2次,說明其它玩家都不要,那麼"牌資料"還原為初始值
w1[0] = -1;
w1[1] = 0;
}
// 當前玩家出牌
int[] w1c = regexMatches(afterW);
if (w1c[0] == -2) {// 牌不符合規則的終止條件:終止
continue;// -->玩家重新輸入
}
System.out.println("前型別=" + w1[1] + ",後型別=" + w1c[1] + ", 前:=" + w1[0] + ",後=" + w1c[0]);
// 比較型別
if (w1[1] == w1c[1] | w1c[1] == 10000 | w1[1] == 0) {
if (w1[0] >= w1c[0]) {// 比較牌大小
w1c[0] = w1[0];// 還原上家牌索引
w1c[1] = w1[1];// 還原上家牌型別
System.out.println("要不起,請重新選擇牌");
continue;
}
} else {// 型別不滿足
w1c[1] = w1[1];
w1c[0] = w1[0];
System.out.println("型別不匹配,請重新出牌");
continue;
}
// 當玩家不是連續輸入重置跳過次數=位置需在skip==2後//中間玩家輸錯,不至於更改
if (!afterW.contains("E")) {
skip = 0;
}
// 顯示出牌
System.out.print("________________________________" + name + afterW + "________________________\n");
// 移除牌
for (int i = 0; i < pcopyI.length; i++) {
p.set(pcopyI[i], "");
}
break w;// 出牌成功跳出迴圈
}
// ---------------------------------判斷玩家是否出完牌--------------------------
for (int i = 0; i < p.size(); i++) {
if (!p.get(i).equals("")) {
break;
}
if (i == (p.size() - 1)) {
System.out.println("________________________________" + name + " 先出完牌,game over");
System.exit(3000);
// return "over";//返回該上一層,判斷是否退出
}
}
beforeW = afterW;// 記憶體地址
return beforeW;// 預設值
}
// -----------方法2-1:對使用者輸入的字串進行排序-----------
public static String diySortString(String str) {
str = str.toUpperCase();// 忽略大小寫
String sortS = "34567890JQKA2小☺大☻";// 指定排序規則字串
if (!str.matches("[" + sortS + "]+")) {// 匹配是否非撲克牌字元,是跳過
return "E";
}
ArrayList<Integer> strA = new ArrayList<Integer>();
for (int i = 0; i < str.length(); i++) {
strA.add(sortS.indexOf(str.charAt(i)));// 匹配待排序字串中的每個字元,對應在規則字串中的索引,並新增
}
Collections.sort(strA);// 將字元的索引從小到大排序
String sortWp = "";
for (int i = 0; i < strA.size(); i++) {
sortWp = sortWp + sortS.charAt(strA.get(i));// 通過索引獲取對應字元
}
return sortWp;
}
// ------------------------方法2-2: 正則表示式-------------------
public static int[] regexMatches(String wp) {
int[] array = { -1, 0 };// 初始"牌資料"
String sCards = "34567890JQKA2小大";// 單牌=規則大小牌
String linkCards1 = "34567890JQKA";// 單連牌
String linkCards2 = "3344556677889900JJQQKKAA";// 對連牌
String linkCards3 = "333444555666777888999000JJJQQQKKKAAA";// 3連牌
String linkCards4 = "33334444555566667777888899990000JJJJQQQQKKKKAAAA";// 4連牌
// 匹配出牌屬於哪一型別
int index = -1;
if (wp.length() == 1) {
index = sCards.indexOf(wp);
array[0] = index;
array[1] = 1;
return array;// 單牌
} else if (linkCards1.contains(wp) && wp.length() > 4) {
index = linkCards1.indexOf(wp);
array[0] = index;
array[1] = 11;
return array;// 單連牌
} else if (wp.matches("(.)\\1")) {
index = sCards.indexOf(wp.charAt(0));
array[0] = index;
array[1] = 2;
return array;// 對牌
} else if (linkCards2.contains(wp) && wp.length() > 5 && linkCards2.indexOf(wp) % 2 == 0) {
index = linkCards2.indexOf(wp);
array[0] = index;
array[1] = 21;
return array;// 對連牌
} else if (wp.matches("(.)\\1\\1")) {
index = linkCards3.indexOf(wp);
array[0] = index;
array[1] = 3;
return array;// 三牌
} else if (!wp.matches("(.)\\1{3}") && (wp.matches(".(.)\\1\\1")) | wp.matches("(.)\\1\\1.")) {// 防止誤匹配4個相同的
index = sCards.indexOf(wp.charAt(2));// 獲取中間字元值,對應規則字串中的索引,作為比較
array[0] = index;
array[1] = 31;
return array;// 三帶一
} else if (linkCards3.contains(wp) && linkCards3.indexOf(wp) % 3 == 0 && wp.length() > 5) {
index = linkCards3.indexOf(wp);
array[0] = index;
array[1] = 33;
return array;// 三連牌
} else if (wp.length() > 7 && linkCards3.contains(wp.replaceAll("[" + wp.replaceAll("(.)\\1\\1", "") + "]", ""))
&& wp.replaceAll("[" + wp.replaceAll("(.)\\1\\1", "") + "]", "").length() / 3 == wp
.replaceAll("(.)\\1\\1", "").length()) {
// 長度8 12 // 滿足連續關係// 三帶1模式:匹配3個相同的數量/3等於額外數 ==4的倍數
index = linkCards3.indexOf(wp.replaceAll("[" + wp.replaceAll("(.)\\1\\1", "") + "]", ""));
array[0] = index;
array[1] = 3311;
return array;// 飛機
} else if (linkCards4.contains(wp) && linkCards3.indexOf(wp) % 4 == 0) {
array[0] = linkCards4.indexOf(wp);
array[1] = 44;
return array;// 四連牌
} else if (wp.matches("(.)\\1{3}.{2}") | wp.matches("..(.)\\1{3}")) {
index = sCards.indexOf(wp.charAt(2));// 44|5555|66
array[0] = index;
array[1] = 42;
return array;// 四帶二
} else if (wp.matches("(.)\\1{3}") | wp.equals("小大")) {
index = sCards.indexOf(wp.charAt(0));
array[0] = index;
array[1] = 10000;
return array;// 炸彈
} else {
if (wp.matches("beforeW")) {// 初始值,則返回預設型別
return array;
} else {
System.out.println("你輸入的牌不符合規則");
array[0] = -2;// 用於終止繼續執行條件
return array;
}
}
}
}
相關推薦
鬥地主Console顯示版
鬥地主:字串+正則的簡單實現 緣由:聽同學說學了集合後,就可以基本實現鬥地主功能,一開始聽到覺得不可能吧,後面就認真構想了一下,覺得如果加上正則匹配撲克牌出牌規則,實現鬥地主是可以的,只不過沒有圖形介面,只能在終端一個人玩,覺得寫出來了也挺有意思的,於是我
自己寫的一部分鬥地主的程序,沒有去寫界面,臨時是用黑框來顯示的
cas getc vector dea 發牌 常見 dma red5 向量 這幾天比較空,所以想寫一點東西。 鬥地主的程序一直以來都想寫,但感覺規則推斷比較復雜,一直沒有較多的時間來寫。 這次主要是把跟牌和牌型的推斷寫出來了。寫了一個比較弱智的AI,屬於有牌就出
vijos p1980鬥地主/luogu p2540鬥地主增強版
mmm 題解 num pro 思考 是我 name sea max https://vijos.org/p/1980 https://www.luogu.org/problemnew/show/2540 這兩題的數據比原版鬥地主數據要毒瘤多了......特別是vj的一百個點
luogu2540 鬥地主增強版
個數 影響 space xunit 鬥地主 cpp d+ define \n 題目大意 給你一副手牌,沒有飛機帶翅膀,按鬥地主的規則,求將所有牌打出的最少次數。 題解 先不考慮順子 我們已經知道花色對牌沒有影響,那麽如果不考慮順子,每個牌具體是什麽數字我們也用不著知
Java課程設計---web版鬥地主
好的 type 回調函數 重定向 定義 redirect 響應 jsp頁面 情況 一. 團隊課程設計博客鏈接 二.個人負責模塊和任務說明 負責前後端數據傳輸 JSP界面的設計 根據後臺傳來的數據進行頁面動態更新 負責Servlet設計 三.自己的代碼
命令列版的鬥地主你玩過沒?
本文適合有 Java 基礎知識的人群,跟著本文可使用和快速搭建命令列鬥地主專案。 本文作者:HelloGitHub-秦人 HelloGitHub 推出的《講解開源專案》系列,今天給大家帶來一款命令列鬥地主開源專案—— ratel 專案原始碼地址:https://github.com/ainilili
P2668 鬥地主
其中 tool -- 正整數 現在 ring left hang == P2668 鬥地主 題目描述 牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、方片的A到K加上大小王的共54張牌來進行的撲克牌遊戲。在鬥地主中
Libgdx: android單機鬥地主支持局域網wifi聯網的網絡模塊核心代碼
ring 本機ip count() trace name out 初始化 current err 這個作品是我近期寫的,結合我的畢業設計的通信模塊和之前的單機版鬥地主。我已經上架到豌豆莢了,貼了點廣告,看看能不能賺點茶錢。但是一點也不樂觀。因此我想分享給大家源代碼。
簡單鬥地主
簡單鬥地主/* * 一副撲克 * 洗牌 * 發牌 *看牌 */ public static void fightLandlord(){ //一副撲克 String[] num={"3","4","5","6","7","8","9","10","J","Q","K","
[NOIP 2016TG D1T3] 鬥地主
color 輸入 pri turn https 測試 撲克牌 .org del 題目描述 牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、方片的A到K加上大小王的共54張牌來進行的撲克牌遊戲。在鬥地主中,牌的大小關系根據牌的數碼表示如下:3<4
luoguP2668 鬥地主 x
com www blank app http 大王 剪枝 mat clu P2668 鬥地主 題目描述 牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、方片的A到K加上大小王的共54張牌來進行的撲克牌遊戲。在鬥地主中,牌的大小關系根據牌的數碼表示
妞一個鬥地主發牌程序!!!
循環 步驟 pan pre length 知識 基本 復制 code 學習java三個星期,利用所學的知識做了一個三人鬥地主發牌程序,閑話少敘,上代碼 1 import java.util.ArrayList; 2 import java.util.Colle
【NOIP2015】鬥地主
eof 2個 ios sca desc input inpu 數據 撲克 P2431 - 【NOIP2015】鬥地主 Description 牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種 使用黑桃、紅心、梅花、方片的A到K加上大小王的共54張牌來進行的撲克牌
棋牌平臺架設教程之鬥地主核心算法
棋牌 源碼 首先,要弄清楚鬥地主的牌型有哪些。可以參考QQ遊戲給出的介紹,如下: 火箭:即雙王(大王和小王),最大的牌。 炸彈:四張同數值牌(如四個 7 )。 單牌:單個牌(如紅桃 5 )。 對牌:數值相同的兩張牌(如梅花 4+ 方塊 4 )。
棋牌平臺開發教程之鬥地主常用算法
源碼 最大的 http 大王 等待時間 細節 第一個 參考 更多 首先,要弄清楚鬥地主的牌型有哪些。可以參考QQ遊戲給出的介紹,如下: 火箭:即雙王(大王和小王),最大的牌。 炸彈:四張同數值牌(如四個 7 )。 單牌:單個
洛谷 P2668 鬥地主
中間 std == i++ 問題 輸出 ace 撲克牌 大小 題目描述 牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、方片的A到K加上大小王的共54張牌來進行的撲克牌遊戲。在鬥地主中,牌的大小關系根據牌的數碼表示如下:3<4<5<
NOIP2015 鬥地主
str 數據 tin 思路 == 1+n logs b- n) 題目描述牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、方片的A 到K 加上大小王的共54 張牌來進行的撲克牌遊戲。在鬥地主中,牌的大小關系根據牌的數碼表示如下:3<4<5&
[BZOJ 4325][NOIP 2015] 鬥地主
output ref input blank can 自己 show 我們 大模擬 一道防AK好題 4325: NOIP2015 鬥地主 Time Limit: 30 Sec Memory Limit: 1024 MBSubmit: 820 Solved: 56
集合應用-鬥地主
發的 ngx dex shu args == tree 獲取 demo /* * 思路: * A:創建一個HashMap集合(編號和對應的牌) * B:創建一個ArrayList集合(編號) * C:創建花色數組和點數數組 * D:從0開始往HashMa
鬥地主2
pre spa Coding 開始 clu mys ont utf move #coding=utf8import random,sys,time# def randDZ():# DZ=random.randint(1,3)# if DZ==1:#