UNO牌简单介绍

UNO牌共有108张牌。包括76张数字牌,32张功能牌。
颜色:红、黄、蓝、绿、黑 5种。
每人先发牌7张,其余当作牌库。翻开牌库,作为第一张,每人轮流出牌。每个出牌的人,必需出与上一家出的牌,同样颜色或同样数字的牌。没有牌可出时需从牌库中拿一张到手上,如果还是不能出,则跳过,轮到下一个人。有功能牌及王牌,可以使其他的人增加手上的牌,也可帮自己快点将牌出光。最先把手中牌出光的人赢。

代码实现

若不是班里有同学中午玩UNO,这篇文章才不会写出来。
首先是静态变量的定义。

 static float second =0.0f;//对局时间,假设每次出牌为4秒static int playerNUM = 1;static int playerNUM2 = 1;static boolean isClockwise = true;//是顺时针static int k = 0;//记录最后一张有效数字牌!static int handCardsNum = 7;//手牌数static int playerNumber = 4;//玩家数量static int lib [] = new int[108];static int OrderLib [] = new int[108];static int free[] = new int [108];static ArrayStack Library = new ArrayStack(108);//牌堆 栈实现static ArrayStack lose = new ArrayStack(108);//弃牌区 栈实现

UNO牌就是几个玩家围成一圈,在桌子上进行的娱乐卡牌游戏,尽管没办法加入他们打牌的行列,加上月底还有考试,所以代码写的冗余就体谅一下还在读高中的萌新程序员吧。
双向链表用来存储玩家信息,节点保存玩家编号,姓名,上一个节点和下一个节点,顺便挂一个数组用来保存自己的手牌。

