欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA CARD实现扫雷AI程序

程序员文章站 2024-03-23 22:11:04
...

beginning

这学期的JAVA智能卡课期末作业居然是叫我们自己做一个能自动扫雷的AI程序,OMG,上网搜了一下,其实网上java的智能卡代码挺多的,但是我们毕竟是智能卡,还是有一点点不一样的,所以把代码在这里码出来。

设计需求分析

老师给的棋盘还是非常简单的,大概相当于系统游戏中的初级难度,所以也不需要网上的那些高级策略,所以只采用了最基本的两条策略。
JAVA CARD实现扫雷AI程序

APDU指令表

JAVA CARD实现扫雷AI程序

完整代码


/**

 * 
 */
package minesweep;

import javacard.framework.Applet;

import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.APDU;
import javacard.framework.Util;

/**
 * @author Administrator
 *
 */
public class SweepAI extends Applet {
	
	byte [] checkerboard=new byte[128];
	byte [] out=new byte[4];
	byte [] studentID={32,30,31,36,32,31,31,30,30,32};
	byte [] name={0x06,(byte) 0xD5,(byte) 0xC5,(byte) 0xD0,(byte) 0xA3,(byte) 0xD3,(byte) 0xEF};
	short Sidelength,bufr,mineset;
	short location=0,dark=0,flag=0,allflag=0,CF=1;
	short locationX=1,locationY=1;
	short maxsize;
	
	
	public  class Stack {
	    protected short MAX_DEPTH = 8;
	    protected short depth = 0;
	    protected byte[] stack = new byte[MAX_DEPTH];
	    protected void push(short n) {stack[depth++] = (byte) n;}

	    protected short pop() {return stack[--depth];}
	}
	 Stack fstack=new Stack();
	 Stack ostack=new Stack();
	 Stack rstack=new Stack();

	
	public static void install(byte[] bArray, short bOffset, byte bLength) {
		// GP-compliant JavaCard applet registration
		new SweepAI().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
	}
	

final static byte MS_CLA =(byte)0x00;
	

	//INS

	public void process(APDU apdu) {
		// Good practice: Return 9000 on SELECT
		if (selectingApplet()) {	
			return;
		}
		apdu.setIncomingAndReceive();
		byte[] buf = apdu.getBuffer();
	
		if(buf[ISO7816.OFFSET_CLA]!=MS_CLA)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		switch (buf[ISO7816.OFFSET_INS]) {
		case (byte) 0x00:
			break;
		case (byte) 0x81:
			Util.arrayCopyNonAtomic(studentID, (short)0, buf, (short)0, (short)10);
			apdu.setOutgoingAndSend((short)0,(short)10);
			return;
		case (byte) 0x82:
			Util.arrayCopyNonAtomic(name, (short)0, buf, (short)0, (short)7);
			apdu.setOutgoingAndSend((short)0,(short)7);
			return;
		case (byte) 0x51:
			Sidelength=buf[ISO7816.OFFSET_P1];
			mineset=buf[ISO7816.OFFSET_P2];
			maxsize=(short)(Sidelength*Sidelength);
		    Util.arrayCopyNonAtomic(buf,ISO7816.OFFSET_CDATA, checkerboard, (short)0, buf[ISO7816.OFFSET_LC]);
			
		    if(checkerboard[location]==0x11){
		    	out[0]=03;
	    		out[1]=00;
	    		CF=1;
	    		Util.arrayCopyNonAtomic(out, (short)0, buf, (short)0, (short)2);
	    		apdu.setOutgoingAndSend((short)0,(short)2);
	    		return;
		    }
		    else if(CF==1){CF=0;openrandom(apdu);}
		    else if(fstack.depth>0){doflag(apdu);}			//待插旗栈不为空则继续插旗操作
		    else if(ostack.depth>0){doopen(apdu);}		//待翻开栈不为空则继续翻开操作
		    else if(allflag==mineset){          //判断是否胜利
		    	for(location=0;location<maxsize;location++){
		    		if(checkerboard[location]==0x09){
		    		out[0]=01;
		    		out[1]=(byte) location;

		    		Util.arrayCopyNonAtomic(out, (short)0, buf, (short)0, (short)2);
		    		apdu.setOutgoingAndSend((short)0,(short)2);
		    		return;}
		    	}
	    		out[0]=04;
				out[1]=00;	
				CF=1;
				Util.arrayCopyNonAtomic(out, (short)0, buf, (short)0, (short)2);
				apdu.setOutgoingAndSend((short)0,(short)2);
}
				
					
		    else zhixing(Sidelength,checkerboard,apdu);		//执行遍历棋盘操作
			return;
		default:
			// good practice: If you don't know the INStruction, say so:
			ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
		}
		
}
	
