面向对象课设实验——solitaire(java实现)

本文详细介绍了如何用Java实现Solitaire游戏,包括理解游戏规则、设计思路及具体实现细节。游戏涉及四种卡堆:牌库、遗弃堆、正序堆和倒序堆,使用枚举类表示花色和大小,Pile类模拟牌堆操作。同时,文章指出了项目存在的不足,如缺少动态卡片移动效果和游戏难度设定。
摘要由CSDN通过智能技术生成

一、读懂题目!

一开始看题目我就看了很久,面对下面这张图解我完全看不懂,不知道这个游戏到底怎么进行,后来在win10自带的游戏里找到了这个游戏才知道是要做什么。(做一个项目之前必须得完完全全理解这个项目具体的要求是什么,不能摸棱两可)
在这里插入图片描述
(点击solitaire进去后选择经典单人游戏即可感受游戏)
在这里插入图片描述

游戏说明:将一副扑克牌去掉大小王,只剩下四个花色的1-13,将这些牌放进四种卡堆中,1、deck cards(牌库)2、discard card(遗弃堆)3、suitpiles(正序堆)4、takepiles(倒序堆)四个正序堆每个牌堆对应一种花色,且该堆必须从小到大牌放,即黑桃1在最下面,黑桃2在黑桃1上面直到黑桃13。七个倒序堆牌堆由13在最下面,1在最上面,且任意两张牌之间花色为红黑交替,在倒序堆间移动卡片只能移动连续放置的卡片。卡库为正序牌堆和倒序牌堆外剩余的牌,点击卡库可以将一张牌放在遗弃堆的最上面,遗弃堆只显示最上面一张牌。

(以上的四个牌堆对应我项目中的deck、waste、foundation、tableau)

二、设计思路

1.有关牌堆的设计
(1)枚举类Suit和Colour我们需要纸牌的四个花色和十三个大小,所以初始化了两个枚举类Suit和Colour,分别存放花色和大小,以便卡牌的初始化。
(2)Card类我们需要卡牌类Card,然后初始化每一张卡牌,Card类中有卡片图像、数值、花色是否正面朝上的属性,以及各个属性对应的get和set方法。
(3)Pile由于牌堆后进先出的,所以我使用了 stack来模拟了堆栈进行操作。Pile类有两个属性,一个是Pile堆在面板上的位置,一个是stack存储该牌堆的所有card。实现的方法有,获取最顶部卡牌,往牌堆顶添加一张卡牌,push一组卡牌,pop一组卡牌,删除顶端卡牌,判断牌堆是否为空等等方法。
(4)Deck卡库继承自Pile。初始化时就把所有卡片先放入Deck中,添加paintComponent方法(画出deck堆,若无牌则显示空白框,有牌则显示有牌的背面)。
(5)waste丢弃堆继承自Pile。添加paintComponent方法(画出waste堆,若无牌则显示空白框,有牌则只显示最上面一张牌的正面,其他牌被覆盖)。(6)Foundation正序堆堆花色堆继承自Pile,是收集已经有序的牌的地方。添加paintComponent方法(画出deck堆,若没有牌则显示花色底牌,有牌则只显示最上面一张牌的正面,其他牌被覆盖)、moveFromWaste方法(从丢弃堆移动到正序堆)、moveTo方法(从正序堆移动到倒序堆)、accepts方法(该卡片是否能放到正序堆)、intToSuit方法(花色和花色相应的数字是否匹配)
(7)Tableau倒序堆桌面堆是玩牌的主要区域,需要根据游戏的规则堆牌堆进行拖动,达到排序的效果,最终让牌全部放到花色堆。桌面堆继承自Pile,并且添加paintComponent方法(画出tableau堆,一沓牌只有最上面的牌显示为正面,其他的显示为背面,并且堆叠放置)、moveFromWaste方法(从丢弃堆移动到倒序堆)、accepts方法(该卡片是否能放到倒序堆)、两个moveTo方法(分别是移动到正序堆和其他倒序堆)、getClickedCard方法(获取选中的是倒序堆的哪些牌)
2. 有关界面的设计
(1)定义GameMoveListener类继承自MouseInputAdapter,其中重写mousePressed、mouseReleased方法,鼠标下压如果选中的是卡库、丢弃堆、或倒序堆的牌如果能放到对应的正序堆则直接放上去。若不能,则根据鼠标释放时的位置判断是否允许该次移动,最后重画各个变化了的组件。
(2)定义GamePanel,在其上添加监听器、各个牌堆类并放置好位置。

三、具体细节

(大家先看一下项目的文件分布)
在这里插入图片描述

