《斗地主游戏》第3节:项目完整代码
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《斗地主游戏》第3节:项目完整代码相关的知识,希望对你有一定的参考价值。
对于初学者来说,斗地主游戏是一个比较复杂的项目,它涉及的类很多,以下是这个项目所有类的源代码,源码中有两个Main.java文件,它们虽然文件名称相同,但位于不同的包下,读者在复制粘贴这两个文件时需要注意要把它们放在正确的位置。
Message.java
package client.model;
import java.io.*;
import java.util.*;
public class Message implements Serializable
private int typeid; //消息类型
private int playerid; //玩家id
private String content; //消息内容
private List<Poker> pokers = new ArrayList<Poker>(); //扑克列表
public int getTypeid()
return typeid;
public void setTypeid(int typeid)
this.typeid = typeid;
public int getPlayerid()
return playerid;
public void setPlayerid(int playerid)
this.playerid = playerid;
public String getContent()
return content;
public void setContent(String content)
this.content = content;
public List<Poker> getPokers()
return pokers;
public void setPokers(List<Poker> pokers)
this.pokers = pokers;
public Message()
public Message(int typeid, int playerid, String content, List<Poker> pokers)
this.typeid = typeid;
this.playerid = playerid;
this.content = content;
this.pokers = pokers;
Player.java
package client.model;
import java.io.*;
import java.net.*;
import java.util.*;
//玩家类
public class Player implements Serializable
private int id; //玩家id
private String name; //玩家姓名
private Socket socket; //玩家对应的socket
private List<Poker> pokers=new ArrayList<Poker>();//玩家的扑克列表
public int getId()
return id;
public void setId(int id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Socket getSocket()
return socket;
public void setSocket(Socket socket)
this.socket = socket;
public List<Poker> getPokers()
return pokers;
public void setPokers(List<Poker> pokers)
this.pokers = pokers;
public Player()
public Player(int id,String name,Socket socket,List<Poker> pokers)
this.id=id;
this.name=name;
this.socket=socket;
this.pokers=pokers;
public Player(int id)
this.id=id;
public Player(int id,String name)
this.id=id;
this.name=name;
public Player(int id,String name,List<Poker> pokers)
this.id=id;
this.name=name;
this.pokers=pokers;
public String toString()
return "player[id:"+this.id+"name:"+this.name+"]";
Poker.java
package client.model;
import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;
//扑克类
public class Poker
private int id; //扑克id
private String name;//扑克名称
private int num; //扑克数量
private boolean isOut; //扑克是否打出
public boolean isOut()
return isOut;
public void setOut(boolean isOut)
this.isOut = isOut;
public int getId()
return id;
public void setId(int id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
public int getNum()
return num;
public void setNum(int num)
this.num = num;
public Poker()
public Poker(int id,String name,int num)
this.id=id;
this.name=name;
this.num=num;
public Poker(int id,String name,int num,boolean isOut)
this.id=id;
this.name=name;
this.num=num;
this.isOut=isOut;
PokerLabel.java
package client.model;
import javax.swing.*;
//扑克标签类
public class PokerLabel extends JLabel implements Comparable
private int id;
private String name;
private int num;
private boolean isOut;
private boolean isUp;
private boolean isSelected; //是否选中
public boolean isSelected()
return isSelected;
public void setSelected(boolean isSelected)
this.isSelected = isSelected;
public int getId()
return id;
public void setId(int id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
public int getNum()
return num;
public void setNum(int num)
this.num = num;
public boolean isOut()
return isOut;
public void setOut(boolean isOut)
this.isOut = isOut;
public boolean isUp()
return isUp;
public void setUp(boolean isUp)
this.isUp = isUp;
public PokerLabel()
this.setSize(105, 150);
public PokerLabel(int id,String name,int num)
this.id=id;
this.name=name;
this.num=num;
this.setSize(105, 150);
public PokerLabel(int id,String name,int num,boolean isOut,boolean isUp)
this.id=id;
this.name=name;
this.num=num;
this.isOut=isOut;
this.isUp=isUp;
if(isUp)
turnUp();
else
turnDown();
this.setSize(105, 150);
public void turnUp()
this.setIcon(new ImageIcon("images/poker/"+id+".jpg"));
public void turnDown()
this.setIcon(new ImageIcon("images/poker/down.jpg"));
@Override
public int compareTo(Object arg0)
PokerLabel pokerLabel=(PokerLabel)arg0;
if(this.num>pokerLabel.num)
return 1;
else if(this.num<pokerLabel.num)
return -1;
else
return 0;
ChuPaiThread.java
package client.thread;
import java.util.*;
import com.alibaba.fastjson.JSON;
import client.model.*;
import client.view.*;
public class ChuPaiThread extends Thread
private int time;
private MainFrame mainFrame;
private boolean isRun;
public int getTime()
return time;
public void setTime(int time)
this.time = time;
public MainFrame getMainFrame()
return mainFrame;
public void setMainFrame(MainFrame mainFrame)
this.mainFrame = mainFrame;
public boolean isRun()
return isRun;
public void setRun(boolean isRun)
this.isRun = isRun;
public ChuPaiThread(int time, MainFrame mainFrame)
isRun = true;
this.time = time;
this.mainFrame = mainFrame;
public void run()
while (time >= 0 && isRun)
mainFrame.timeLabel.setText(time + "");
time--;
try
Thread.sleep(1000);
catch (InterruptedException e)
// TODO Auto-generated catch block
e.printStackTrace();
Message message = null;
//如果是不出 (一种是时间到了 一种是 选择不出)
if (time == -1 || isRun == false && mainFrame.isOut == false)
//时间到了不出,则将出牌按钮隐藏
mainFrame.chupaiJLabel.setVisible(false);
mainFrame.buchuJLabel.setVisible(false);
mainFrame.timeLabel.setVisible(false);
message = new Message(3, mainFrame.currentPlayer.getId(), "不出", null);
//转换为json 交给 sendThread发送到服务器去
String msg = JSON.toJSONString(message);
mainFrame.sendThread.setMsg(msg);
//出牌
if (isRun == false && mainFrame.isOut == true)
message = new Message(4, mainFrame.currentPlayer.getId(), "出牌",
changePokerLableToPoker(mainFrame.selectedPokerLabels));
//转换为json 交给 sendThread发送到服务器去
String msg = JSON.toJSONString(message);
mainFrame.sendThread.setMsg(msg);
//将当前发送出去的扑克牌 从扑克牌列表中移除
mainFrame.removeOutPokerFromPokerList();
//如果扑克列表的数量为0 代表赢了
if (mainFrame.pokerLabels.size() == 0)
//产生游戏结束的消息
message = new Message(5, mainFrame.currentPlayer.getId(),
"游戏结束", null);
msg = JSON.toJSONString(message);
try
Thread.sleep(100);
//发送消息
mainFrame.sendThread.setMsg(msg);
catch (InterruptedException e)
e.printStackTrace();
public List<Poker> changePokerLableToPoker(List<PokerLabel> selectedPokerLabels)
List<Poker> list = new ArrayList<Poker>();
for (int i = 0; i < selectedPokerLabels.size(); i++)
PokerLabel pokerLabel = selectedPokerLabels.get(i);
Poker poker = new Poker(pokerLabel.getId(), pokerLabel.getName(),
pokerLabel.getNum());
list.add(poker);
return list;
CountThread.java
package client.thread;
import com.alibaba.fastjson.JSON;
import client.model.*;
import client.view.*;
//计时器的线程
public class CountThread extends Thread
private int i;
private MainFrame mainFrame;
private boolean isRun;
public boolean isRun()
return isRun;
public void setRun(boolean isRun)
this.isRun = isRun;
public CountThread(int i,MainFrame mainFrame)
isRun=true;
this.i=i;
this.mainFrame=mainFrame;
public void run()
while(i>=0 && isRun)
mainFrame.timeLabel.setText(i+"");
i--;
try
Thread.sleep(1000);
catch (InterruptedException e)
e.printStackTrace();
Message msg=null;
//时间到了 或者 点击过不抢地主的按钮了
if(i==-1 || isRun==false && mainFrame.isLord==false)
msg=new Message(1,mainFrame.currentPlayer.getId(),
"不抢",null);
//点了抢地主的按钮了
if(isRun==false && mainFrame.isLord==true)
msg=new Message(2,mainFrame.currentPlayer.getId(),
"抢地主",null);
//将消息传到服务器端
mainFrame.sendThread.setMsg(JSON.toJSONString(msg));
ReceiveThread.java
package client.thread;
import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.*;
import com.alibaba.fastjson.*;
import client.model.*;
import client.view.*;
//创建一个接收消息的线程
public class ReceiveThread extends Thread
private Socket socket;
private MainFrame mainFrame;
private int step = 0;
private boolean isRun = true;
public boolean isRun()
return isRun;
public void setRun(boolean isRun)
this.isRun = isRun;
public ReceiveThread(Socket socket, MainFrame mainFrame)
this.socket = socket;
this.mainFrame = mainFrame;
public void run()
try
DataInputStream dataInputStream =
new DataInputStream(socket.getInputStream());
while (true)
if (isRun == false)
break;
//接收从服务器端传递过来的消息 json字符串
String jsonString = dataInputStream.readUTF();
if (step == 0)
java.util.List<Player> players = new ArrayList<Player>();
//System.out.println(jsonString);
//解析json字符串 "[,]" [,]
//将json字符串转换为json数组
JSONArray playerJsonArray = JSONArray.parseArray(jsonString);
for (int i = 0; i < playerJsonArray.size(); i++)
//获得当个json对象--> 玩家对象
JSONObject playerJson = (JSONObject) playerJsonArray.get(i);
int id = playerJson.getInteger("id");
String name = playerJson.getString("name");
//存放扑克列表
java.util.List<Poker> pokers = new ArrayList<Poker>();
JSONArray pokerJsonArray =
playerJson.getJSONArray("pokers");
for (int j = 0; j < pokerJsonArray.size(); j++)
// 每循环一次 获得一个扑克对象
JSONObject pokerJSon = (JSONObject) pokerJsonArray.get(j);
int pid = pokerJSon.getInteger("id");
String pname = pokerJSon.getString("name");
int num = pokerJSon.getInteger("num");
Poker poker = new Poker(pid, pname, num);
pokers.add(poker);
Player player = new Player(id, name, pokers);
players.add(player);
//获得3个玩家的信息了
if (players.size() == 3)
mainFrame.showAllPlayersInfo(players);
step = 1; //玩家到齐 进展到第二步
else if (step == 1)
//接收抢地主的消息或者出牌的消息
JSONObject msgJsonObject = JSONObject.parseObject(jsonString);
//解析消息对象
int typeid = msgJsonObject.getInteger("typeid");
int playerid = msgJsonObject.getInteger("playerid");
String contentString = msgJsonObject.getString("content");
//消息类型为不抢
if (typeid == 1)
//1.主窗口显示不抢的信息
mainFrame.showMsg(playerid, 1);
//2.设置下一家开始抢地主
if (playerid + 1 == mainFrame.currentPlayer.getId())
mainFrame.getLord();
//抢地主的消息
if (typeid == 2)
//获得地主牌
JSONArray pokersJsonArray =
msgJsonObject.getJSONArray("pokers");
java.util.List<Poker> lordPokers = new ArrayList<Poker>();
for (int i = 0; i < pokersJsonArray.size(); i++)
JSONObject pokerJsonObject = (JSONObject) pokersJsonArray.get(i);
int id = pokerJsonObject.getInteger("id");
String name = pokerJsonObject.getString("name");
int num = pokerJsonObject.getInteger("num");
Poker p = new Poker(id, name, num);
System.out.println(p);
lordPokers.add(p);
//如果是自己抢的地主
if (mainFrame.currentPlayer.getId() == playerid)
//添加地主牌
mainFrame.addLordPokers(lordPokers);
//第一家出牌 显示出牌的按钮
mainFrame.showChuPaiJabel();
//显示地主图标
mainFrame.showLordIcon(playerid);
//之前的消息框隐藏
mainFrame.msgLabel.setVisible(false);
//所有玩家 都可以选择出牌列表 (不代表能出牌)
mainFrame.addClickEventToPoker();
if (typeid == 3) //不出牌
//显示不出牌的消息
mainFrame.showMsg(playerid, 3);
//判断自己是不是下一家 如果是 显示出牌按钮 0->1 1-> 2 2-> 0
if (playerid + 1 == mainFrame.currentPlayer.getId() ||
playerid - 2 == mainFrame.currentPlayer.getId())
mainFrame.showChuPaiJabel();
if (typeid == 4) //出牌
//获得出牌列表
JSONArray pokersJsonArray =
msgJsonObject.getJSONArray("pokers");
java.util.List<Poker> outPokers = new ArrayList<Poker>();
for (int i = 0; i < pokersJsonArray.size(); i++)
JSONObject pokerJsonObject = (JSONObject) pokersJsonArray.get(i);
int id = pokerJsonObject.getInteger("id");
String name = pokerJsonObject.getString("name");
int num = pokerJsonObject.getInteger("num");
Poker p = new Poker(id, name, num);
System.out.println(p);
outPokers.add(p);
//显示出牌列表
mainFrame.showOutPokerList(playerid, outPokers);
//判断自己是不是下一家 如果是 显示出牌按钮 0->1 1-> 2 2-> 0
if (playerid + 1 == mainFrame.currentPlayer.getId() ||
playerid - 2 == mainFrame.currentPlayer.getId())
mainFrame.showChuPaiJabel();
mainFrame.prevPlayerid = playerid; //记录上一个出牌的玩家id
//如果是游戏结束的消息
if (typeid == 5)
if (playerid == mainFrame.currentPlayer.getId())
JOptionPane.showMessageDialog(mainFrame, "赢了");
else
JOptionPane.showMessageDialog(mainFrame, "输了");
//游戏结束 关闭线程 清理窗口等
mainFrame.gameOver();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
SendThread.java
package client.thread;
import java.io.*;
import java.net.Socket;
//发送消息的线程
public class SendThread extends Thread
private String msg;
public String getMsg()
return msg;
public void setMsg(String msg)
this.msg = msg;
private Socket socket;
public Socket getSocket()
return socket;
public void setSocket(Socket socket)
this.socket = socket;
private boolean isRun = true;
public boolean isRun()
return isRun;
public void setRun(boolean isRun)
this.isRun = isRun;
public SendThread(Socket socket)
this.socket = socket;
public SendThread(Socket socket, String msg)
this.socket = socket;
this.msg = msg;
public SendThread()
public void run()
DataOutputStream dataOutputStream;
try
dataOutputStream = new DataOutputStream(socket.getOutputStream());
while (true)
if (isRun == false)
break;
//如果消息不为null
if (msg != null)
System.out.println("消息在发送中:" + msg);
//发送消息
dataOutputStream.writeUTF(msg);
//消息发送完毕 消息内容清空
msg = null;
Thread.sleep(50); //暂停 等待新消息进来
catch (IOException e)
e.printStackTrace();
catch (InterruptedException e)
e.printStackTrace();
GameUtil.java
package client.util;
import client.model.*;
public class GameUtil
public static void move(PokerLabel pokerLabel,int x,int y)
pokerLabel.setLocation(x, y);
try
Thread.sleep(50);
catch (InterruptedException e)
e.printStackTrace();
public static void move2(PokerLabel pokerLabel,int x,int y)
pokerLabel.setLocation(x, y);
PokerRule.java
package client.util;
import java.util.*;
import client.model.*;
public class PokerRule
//判断牌型
public static PokerType checkPokerType(List<PokerLabel> list)
Collections.sort(list);
int count = list.size();
if (count == 1)
//单张
return PokerType.p_1;
else if (count == 2)
//对子
if (isSame(list, count))
return PokerType.p_2;
//王炸
if (isWangZha(list))
return PokerType.p_2w;
return PokerType.p_error;
else if (count == 3)
//三个头
if (isSame(list, count))
return PokerType.p_3;
return PokerType.p_error;
else if (count == 4)
//炸弹
if (isSame(list, count))
return PokerType.p_4;
//三带一
if (isSanDaiYi(list))
return PokerType.p_31;
return PokerType.p_error;
else if (count >= 5)
//顺子
if (isShunZi(list))
return PokerType.p_n;
else if (isSanDaiYiDui(list))
//三代一对
return PokerType.p_32;
else if (isLianDui(list))
//连对
return PokerType.p_1122;
else if (isFeiJI(list))
//双飞or双飞双带
return PokerType.p_111222;
else if (isFeiJIDaiChiBang1(list))
//双飞or双飞双带
return PokerType.p_11122234;
else if (isFeiJIDaiChiBang2(list))
//双飞or双飞双带
return PokerType.p_1112223344;
return PokerType.p_error;
public static boolean isWangZha(List<PokerLabel> list)
if ((list.get(0).getNum() == 16 && list.get(1).getNum() == 17) ||
(list.get(0).getNum() == 17 && list.get(1).getNum() == 16))
return true;
return false;
//判断list内扑克是否相同
public static boolean isSame(List<PokerLabel> list, int count)
for (int j = 0; j < count - 1; j++)
int a = list.get(j).getNum();
int b = list.get(j + 1).getNum();
if (a != b)
return false;
return true;
//判断是否是三带一
public static boolean isSanDaiYi(List<PokerLabel> list)
List<PokerLabel> temp = new ArrayList<PokerLabel>();
temp.addAll(list);
if (isSame(temp, 3))
return true;
temp.remove(0);
if (isSame(temp, 3))
return true;
return false;
//判断是否是三带一对
public static boolean isSanDaiYiDui(List<PokerLabel> list)
List<PokerLabel> temp = new ArrayList<PokerLabel>();
temp.addAll(list);
if (temp.size() == 5)
if (isSame(temp, 3))
temp.remove(0);
temp.remove(0);
temp.remove(0);
if (isSame(temp, 2))
return true;
return false;
if (isSame(temp, 2))
temp.remove(0);
temp.remove(0);
if (isSame(temp, 3))
return true;
return false;
return false;
// 判断是否是顺子
public static boolean isShunZi(List<PokerLabel> list)
for (int i = 0; i < list.size() - 1; i++)
int a = list.get(i).getNum();
int b = list.get(i + 1).getNum();
if (b - a != 1)
return false;
return true;
// 判断是否是连对
public static boolean isLianDui(List<PokerLabel> list)
int size = list.size();
if (size < 6 && size % 2 != 0)
return false;
for (int i = 0; i < size; i++)
int a = list.get(i).getNum();
int b = list.get(i + 1).getNum();
if (a != b)
return false;
i++;
for (int i = 0; i < size; i++)
int a = list.get(i).getNum();
int b = list.get(i + 2).getNum();
if (b - a != 1)
return false;
i++;
i++;
return true;
//判断是不是双飞
public static boolean isFeiJI(List<PokerLabel> list)
List<Integer> count = feiCount(list);
if (count != null && count.size() >= 2)
int len = count.size();
for (int i = 0; i < len - 1; i++)
if (count.get(i + 1) - count.get(i) != 1)
return false;
int dui = feiDuiCount(list, count);
if (dui == 0)
return true;
return false;
//飞机带翅膀 3311
public static boolean isFeiJIDaiChiBang2(List<PokerLabel> list)
List<Integer> feiji = feiCount(list);
if (feiji != null && feiji.size() >= 2)
int len = feiji.size();
for (int i = 0; i < len - 1; i++)
if (feiji.get(i + 1) - feiji.get(i) != 1)
return false;
int dui = feiDuiCount(list, feiji);
if (dui == feiji.size())
return true;
return false;
//飞机带翅膀3322
public static boolean isFeiJIDaiChiBang1(List<PokerLabel> list)
List<Integer> feiji = feiCount(list);
if (feiji != null && feiji.size() >= 2)
int len = feiji.size();
for (int i = 0; i < len - 1; i++)
if (feiji.get(i + 1) - feiji.get(i) != 1)
return false;
int dui = feiDanZhangCount(list, feiji);
if (dui == feiji.size())
return true;
return false;
//判断三个头有几个
public static List<Integer> feiCount(List<PokerLabel> list)
List<Integer> cnt = new ArrayList<Integer>();
for (int i = 0; i < list.size() - 2; i++)
int a = list.get(i).getNum();
int b = list.get(i + 1).getNum();
int c = list.get(i + 2).getNum();
if (a == b && a == c)
cnt.add(a);
return cnt;
// 判断双飞中对子有几个
public static int feiDuiCount(List<PokerLabel> list,
List<Integer> feiji)
List<PokerLabel> temp = new ArrayList<PokerLabel>();
temp.addAll(list);
int cnt = 0;
for (int i = 0; i < temp.size(); i++)
for (int j = 0; j < feiji.size(); j++)
int a = list.get(i).getNum();
if (a == feiji.get(j))
temp.remove(i);
int size = temp.size();
if (size > 0 && size % 2 == 0)
for (int i = 0; i < temp.size() - 1; i++)
int a = list.get(i).getNum();
int b = list.get(i + 1).getNum();
if (a == b)
cnt++;
return cnt;
//判断双飞中单张有几个
public static int feiDanZhangCount(List<PokerLabel> list,
List<Integer> feiji)
List<PokerLabel> temp = new ArrayList<PokerLabel>();
temp.addAll(list);
int cnt = 0;
for (int i = 0; i < temp.size(); i++)
for (int j = 0; j < feiji.size(); j++)
int a = list.get(i).getNum();
if (a == feiji.get(j))
temp.remove(i);
int size = temp.size();
if (size > 0)
for (int i = 0; i < temp.size() - 1; i++)
int a = list.get(i).getNum();
int b = list.get(i + 1).getNum();
if (a != b)
cnt++;
return cnt;
//判断是否符合出牌规则,即根据上家牌面判断本次出牌是否合规
public static boolean legal(List<PokerLabel> prevList,
List<PokerLabel> currentList)
// 首先判断牌型是不是一样
PokerType paiXing = checkPokerType(prevList);
if (paiXing.equals(checkPokerType(currentList)))
// 根据牌型来判断大小
if (PokerType.p_1.equals(paiXing))
// 单张
if (compareLast(prevList, currentList))
return true;
return false;
else if (PokerType.p_2w.equals(paiXing))
// 王炸
return false;
else if (PokerType.p_2.equals(paiXing))
// 对子
if (compareLast(prevList, currentList))
return true;
return false;
else if (PokerType.p_3.equals(paiXing))
// 三张
if (compareLast(prevList, currentList))
return true;
return false;
else if (PokerType.p_31.equals(paiXing))
// 三带一
if (compareLast(prevList, currentList))
return true;
return false;
else if (PokerType.p_32.equals(paiXing))
// 三带一对
if (compare(prevList, currentList))
return true;
return false;
else if (PokerType.p_4.equals(paiXing))
// 炸弹
if (compareLast(prevList, currentList))
return true;
return false;
else if (PokerType.p_n.equals(paiXing))
// 顺子
if (compareLast(prevList, currentList))
return true;
return false;
else if (PokerType.p_1122.equals(paiXing))
// 连对
if (compareLast(prevList, currentList))
return true;
return false;
else if (PokerType.p_111222.equals(paiXing))
// 双飞
if (compare(prevList, currentList))
return true;
return false;
else if (PokerType.p_11122234.equals(paiXing))
// 飞机带翅膀(单张)
if (compare(prevList, currentList))
return true;
return false;
else if (PokerType.p_1112223344.equals(paiXing))
// 飞机带翅膀(对子)
if (compare(prevList, currentList))
return true;
return false;
else if (currentList.size() == 2)
//判断是不是王炸
if (isWangZha(currentList))
return true;
return false;
else if (currentList.size() == 4)
//判断是不是炸弹
if (isSame(currentList, 4))
return true;
return false;
return false;
public static boolean compareLast(List<PokerLabel> prevList,
List<PokerLabel> currentList)
if (prevList.get(prevList.size() - 1).getNum() <
currentList.get(currentList.size() - 1).getNum())
return true;
return false;
public static boolean compare(List<PokerLabel> prevList,
List<PokerLabel> currentList)
int a = san(prevList);
int b = san(currentList);
if (a == -1 || b == -1)
return false;
if (b > a)
return true;
return false;
public static int san(List<PokerLabel> list)
for (int i = 0; i < list.size() - 2; i++)
int a = list.get(i).getNum();
int b = list.get(i + 1).getNum();
int c = list.get(i + 2).getNum();
if (a == b && a == c)
return a;
return -1;
PokerType.java
package client.util;
public enum PokerType
p_1,//单牌。
p_2,//对子。
p_2w,//王炸
p_3,//3不带。
p_4,//炸弹。
p_n,//顺子。
p_31,//3带1。
p_32,//3带2。
p_1122,//连队。
p_111222,//飞机。
p_11122234,//飞机带单排.
p_1112223344,//飞机带对子.
p_error//不能出牌
LoginFrame.java
package client.view;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
public class LoginFrame extends JFrame
private JLabel lblUserName;
private JTextField txtUserName;
private JButton btnLogin;
private JButton btnCancel;
private void init()
Container container = this.getContentPane();
//创建组件对象
lblUserName = new JLabel("用户名:");
txtUserName = new JTextField();
btnLogin = new JButton("登录");
btnCancel = new JButton("取消");
//设置窗口属性
setSize(400, 220);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container.setLayout(null);
//设置组件属性
lblUserName.setSize(80, 25);
lblUserName.setLocation(90, 50);
lblUserName.setFont(new Font("微软雅黑", Font.PLAIN, 20));
txtUserName.setSize(120, 25);
txtUserName.setLocation(180, 50);
txtUserName.setFont(new Font("微软雅黑", Font.PLAIN, 20));
btnLogin.setSize(80, 25);
btnLogin.setLocation(100, 100);
btnLogin.setFont(new Font("微软雅黑", Font.PLAIN, 20));
btnCancel.setSize(80, 25);
btnCancel.setLocation(200, 100);
btnCancel.setFont(new Font("微软雅黑", Font.PLAIN, 20));
//添加组件到窗口中
container.add(lblUserName);
container.add(txtUserName);
container.add(btnLogin);
container.add(btnCancel);
//创建监听器对象 绑定到按钮上
MyEvent myEvent = new MyEvent();
btnLogin.addActionListener(myEvent);
public LoginFrame()
init();
//创建事件监听器类
class MyEvent implements ActionListener
@Override
public void actionPerformed(ActionEvent arg0)
//点击登录
//1.获得用户名
String uname = txtUserName.getText();
//2.创建一个socket链接服务器端
try
Socket socket = new Socket("127.0.0.1", 8888);
//3.跳转到主窗口
new MainFrame(uname, socket);
dispose();//关闭当前窗口
catch (UnknownHostException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
MainFrame.java
package client.view;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import client.model.*;
import client.util.*;
import client.thread.*;
public class MainFrame extends JFrame
public MyPanel myPanel;
public String uname;
public Socket socket;
public SendThread sendThread; // 发送消息的线程
public ReceiveThread receiveThread;// 接收消息的线程
public Player currentPlayer; // 存放当前玩家对象
public java.util.List<PokerLabel> pokerLabels =
new ArrayList<PokerLabel>(); // 存放扑克标签列表
public JLabel lordLabel1; // 抢地主标签
public JLabel lordLabel2; // 不叫
public JLabel timeLabel; // 定时器标签
public CountThread countThread; // 计数器的线程
public boolean isLord; // 是否是地主
public JLabel msgLabel; // 存放消息
public JLabel lordIconLabel; //地主图标
public JLabel chupaiJLabel;//出牌标签
public JLabel buchuJLabel; //不出牌标签
public ChuPaiThread chuPaiThread; //出牌定时器线程
public java.util.List<PokerLabel> selectedPokerLabels =
new ArrayList<PokerLabel>();//存放选中的扑克列表
public java.util.List<PokerLabel> showOutPokerLabels =
new ArrayList<PokerLabel>(); //存放当前出牌的列表
public boolean isOut; //选择的是出牌还是不出牌
public int prevPlayerid = -1; //上一个出牌的玩家id
public MainFrame(String uname, Socket socket)
this.uname = uname;
this.socket = socket;
// 设置窗口的属性
this.setTitle(uname);
this.setSize(1200, 700);
this.setVisible(true);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 添加mypanel
myPanel = new MyPanel();
myPanel.setBounds(0, 0, 1200, 700);
this.add(myPanel);
//初始化窗口信息
init();
// 启动发消息的线程
sendThread = new SendThread(socket, uname);
sendThread.start();
// 启动接收消息的线程
receiveThread = new ReceiveThread(socket, this);
receiveThread.start();
//窗口初始化
public void init()
//创建消息框
msgLabel = new JLabel();
chupaiJLabel = new JLabel();
chupaiJLabel.setBounds(330, 350, 110, 53);
chupaiJLabel.setIcon(new ImageIcon("images/bg/chupai.png"));
chupaiJLabel.addMouseListener(new MyMouseEvent());
chupaiJLabel.setVisible(false);
this.myPanel.add(chupaiJLabel);
buchuJLabel = new JLabel();
buchuJLabel.setBounds(440, 350, 110, 53);
buchuJLabel.setIcon(new ImageIcon("images/bg/buchupai.png"));
buchuJLabel.addMouseListener(new MyMouseEvent());
buchuJLabel.setVisible(false);
this.myPanel.add(buchuJLabel);
timeLabel = new JLabel();
timeLabel.setBounds(550, 350, 50, 50);
timeLabel.setFont(new Font("Dialog", 0, 30));
timeLabel.setForeground(Color.red);
timeLabel.setVisible(false);
this.myPanel.add(timeLabel);
public void showAllPlayersInfo(java.util.List<Player> players)
// 1.显示三个玩家的名称
// 2.显示当前玩家的扑克列表
for (int i = 0; i < players.size(); i++)
if (players.get(i).getName().equals(uname))
currentPlayer = players.get(i);
java.util.List<Poker> pokers = currentPlayer.getPokers();
for (int i = 0; i < pokers.size(); i++)
// 创建扑克标签
Poker poker = pokers.get(i);
PokerLabel pokerLabel = new PokerLabel(poker.getId(),
poker.getName(), poker.getNum());
pokerLabel.turnUp(); // 显示正面图
// 添加到面板中
this.myPanel.add(pokerLabel);
this.pokerLabels.add(pokerLabel);
// 动态的显示出来
this.myPanel.setComponentZOrder(pokerLabel, 0);
// 一张一张的显示出来
GameUtil.move(pokerLabel, 300 + 30 * i, 450);
// 对扑克列表排序
Collections.sort(pokerLabels);
// 重新移动位置
for (int i = 0; i < pokerLabels.size(); i++)
this.myPanel.setComponentZOrder(pokerLabels.get(i), 0);
GameUtil.move(pokerLabels.get(i), 300 + 30 * i, 450);
if (currentPlayer.getId() == 0)
getLord(); // 抢地主
//抢地主
public void getLord()
// 显示抢地主的按钮 和 定时器按钮
lordLabel1 = new JLabel();
lordLabel1.setBounds(330, 400, 104, 46);
lordLabel1.setIcon(new ImageIcon("images/bg/jiaodizhu.png"));
lordLabel1.addMouseListener(new MyMouseEvent());
this.myPanel.add(lordLabel1);
lordLabel2 = new JLabel();
lordLabel2.setBounds(440, 400, 104, 46);
lordLabel2.setIcon(new ImageIcon("images/bg/bujiao.png"));
lordLabel2.addMouseListener(new MyMouseEvent());
this.myPanel.add(lordLabel2);
//显示定时器的图标
this.timeLabel.setVisible(true);
this.setVisible(true);
// 重绘
this.repaint();
// 启动计时器的线程
countThread = new CountThread(10, this);
countThread.start();
//显示出牌的标签
public void showChuPaiJabel()
if (prevPlayerid == currentPlayer.getId())
//从窗口上移除之前的出牌的列表
for (int i = 0; i < showOutPokerLabels.size(); i++)
myPanel.remove(showOutPokerLabels.get(i));
//清空之前出牌的列表
showOutPokerLabels.clear();
// 显示出牌和不出牌的按钮 和 定时器按钮
chupaiJLabel.setVisible(true);
buchuJLabel.setVisible(true);
timeLabel.setVisible(true);
this.repaint();
chuPaiThread = new ChuPaiThread(30, this);
chuPaiThread.start();
// 显示消息(不抢 或 不出)
public void showMsg(int playerid, int typeid)
msgLabel.setVisible(true);
msgLabel.setBounds(500, 300, 129, 77);
if (typeid == 1)
msgLabel.setIcon(new ImageIcon("images/bg/buqiang.png"));
if (typeid == 3)
msgLabel.setIcon(new ImageIcon("images/bg/buchu.png"));
if (playerid == currentPlayer.getId())
msgLabel.setLocation(400, 300);
else if (playerid + 1 == currentPlayer.getId() ||
playerid - 2 == currentPlayer.getId()) //上家 // 2 0 0 1 1 2
msgLabel.setLocation(300, 100);
else // 下家
msgLabel.setLocation(800, 100);
this.myPanel.add(msgLabel);
this.repaint();
// 添加地主牌
public void addLordPokers(java.util.List<Poker> lordPokers)
for (int i = 0; i < lordPokers.size(); i++)
Poker poker = lordPokers.get(i);
PokerLabel pokerLabel = new PokerLabel(poker.getId(),
poker.getName(), poker.getNum());
pokerLabel.turnUp(); // 显示正面图
this.pokerLabels.add(pokerLabel);
Collections.sort(pokerLabels);
for (int i = 0; i < pokerLabels.size(); i++)
// 添加到面板中
this.myPanel.add(pokerLabels.get(i));
// 动态的显示出来
this.myPanel.setComponentZOrder(pokerLabels.get(i), 0);
// 一张一张的显示出来
GameUtil.move(pokerLabels.get(i), 300 + 30 * i, 450);
currentPlayer.getPokers().addAll(lordPokers);
//显示地主图标
public void showLordIcon(int playerid)
//创建地主图标对象
lordIconLabel = new JLabel();
lordIconLabel.setIcon(new ImageIcon("images/bg/dizhu.png"));
lordIconLabel.setSize(60, 89);
//根据玩家id显示到具体的位置
//如果自己是地主
if (playerid == currentPlayer.getId())
lordIconLabel.setLocation(200, 450);
else if (playerid + 1 == currentPlayer.getId() ||
playerid - 2 == currentPlayer.getId()) //上家 // 2 0 0 1 1 2
lordIconLabel.setLocation(200, 100);
else // 下家
lordIconLabel.setLocation(950, 100);
//添加地主图标到面板上
this.myPanel.add(lordIconLabel);
this.repaint(); //重绘
//给扑克牌添加单击事件
public void addClickEventToPoker()
for (int i = 0; i < pokerLabels.size(); i++)
pokerLabels.get(i).addMouseListener(new PokerEvent());
//显示出牌的列表
public void showOutPokerList(int playerid,
java.util.List<Poker> outPokers)
//从窗口上移除之前的出牌的列表
for (int i = 0; i < showOutPokerLabels.size(); i++)
myPanel.remove(showOutPokerLabels.get(i));
//清空之前出牌的列表
showOutPokerLabels.clear();
//显示当前出牌的列表
for (int i = 0; i < outPokers.size(); i++)
Poker poker = outPokers.get(i);
PokerLabel pokerLabel = new PokerLabel(poker.getId(),
poker.getName(), poker.getNum());
if (playerid == currentPlayer.getId())
pokerLabel.setLocation(400 + 30 * i, 300);
else if (playerid + 1 == currentPlayer.getId() ||
playerid - 2 == currentPlayer.getId())
pokerLabel.setLocation(200 + 30 * i, 100);
else
pokerLabel.setLocation(700 + 30 * i, 100);
pokerLabel.turnUp();
myPanel.add(pokerLabel);
showOutPokerLabels.add(pokerLabel);
myPanel.setComponentZOrder(pokerLabel, 0);
this.repaint(); //窗口重绘
//出牌 将出的牌从当前玩家的扑克列表中移除
public void removeOutPokerFromPokerList()
//1.从当前玩家的扑克列表中移除
pokerLabels.removeAll(selectedPokerLabels);
//2.从面板中移除
for (int i = 0; i < selectedPokerLabels.size(); i++)
myPanel.remove(selectedPokerLabels.get(i));
//3.剩下的扑克列表重新定位
for (int i = 0; i < pokerLabels.size(); i++)
myPanel.setComponentZOrder(pokerLabels.get(i), 0);
GameUtil.move2(pokerLabels.get(i), 300 + 30 * i, 450);
//4.清空选择的扑克牌列表
selectedPokerLabels.clear();
this.repaint();
//游戏结束
public void gameOver()
this.myPanel.removeAll();
this.repaint();
try
this.socket.close();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
this.countThread.setRun(false);
this.chuPaiThread.setRun(false);
this.sendThread.setRun(false);
this.receiveThread.setRun(false);
// 创建鼠标事件监听器类
class MyMouseEvent extends MouseAdapter
@Override
public void mouseClicked(MouseEvent event)
// 点击的是抢地主
if (event.getSource().equals(lordLabel1))
// 停止计时器
countThread.setRun(false);
isLord = true;
// 设置抢地主的按钮不可见
lordLabel1.setVisible(false);
lordLabel2.setVisible(false);
timeLabel.setVisible(false);
// 点击的不抢
if (event.getSource().equals(lordLabel2))
// 停止计时器
countThread.setRun(false);
isLord = false;
lordLabel1.setVisible(false);
lordLabel2.setVisible(false);
timeLabel.setVisible(false);
//点击出牌
if (event.getSource().equals(chupaiJLabel))
PokerType pokerType = PokerRule.checkPokerType(selectedPokerLabels);
//判断是否符合牌型
if (!pokerType.equals(PokerType.p_error))
System.out.println(prevPlayerid + "," + currentPlayer.getId());
//符合牌型,判断是不是比上家大 或者上家就是自己
if (prevPlayerid == -1 || prevPlayerid == currentPlayer.getId() ||
PokerRule.legal(showOutPokerLabels, selectedPokerLabels))
isOut = true;
//计时器停止
chuPaiThread.setRun(false);
chupaiJLabel.setVisible(false);
buchuJLabel.setVisible(false);
timeLabel.setVisible(false);
else
JOptionPane.showMessageDialog(null, "请按规则出牌");
else
JOptionPane.showMessageDialog(null, "不符合牌型");
if (event.getSource().equals(buchuJLabel))
isOut = false;
//计时器停止
chuPaiThread.setRun(false);
chupaiJLabel.setVisible(false);
buchuJLabel.setVisible(false);
timeLabel.setVisible(false);
//创建扑克牌的事件监听器类
class PokerEvent extends MouseAdapter
@Override
public void mouseClicked(MouseEvent arg0)
// TODO Auto-generated method stub
PokerLabel pokerLabel = (PokerLabel) arg0.getSource();
//如果之前选择过了 则取消选择(设置选中属性为false 位置回到原位,从选择的扑克牌列表中移除)
if (pokerLabel.isSelected())
pokerLabel.setSelected(false);
pokerLabel.setLocation(pokerLabel.getX(), pokerLabel.getY() + 30);
selectedPokerLabels.remove(pokerLabel);
//如果之前没有选择 则选中(设置选中属性为true 位置往上移动一点,添加到选择的扑克牌列表中)
else
pokerLabel.setSelected(true);
pokerLabel.setLocation(pokerLabel.getX(), pokerLabel.getY() - 30);
selectedPokerLabels.add(pokerLabel);
MyPanel.java
package client.view;
import java.awt.*;
import javax.swing.*;
public class MyPanel extends JPanel
public MyPanel()
this.setLayout(null);
@Override
protected void paintComponent(Graphics g)
Image image=new ImageIcon("images/bg/bg1.png").getImage();
g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), null);
Main.java
package client.view;
public class Main
public static void main(String[] args)
new LoginFrame();//打开第一个玩家的登录窗口
new LoginFrame();//打开第二个玩家的登录窗口
new LoginFrame();//打开第三个玩家的登录窗口
MainServer.java
package server;
import java.io.*;
import java.net.*;
import java.util.*;
import com.alibaba.fastjson.*;
import client.model.*;
public class MainServer
//创建玩家列表
public List<Player> players = new ArrayList<Player>();
public int index = 0;
//存放扑克列表
public List<Poker> allPokers = new ArrayList<Poker>();
//存放底牌
public List<Poker> lordPokers = new ArrayList<Poker>();
public int step = 0; //牌局的进展步骤
public MainServer()
//创建扑克列表
createPokers();
try
//1.创建服务器端socket
ServerSocket serverSocket = new ServerSocket(8888);
while (true)
//2.接收客户端的socket
Socket socket = serverSocket.accept();
//3.开启线程 处理客户端的socket
AcceptThread acceptThread = new AcceptThread(socket);
acceptThread.start();
catch (IOException e)
e.printStackTrace();
System.out.println("服务器端异常");
//创建一个接收线程 处理客户端的信息
class AcceptThread extends Thread
Socket socket;
public AcceptThread(Socket socket)
this.socket = socket;
public void run()
try
DataInputStream dataInputStream =
new DataInputStream(socket.getInputStream());
while (true)
String msg = dataInputStream.readUTF();
if (step == 0)
//创建player对象
Player player = new Player(index++, msg);
player.setSocket(socket);
//存入玩家列表
players.add(player);
System.out.println(msg + "上线了");
System.out.println("当前上线人数:" + players.size());
//玩家人数到齐,发给三个玩家
if (players.size() == 3)
deal();//发牌
step = 1;
else if (step == 1) //接收抢地主的信息
System.out.println("接收抢地主的消息");
JSONObject msgJsonObject = JSON.parseObject(msg);
int typeid = msgJsonObject.getInteger("typeid");
int playerid = msgJsonObject.getInteger("playerid");
String content = msgJsonObject.getString("content");
//抢地主
if (typeid == 2)
//重新组将一个 消息对象 ,添加地主牌
Message sendMessage =
new Message(typeid, playerid, content, lordPokers);
msg = JSON.toJSONString(sendMessage);
step = 2;
//不抢 将客户端发过来的不抢的信息 原样群发到所有玩家
sendMessageToClient(msg);
else if (step == 2) //出牌和不出牌和游戏结束
sendMessageToClient(msg); //转发到所有的客户端
catch (IOException e)
e.printStackTrace();
System.out.println("服务器异常:" + e.getMessage());
//群发消息到客户端
public void sendMessageToClient(String msg)
for (int i = 0; i < players.size(); i++)
DataOutputStream dataOutputStream;
try
dataOutputStream = new DataOutputStream(
players.get(i).getSocket().getOutputStream());
dataOutputStream.writeUTF(msg);
catch (IOException e)
e.printStackTrace();
//创建所有的扑克列表
public void createPokers()
//创建大王 ,小王
Poker dawang = new Poker(0, "大王", 17);
Poker xiaowang = new Poker(1, "小王", 16);
allPokers.add(dawang);
allPokers.add(xiaowang);
//创建其它扑克
String[] names = new String[]
"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3";
String[] colors = new String[]
"黑桃", "红桃", "梅花", "双块";
int id = 2;
int num = 15;
//遍历扑克的种类
for (String name : names)
//遍历每个种类的花色
for (String color : colors)
Poker poker = new Poker(id++, color + name, num);
allPokers.add(poker);
num--;
//洗牌
Collections.shuffle(allPokers);
//发牌
public void deal()
//发给三个玩家
for (int i = 0; i < allPokers.size(); i++)
//最后三张留给地主牌
if (i >= 51)
lordPokers.add(allPokers.get(i));
以上是关于《斗地主游戏》第3节:项目完整代码的主要内容,如果未能解决你的问题,请参考以下文章