	private void zhixing(short Slength,byte [] boardinfo,APDU apdu){
		for(location=0;location<maxsize;location++){
			if(boardinfo[location]<=8 && boardinfo[location]>0){
			setlocationXY(location);
			if(boardinfo[location]!=0x00 |boardinfo[location]!=0x10)
			{judge(location,boardinfo,Slength);
			  if(dark!=0){
				if(boardinfo[location]==dark+flag)
				{flagA();doflag(apdu);clrrstate();;break;}
				if(boardinfo[location]==flag)    
				{openA();doopen(apdu);clrrstate();;break;}
				clrrstate();
			  }
			}
		}
			
			if(location==maxsize-1){
				openrandom(apdu);return;
				}
		}
}
		
	
	private void clrrstate() {
		// TODO Auto-generated method stub
		for(;rstack.depth>0;){rstack.pop();}
		dark=0;
		flag=0;
	}

	private void setlocationXY(short n){
		locationX=(short) (n/Sidelength+1);
		locationY=(short) (n%Sidelength+1);
	}
	
	private void judge(short locat,byte [] info,short size){
//判断周围的格子情况
		if(locationX-1>0 && locationY-1>0 && locationX-1<=size && locationY-1<=size){
			if(info[locat-size-1]==0x09)
			{dark=(short) (dark+1);rstack.push((short)(locat-size-1));}
			else if(info[locat-size-1]==0x10){flag=(short) (flag+1);}
		
		}
		if(locationX-1>0 && locationY>0 && locationX-1<=size && locationY<=size ){
			if(info[locat-size]==0x09)
			{dark=(short) (dark+1);rstack.push((short)(locat-size));}
			else if(info[locat-size]==0x10){flag=(short) (flag+1);}
		}
		if(locationX-1>0 && locationY+1>0&& locationX-1<=size && locationY+1<=size){
			if(info[locat-size+1]==0x09)
			{dark=(short) (dark+1);rstack.push((short)(locat-size+1));}
			else if(info[locat-size+1]==0x10){flag=(short) (flag+1);}
		}
		if(locationX>0 && locationY-1>0  && locationX<=size && locationY-1<=size){
			if(info[locat-1]==0x09)
			{dark=(short) (dark+1);rstack.push((short)(locat-1));}
			else if(info[locat-1]==0x10){flag=(short) (flag+1);}
		}
		if(locationX>0 && locationY+1>0  && locationX<=size && locationY+1<=size){
			if(info[locat+1]==0x09)
			{dark=(short) (dark+1);rstack.push((short)(locat+1));}
			else if(info[locat+1]==0x10){flag=(short) (flag+1);}
		}
		if(locationX+1>0 && locationY-1>0&& locationX+1<=size && locationY-1<=size){
			if(info[locat+size-1]==0x09)
			{dark=(short) (dark+1);rstack.push((short)(locat+size-1));}
			else if(info[locat+size-1]==0x10){flag=(short) (flag+1);}
		}
		if(locationX+1>0 && locationY>0 && locationX+1<=size && locationY<=size ){
			if(info[locat+size]==0x09)
			{dark=(short) (dark+1);rstack.push((short)(locat+size));}
			else if(info[locat+size]==0x10){flag=(short) (flag+1);}
		}
		if(locationX+1>0 && locationY+1>0&& locationX+1<=size && locationY+1<=size){
			if(info[locat+size+1]==0x09)
			{dark=(short) (dark+1);rstack.push((short)(locat+size+1));}
			else if(info[locat+size+1]==0x10){flag=(short) (flag+1);}
		}
		
	}
	
	
	private void  openA(){
		//为m位置周围所有的09做待翻开标记
		for(;rstack.depth>0;){bufr=rstack.pop();ostack.push(bufr);}
	}

	private void  flagA(){
		//为m位置周围所有的09做待插旗标记
		for(;rstack.depth>0;){bufr=rstack.pop();fstack.push(bufr);}
	}
	
	private void doopen(APDU apdu){
	
		byte[]buffer=apdu.getBuffer();
		out[0]=01;
		out[1]=	(byte) ostack.pop();

		Util.arrayCopyNonAtomic(out, (short)0, buffer, (short)0, (short)2);
		apdu.setOutgoingAndSend((short)0,(short)2); 
	}
	
	private void doflag(APDU apdu){
		allflag=(short) (allflag+1);
		byte[]buffer=apdu.getBuffer();
		out[0]=02;
		out[1]=	(byte) fstack.pop();
		
		Util.arrayCopyNonAtomic(out, (short)0, buffer, (short)0, (short)2);
		apdu.setOutgoingAndSend((short)0,(short)2); 	
		return;
	}
	
	private void  openrandom(APDU apdu){
		//翻开一个未翻开的
		short m=0;	
		location=0;
	
		for(m=0;m<maxsize;m++){
			if(checkerboard[m]==0x09){		
			byte[]buffer=apdu.getBuffer();
			out[0]=01;
			out[1]=	(byte)m;
			Util.arrayCopyNonAtomic(out, (short)0, buffer, (short)0, (short)2);
			apdu.setOutgoingAndSend((short)0,(short)2); 	
			break;}
		}
	}
}

总结

使用卡模拟器的时候运行的速度非常快,使用读卡器的时候运行速度大幅度下降,开始在遍历棋盘的时候没有加入判断是否为非暗格,结果第一步执行了足足41秒,加入判断后直接缩短到2秒,还是可以的。

在较大棋盘较少雷数下的表现还是不错的。