class BidirectionalLinkedManager{Node head = new Node(1,"玩家1");//头节点boolean k1 = true;Main m = new Main();public void add(Node nd) {//添加节点Node temp = head;while(true) {if(temp.next==(k1?null:head)) {//头结点的下一个节点temp.next = nd;nd.pre = temp;//头结点与此节点head.pre = nd;nd.next = head;k1 = false;break;}temp = temp.next;}}public void list() {//遍历节点Node temp = head.next;System.out.println("N:"+head);while(true) {if(temp==head) {return;}System.out.println("N:"+temp);temp = temp.next;}}
}
class Node{int Num;int index = 0;int handcard[] = new int [100];String name;Node next;Node pre;Node(int _Num,String _name){this.name = _name;this.Num = _Num;}@Overridepublic String toString() {// TODO Auto-generated method stubreturn "<NODE--- Num--> "+Num+" Name--> "+name+"  >"+"上一个: "+pre.name+" 下一个: "+next.name;}
}

其中,反转牌的实现我是采用一个isClockwise变量保存顺时针逆时针,使用反转牌则顺时针变逆时针,逆时针变顺时针。
假设有1-5名玩家,编号分别为1-5,顺时针,5后为1,1前为5。则+2+4牌就需要以下方法。

public static void numTurn(int pN,boolean isclock) {if(isclock) {if(pN<playerNumber) {//System.out.println("playerNumber"+pN);playerNUM++;}else{playerNUM=1;}}else {if(pN>1) {playerNUM--;}else {playerNUM=playerNumber;}}}

玩家对战,NPC的逻辑部分,new一个节点,用节点管理器来寻找保存的节点。找到编号对应的Node,把它挂着的数组拿过来遍历。静态变量里面有个k变量,用来存放最后一张有效牌。遍历判断该牌是否与k代表的颜色相同,若颜色相同,则还要注意几张还带有颜色的功能牌。+2,禁止与反转。
如何让k代表所有牌呢?
我注意到了UNO牌有0-9,以及+2,禁止,反转,黑色王牌的万用和+4,有红黄蓝绿黑五种颜色。所以我的做法是给它们编号,0-9一样,+2为10,禁止11,反转12,则给颜色编号就是100,200,300这样。
黑色牌万用550,黑色牌+4 660.。
举例 红4 代表编号104,绿反转代表编号412
先展示一下其他的方法。


public boolean iSHave(Node nd,int preCard) {//手牌是否有能出的牌Node temp = head;int c = 0;while(true) {if(nd.Num==temp.Num) {for(int i = 0;i<temp.index;i++) {int cardNum = temp.handcard[i];if((cardNum-cardNum%100)/100==(preCard-preCard%100)/100) {//相同颜色牌return true;}if(cardNum%100==preCard%100) {//相同数字牌return true;}}}temp = temp.next;if(++c>m.playerNumber)break;}return false;}public boolean iSHaveKing(Node nd) {//是否有王牌Node temp = head;int c = 0;while(true) {if(nd.Num==temp.Num) {for(int i = 0;i<temp.index;i++) {int cardNum = temp.handcard[i];if(cardNum>=500) {return true;}}}temp = temp.next;if(++c>m.playerNumber)break;}return false;}public void sort(Node nd) {//出牌后 整理手牌Node temp = head;while(true) {if(nd.Num==temp.Num) {for(int i = 0;i<temp.index-1;i++) {if(temp.handcard[i]==0) {temp.handcard[i] = temp.handcard[i+1];temp.handcard[i+1] = 0;}}temp.index--;break;}temp = temp.next;}System.out.println("出牌后 手牌数: "+temp.index);}
public void showCard(Node nd) {//展示手牌Node temp = head;while(true) {if(nd.Num==temp.Num) {//找到目标节点System.out.print("玩家"+temp.Num+"  手牌为");for(int i=0;i<temp.index;i++) {//System.out.print(temp.handcard[i]+" ");System.out.print(Main.howColor(temp.handcard[i])+temp.handcard[i]%100+" ");}System.out.println();break;}temp = temp.next;}}public void addArray(Node nd,int a) {//添加手牌Node temp = head;while(true) {if(nd.Num==temp.Num) {//找到目标节点temp.handcard[temp.index++]=a;break;}temp = temp.next;}if(Main.Library.top==0) {System.out.println("牌库空,洗牌");Random r1 = new Random();int index = Main.lose.top;System.out.println("lose index:"+ Main.lose.top);for(int i=0;i<index;i++) {Main.free[i] = Main.lose.Pop();}int s = index;while(index>0) {int s1 = r1.nextInt(s);if(Main.free[s1]!=0) {Main.Library.Push(Main.free[s1]);Main.free[s1]=0;index--;}}}}

然后我们写一个使用自己手牌的方法

public void useCard(Node nd,int k) {//使用手牌Node temp = head;int c = 0;while(true) {if(nd.Num==temp.Num) {System.out.println("temp:index:"+temp.index);boolean x = true;for(int i=0;i<temp.index;i++) {int num =temp.handcard[i];if(Main.howColor(num)==Main.howColor(m.k)) {//相同颜色showCard(nd);if(num%100<10) {temp.handcard[i]=0;sort(nd);Main.k = num;//覆盖有效牌System.out.println("玩家"+nd.Num+"打出"+Main.howColor(num)+num%100);}else if(num%100==10){//+2temp.handcard[i]=0;sort(nd);addArray(new Node(Main.NT1(nd.Num, Main.isClockwise)," "), Main.Library.Pop());addArray(new Node(Main.NT1(nd.Num, Main.isClockwise)," "), Main.Library.Pop());System.out.println("玩家"+nd.Num+"使用"+Main.howColor(num)+"+2牌");}else if(num%100==11) {//阻挡temp.handcard[i]=0;sort(nd);Main.numTurn(nd.Num,Main.isClockwise);System.out.println("玩家"+nd.Num+"使用阻挡牌");}else if(num%100==12) {//反转temp.handcard[i]=0;sort(nd);Main.isClockwise = Main.isClockwise ? false : true;System.out.println("玩家"+nd.Num+"使用反转牌");System.out.println(Main.isClockwise);}Main.lose.Push(num);//压入弃牌区x = false;break;}else if(num%100==k%100){//相同数字Main.k = num;//覆盖有效牌Main.lose.Push(num);temp.handcard[i]=0;sort(nd);showCard(nd);System.out.println("玩家"+nd.Num+"打出"+Main.howColor(num)+num%100);x = false;break;}else if(num%100==50){//Main.k = k-k%100+20;//覆盖有效牌Main.lose.Push(num);temp.handcard[i]=0;sort(nd);showCard(nd);System.out.println("玩家"+nd.Num+"使用万用牌");x = false;break;}else if(num%100==60){temp.handcard[i]=0;sort(nd);for(int j =0;j<4;j++) {addArray(new Node(Main.NT1(nd.Num, Main.isClockwise)," "), Main.Library.Pop());}showCard(nd);System.out.println("玩家"+nd.Num+"使用+4牌");x = false;break;}}if(x) {c=0;//让链表再循环一次找这个node编号addArray(nd, Main.Library.Pop());showCard(nd);System.out.println("玩家"+nd.Num+"抽牌");}}temp = temp.next;if(c++>Main.playerNumber-1) break;}}

最开始的初始化:牌堆随机化,玩家建立等

public static void initial () {//初始化int index = 0;for(int i = 1;i<5;i++) {//基本牌四个颜色21张,有颜色功能牌24张for(int j = 0;j<13;j++) {//除无颜色功能牌以及0有一张牌,其余都是两张,则循环两次lib[index++] = j+100*i;}for(int j = 1;j<13;j++) {lib[index++] = j+100*i;}}for(int i=5;i<=6;i++) {//无颜色功能牌8张 +4 wfor(int j=0;j<4;j++) {lib[index++] = i*110;}}Random r = new Random();while(index>0) {//没有重复为止int s = r.nextInt(108);if(OrderLib[s]==0) {OrderLib[s] = lib[--index];}}for(int i=0;i<OrderLib.length;i++) {//压入牌堆Library.Push(OrderLib[i]);}}

最后主方法

public static void main(String[] args) {BidirectionalLinkedManager blm = new BidirectionalLinkedManager();Scanner sc = new Scanner(System.in);initial();//初始化,牌堆已打乱System.out.println("请输入玩家数量");playerNumber = sc.nextInt();for(int i = 2;i<=playerNumber;i++) {Node n = new Node(i, "玩家"+i);blm.add(n);}blm.list();//System.out.println("玩家就绪");for(int i = 1;i<=playerNumber;i++) {Node nd = new Node(i, "玩家"+i);for(int j =0;j<handCardsNum;j++) {//每个玩家初始7张手牌blm.addArray(nd, Library.Pop());}}System.out.println("游戏开始");System.out.print("第一张牌是:");String first = ""; while(true) {k = Library.Pop();if(isfunction(k)) {lose.Push(k);}else {System.out.print(howColor(k));System.out.println(k%100);lose.Push(k);break;}}while(true) {Node node = new Node(playerNUM,"玩家"+playerNUM);blm.useCard(node, k);//根据isClockwise判断playerNUM是否加或减numTurn(node.Num,isClockwise);second +=4.0;if(blm.isWin(node))break;}System.out.println("共用时"+second);


需要注意的点(萌新博主犯的错误)
链表之间的节点关联。
弄明白游戏机制(为了出一张牌倒是得多摸几张牌)
别一股脑不调试刷刷刷写到底,会崩溃的(指心情)
好吧,就这样了,欢迎各方大佬指正,本人虚心求教。路漫漫其修远兮。

java模拟UNO玩家对战相关推荐

  1. Java用最少代码实现五子棋-玩家对战模式-人机对战模式-电脑策略对战

    Java用最少代码实现五子棋-玩家对战模式-人机对战模式-电脑策略对战 玩家对战模式 背景说明 代码实现 人机对战模式 背景说明 完整代码实现 电脑根据优势分数对战 背景说明 完整代码实现 小结 玩家 ...

  2. Jsoup实现java模拟登陆

    Jsoup实现java模拟登陆 1:如何获取cookies. 1.1:由于需要登录,故先模拟登陆时的那一个<form>,这里用map来装载变量名称,变量值. Map<String, ...

  3. java五子棋联网对战,毕业设计-- 用JAVA实现五子棋网络对战系统

    毕业设计-- 用JAVA实现五子棋网络对战系统 本科生毕业设计(论文)本科生毕业设计(论文) 题 目 用 JAVA 实现五子棋网络对战系统 姓 名 xxxx 学 号 xxxxx 系 别 计算机工程系 ...

  4. java模拟回合打怪游戏

    java模拟回合打怪游戏 玩家的血值:w = 315 怪物的血值:g = 500 玩家和怪物互打 玩家每次攻击怪物产生5-8点伤害 怪物每次攻击玩家产生3-5点伤害 采用回合制,一方血量<=0游 ...

  5. 【C语言实现】玩家互战五子棋(具体步骤和代码)

    文章目录 前言 一.问题描述 二.基本流程 三.步骤 1.构建程序主体框架以及菜单的实现 2.良好的宏定义增强代码可读性 3.构建游戏入口PlayersGame()函数 4.实现打印棋盘函数 5.实现 ...

  6. java 模拟时钟_java模拟时钟

    本次课程设计采用时间片轮转调度算法来实现模拟进程调度任务的执行过 程. 用 Java 模拟进程调度过程,可以方便地将运行结果直观地表示出来.Java 语言 独有的多...... 本次课程设计采用时间片 ...

  7. 233网校java_java辅导:使用java模拟登陆考试大

    java辅导:使用java模拟登陆考试大 2009年1月5日来源:233网校网校课程 在线题库评论 分享到 public static void loginexamda() { URL url = n ...

  8. JAVA同时输入用户名和密码_用java模拟设计一个简单的“用户注册”程序。当用户输入用户名和密码时,单击“注...

    用java模拟设计一个简单的"用户注册"程序.当用户输入用户名和密码时,单击"注 2020 - 9 - 26 TAG : 所有功能均已实现,如有不满意的地方我再修改imp ...

  9. 用Java模拟multipart形式的Http Post请求

    本例通过java模拟了Http的request请求,请求格式为multipart,实现了向服务器同时传递json数据和图片数据. 1 import java.io.ByteArrayOutputStr ...

最新文章

  1. 高德亿级流量接入层服务的演化之路
  2. 临河天气预报软件测试,临河天气预报15天
  3. php tp3 操作绑定到类,操作绑定到类 · ThinkPHP3.2.3完全开发手册 · 看云
  4. eclipse 代码上传github 笔记
  5. 红旗linux 进不去图形界面,进不了红旗Linux6.0的图形界面请高手帮忙
  6. LintCode 69---二叉树的层次遍历
  7. (转)em重建全过程
  8. 个人电脑 公司电脑 代理_你们想要打造的树莓派电脑,刚发布了官方版:性能更强大,只卖70美元...
  9. Echarts定制一个地图
  10. 通​过​C​a​c​t​i​监​控​w​i​n​d​o​w​s​资​源
  11. iOS 13问题记录
  12. hdu 4928 Series 2 (优化+模拟)
  13. 分省老年抚养比和老年人口比重(1995-2018年)
  14. 服务器整体爆率如何修改,传奇服务端gom引擎提升爆率脚本
  15. Ionic页面传参跳转
  16. [应用推荐]FreeMind自动生成系统盘的树状图(思维导图)
  17. vue element-ui table表格自定义纵向合计横向合计
  18. linux||Linux的操作系统的简单指令
  19. 这算通过审核了么?接下来还有没有什么坑,求大神指点!--酷课堂iOS交流群问答精华整理(201808期)
  20. C++中用 GetModuleFileName()函数 获得程序当前的运行目录

热门文章

  1. Swagger错误:The provided definition does not specify a valid version field.
  2. ip访问次数统计 nginx_分析Nginx 5分钟内的 日志 然后统计出 访问次数最多的ip 地址 和次数...
  3. How input events are dispatched in Android?
  4. 微软iis服务器并发量,服务器IIS最大并发数
  5. HAVOK如何处理挖洞处的碰撞问题
  6. 图像处理之matlab中meshgrid函数用法详解
  7. 域名证书到期,如何通过nginx更换https证书
  8. 实现访问http 自动跳转到https
  9. 向天草学习之路(三)
  10. 什么是WEB服务器?