《斗地主游戏》第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节:项目完整代码的主要内容,如果未能解决你的问题,请参考以下文章

[“斗地主”的技巧:扑克游戏指导].孔维民.扫描版

手机斗地主游戏开发,好玩有趣的模式

斗地主

斗地主

NOIP2015斗地主

[教你做小游戏] 展示斗地主扑克牌,支持按出牌规则排序!支持按大小排序!