cards包用来装卡片的图像图片
(命名格式非常重要!!!!)
在这里插入图片描述
在这里插入图片描述
//back001为卡片背面图片,bottom01为空白卡片轮廓图片,放在空白遗弃堆位置。fpBase为四个花色的背景图片,放在空白正序堆位置。

在这里插入图片描述

实现思路:
Pile类为牌堆的基类
其他四个牌堆继承Pile类,
Color、suit类为枚举类,存放颜色、花色信息
GameMoveListener实现移动卡片的监听器
GamePanel为创建游戏面板,添加入所有组件
PhotoMoving为一个移动卡片拖拽的实现,尝试了加在项目里面结果没成功(于是项目现在的卡片移动过程看不到,只能怪看到移动成功后的卡片位置变换)

上代码!!!

Suit.java

package solitaire;
 public enum Suit {
   		
 Spades, Hearts, Clubs, Diamonds }//enum枚举类型这
 //段代码实际上调用了Enum(String name, int ordinal):new Enum<EnumTest>("MON",0);

Colour.java

package solitaire; 
public enum Colour {
   		
Red, Black, Neither }

Card.java

package solitaire; 
import java.awt.Image; 
import javax.swing.ImageIcon; 
public class Card {
   		
	public static String cardBackFilename = "back001",			cardOutlineFilename = "bottom01",			
	fpBaseFilename = "fpBase0";	
	public static String directory = "cards", extension = ".gif";	
	private Image im;//每一张卡片的正面图片	
	private int value;//卡片数值	
	private String suit;//花色	
	private boolean faceUp;	private Colour colour; 	
	public Card(int value, Suit suit) {
   //通过switch选择花色		
		this.value = value;		
		switch(suit) {
   		
		case Clubs:			
		this.suit = "c";			
		colour = Colour.Black;			
		break;		
		case Diamonds:			
		this.suit = "d";			
		colour = Colour.Red;			
		break;		
		case Spades:			
		this.suit = "s";			
		colour = Colour.Black;			
		break;		
		case Hearts:			
		this.suit = "h";			
		colour = Colour.Red;			
		break;		
		}				
		faceUp = false;				
		try {
   			
			ImageIcon ii = new 
			ImageIcon(getClass().getResource("/"+directory + cardFile(suit, value)));			
			im = ii.getImage();		
			}catch(Exception e) {
   			
			System.err.println("Error: " + e.getMessage()+"lalala");		
			}	
			}   	

	private String cardFile(Suit s, int val) {
   //返回卡片对应图片的文件名		
		char ch;				
		if (val < 1 || val > 13)			
		throw new IllegalArgumentException("Bad Card Number");				
		if(s == Suit.Clubs) {
   			
		ch = 'c';		
		}else if(s == Suit.Hearts) {
   			ch = 'h';		}else if(s == Suit.Spades) {
   			ch = 's';		}else if(s == Suit.Diamonds) {
   			ch = 'd';		}		else throw new IllegalArgumentException("Bad Card Suit");				if(val < 10)			return "/0" + val + ch + extension;		else			return "/" + val + ch + extension;	} 	public Image getCardImage() {
   		return im;	}  	

	public boolean isFaceUp() {
   //是否为正面		
	return faceUp;	}   	

	public Colour getColour() {
   		
	return colour;	}   	

	@Override	
	public String toString() {
   		
	return value + " of " + suit ;	}		

	public static Image getFoundationBase(int suit) {
   //获取牌的花色信息,,空牌		
	ImageIcon ii = new ImageIcon(				Card.class.getResource("/"+directory + "/" + fpBaseFilename + suit + extension));		
	Image image = ii.getImage();		
	return image;	} 	

	public static Image getCardOutline() {
   //获取空白的卡牌图像		
	ImageIcon ii = new ImageIcon(				
	Card.class.getResource("/"+directory + "/" + cardOutlineFilename + extension));		
	Image image = ii.getImage();		
	return image;	}  	

	public static Image getCardBack() {
   //返回盖着的牌的图像		
	ImageIcon ii = new ImageIcon(Card.class.getResource("/"+directory + "/" + cardBackFilename + extension));		
	Image image = ii.getImage();		
	return image;	}   	

	public int getValue() {
   		
	return value;	}   	

	public String getSuit() {
   		
	return suit;	}   	

	public void showFace() {
   		
	faceUp = true;	} }

Pile.java

package solitaire; 
import java.util.EmptyStackException;
import java.util.Stack; 
import javax.swing.JPanel; 
public abstract class Pile extends JPanel {
   //牌堆基类	
//牌堆类
	protected int x, y;//牌堆放置的位置	
	protected Stack<Card> cards;//用堆栈来存储牌堆里的卡片 	
	public Pile(int x, int y) {
   		
		super.setLocation(x, y);//设置面板的位置		
		cards = new Stack<>()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值