//
/* --------------------------------------------------------------------------------------------------------
	turing.java	チューリングマシン										ver. 1.00 (JDK 1.02)
																		ueyama@infonet.co.jp 2009.03.14
-------------------------------------------------------------------------------------------------------- */
import java.applet.*;
import java.awt.*;
import java.util.*;

public class turing extends Applet implements Runnable
{
	int			Hx;														// ヘッド表示X座標
	int			Ty=38;													// テープ表示Y座標
	int			Bx[]={18,278,308,338,398,428,458,518,748,660,660};		// ボタン表示X座標
	int			By[]={90, 90, 90, 90, 90, 90, 90, 90, 90,344,370};		// ボタン表示Y座標
	int			Kx=405;													// キー表示X座標
	int			Ky[]={154,204,240,266,292};								// キー表示Y座標
	int			Kq[]={26,8,8,2,26};										// 入力キーの数
	int			Kn=-1;													// 入力可能キー列No.
	int			Kc=-1;													// クリックされたキーNo.
	int			Tape[]=new int[512];									// テープのデータ
	int			Rt[][]=new int[256][5];									// ルール
	int			Rq=0;													// ルール数
	int			Rx=-1, Ry=-1;											// ルール表編集位置
	int			Rm=-1, Rn=-1;											// ルール表旧編集位置
	int			Td=239;													// テープの表示開始No.
	int			Rd=0;													// ルールの表示開始No.
	int			Hp;														// ヘッドの位置
	int			Hs=0;													// ヘッドの状態
	int			Ra;														// 適用されるルール No.
	int			Pn=0;													// プログラム No.
	int			Sp=0;													// 実行ステップ数
	int			Te=-1;													// 編集テープNo.
	int			Dx=-1,Dy=-1;											// ドラッグの処理用
	int			Mc=-1;													// 0:Head, 1:Tape, 2:Btn, 3:Tbl, 4:Rule
	int			Mx=0;
	int			Wait=256;
	int			Bgc;
	Thread		th=null;
	boolean		Run=false;
	boolean		Err=false;
	TextArea	Rtxt=new TextArea(3,30);
	Image		Img;
		//	Ar[n][0]: ルールNo.  [1]: ルール表示開始No.  [2]: テープ表示開始No.  [3]: ヘッド位置  [4]: テープデータ
	int			Ar[][]=new int[256][5];									// 履歴データ
		//	Rule[0]: テープデータ件数 (8bit), テープの表示開始位置 (8bit), ヘッドの位置 (8bit), 状態 (8bit)
		//	Rule[1]〜 テープデータ:  テープ位置 (任意), データ (8bit)
		//	Rule[] 以後ルールデータ: 状態 (8), 入力 (4), 出力 (4), 移動 (4), 次の状態 (8bit)
		//	Rule[] 最後  負の数
	int			Rule[][]=new int[5][256];
	String		Rstr[]={"03efff00,fd01,fe00,ff01,0061101,0001101,0010000,0166019,0100101,0111101",	// インクリメント
						"04efff00,fc01,fd00,fe01,ff01,0001000,0010000,0066101,0166019,0177101",		// 否定
						"0ce9ff00,f301,f401,f500,f601,f701,f800,fa00,fb01,fc00,fd01,fe01,ff01,0066108,0002001,0013003,0077108,0166002,0100001,0111001,0262106,0202106,0213106,0222002,0233002,0366004,0300003,0311003,0463106,0403106,0412005,0422004,0433004,0561106,0501106,0510005,0666107,0677106,0700107,0711107,0722000,0733000,0866009,0877108,096600a,0900109,0911109,0926009,0936009,0a6610b,0a0010b,0a1110b,0a2000a,0a3100a,0b66019,0b7710b",		// 加算
						"08eafc00,f401,f501,f600,f701,f900,fa01,fb01,fc00,0001000,0010000,0066101,0166002,0177101,0261103,0201103,0210002,0300103,0311103,0366004,046610c,0402005,0413007,047710c,0566006,0500005,0511005,066210a,060210a,061310a,0622006,0633006,0766008,0700007,0711007,086310a,080310a,0812009,0822008,0833008,096110a,090110a,0910009,0a6610b,0a7710a,0b0010b,0b1110b,0b22004,0b33004,0c6600d,0c7710c,0d6600e,0d0010d,0d1110d,0d2600d,0d3600d,0e6610f,0e0010f,0e1110f,0e2000e,0e3100e,0f66010,0f7710f,1066111,1077010,1116112,1266019,1277112"};		// 減算

	public void init()													// 初期設定
	{
		int i,j;
		String q;
		String bg=getParameter("bgcolor");
		Bgc=Integer.valueOf(bg,16).intValue();
		setBackground(new Color(Bgc)); 
		MediaTracker mt=new MediaTracker(this);
		Img=getImage(getCodeBase(), getParameter("figure"));
		setLayout(null);
		add(Rtxt);
		Rtxt.reshape(405,345,240,48);
		mt.addImage(Img, 0);
		try
		{
			mt.waitForID(0);
		}
		catch(InterruptedException e){};
		for(i=0;i<4;i++)												// ルールデータの設定
		{
			StringTokenizer st=new StringTokenizer(Rstr[i],",");
			for(j=0; st.hasMoreTokens(); j++)
			{
				q=st.nextToken();
				Rule[i][j]=Integer.valueOf(q,16).intValue();			// ルール
			}
		}
		rule_init(Pn);
	}

	public void rule_init(int c)										// ルールの初期化
	{
		int i,m,n;
		m=Rule[c][0];
		Hs=m%256; m/=256;												// ヘッドの初期状態
		Hp=m%256; m/=256;												// ヘッドの位置
		Td=m%256;														// テープの表示開始位置
		n=m/=256;														// テープデータ件数
		for(i=0; i<512;i++) Tape[i]=6;									// テープのクリア
		for(i=0; i<256;i++) Rt[i][0]=-1;								// ルールのクリア
		for(i=0;i0; i++)									// ルールデータの読み込み
		{
			m=Rule[c][i+n+1];
			Rt[i][4]=m%256; m/=256;
			Rt[i][3]=m%16; m/=16;
			Rt[i][2]=m%16; m/=16;
			Rt[i][1]=m%16; m/=16;
			Rt[i][0]=m%256;
		}
		Rq=i;															// ルール数
		Sp=0; Err=false;
	}
	
	public void start()
	{
		if(th==null)
		{
			th=new Thread(this);
			th.start();
		}
	}
	
	public boolean inside(int x, int a, int b)							// マウスの位置座標チェック
	{
		return (x<=Math.max(a,b) && x>=Math.min(a,b)) ? true:false;
	}

	public void dsp_g(int x, int y, int m, int n, int e, int c)			// 画像の表示
	{
		int			w=0, h=0, ox=0, oy=0;
		Graphics	gx=getGraphics();
		switch(c)
		{
			case  0: w= 15; h= 11; ox=  66; oy= 24; break;				// キー  状態用数字
			case  1: w=  8; h= 13; ox= 456; oy= 24; break;				// キー  テープ用記号
			case  2: w= 26; h= 20; ox=   0; oy= 38; break;				// キー
			case  4: w= 33; h= 38; ox=   0; oy=  0; break;				// ヘッド
			case  5: w= 25; h= 22; ox= 520; oy= 70; break;				// テープ
			case  6: w= 18; h= 12; ox=  66; oy=  0; break;				// 状態用数字
			case  7: w= 60; h= 13; ox=  52; oy= 57; break;				// "状態  入力  出力  移動  次の状態"
			case  8: w= 26; h= 23; ox=  52; oy= 70; break;				// ボタン
			case  9: w= 59; h= 16; ox=  52; oy=116; break;				// ルール表の編集表示
			case 10: w= 24; h=  4; ox= 351; oy= 63; break;				// 速度表示用ドット
			case 11: w=104; h= 15; ox= 757; oy=  0; break;				// ポップアップメニュー選択項目
			case 12: w= 83; h= 15; ox= 757; oy=  0; break;				// ポップアップメニュー選択項目
			case 13: w=106; h= 98; ox= 545; oy=  0; break;				// ポップアップメニュー
			case 14: w= 33; h=  9; ox=   0; oy=116; break;				// ボタン説明
		}
		gx.clipRect(x, y, w, h);
		if(e>0) gx.clearRect(x, y, w, h);
		gx.drawImage(Img,x-(ox+m*w),y-(oy+n*h),this);
		gx.dispose();
	}
	
	public void paint(Graphics g)										// 画面の表示
	{
		int i,j,m;
		g.clearRect(0, 0, size().width, size().height);
		g.setColor(new Color (0x000000));
		for(i=0; i<34; i++) g.drawRect(i*24-12,Ty,24,21);				// テープの表示
		dsp_tape();														// テープデータの表示
		dsp_head();														// ヘッドの表示
		dsp_g(70,93,0,0,1,13);											// ポップアップメニューの表示
		dsp_g(72,96,0,Pn,1,12);											// メニュー選択項目の表示
		dsp_tbl();														// 表の罫線の表示
		dsp_rules();													// ルール表 の表示
		for(i=0;i<11;i++) dsp_btn(i,0);									// ボタンの表示
		for(i=0;i<9;i++) dsp_g(Bx[i]-4,118,(i==6)?9:i,0,0,14);			// ボタンの説明表示
		dsp_g(Bx[1]+Mx*10+32,84,0,0,1,10);								// 実行速度表示用ドットの表示
		for(i=0;i<5;i++) dsp_g(Kx-85+((i==4 || i==0)?15:0),Ky[i]+4,i,0,1,7);	// キーの説明の表示
		for(i=0;i<5;i++) dsp_keys(i,0);									// キーの表示
	}

	public void dsp_head()												// ヘッドの表示
	{
		Hx=(Hp-Td)*24+8;												// ヘッド表示座標
		dsp_g(Hx,0,0,0,1,4);											// ヘッドの表示
		dsp_g(Hx+7,8,Hs,0,1,6);											// ヘッドの状態の表示
	}
	
	public void dsp_tape()												// テープデータの表示
	{
		int i,m;
		for(i=0;i<32;i++)												// テープデータの表示
		{
			dsp_g(i*24+12,Ty,0,0,1,5);									// テープの表示
			m=Tape[Td+i];
			dsp_g(i*24+20,Ty+5,(m==6)?8:m,1,1,1);						// (m==6)?8:m は空白の処理
		}
	}
	
	public void dsp_rule(int m, int n)									// ルールの表示
	{
		int j=Rt[m][n], k=(Ra==m)?2:1;									// ルールNo.
		if(Rt[m][0]>=0)
		{
		if(m>Rq) dsp_g(23+n*60,172+(m-Rd)*17+1,8,k,1,1);				// 状態
		else
		{
			if(n==0 || n==4) dsp_g(23+n*60,172+(m-Rd)*17+1,j,k,1,0);	// 状態
			else if(n==3)    dsp_g(26+n*60,172+(m-Rd)*17,j+9,k,1,1);	// 移動
			else             dsp_g(26+n*60,172+(m-Rd)*17,j,k,1,1);		// 入出力
		}
		}
	}
	
	public void dsp_rules()												// ルール表 の表示
	{
		int i,j;
		Ra=-1;
		Err=false;
		for(i=0;i12)?Ra-6:0;
		for(i=0;i<13;i++) for(j=0;j<5;j++) if(i+Rd0 && Hs<25)?2:0;			break;	// Rule Clear
			case  1: m=6;  n=1; k=(Wait<4096)?0:2;				break;	// Slow
			case  2: m=3;  n=(Run)?1:0; k=(Hs==25 || Err)?2:0;	break;	// Run
			case  3: m=9;  n=1; k=(Wait>16)?0:2;				break;	// Fast
			case  4: m=0;  n=0; k=(Sp==0)?2:0;					break;	// Back
			case  5: m=6;  n=0; k=(Hs==25 || Err)?2:0;			break;	// Step
//			case  6: m=12; n=1; k=(Sp==0)?2:0;					break;	// Reset
			case  6: m=0;  n=1; k=(Sp==0)?2:0;					break;	// Reset
			case  7: m=9;  n=0; k=(Sp==0)?2:0;					break;	// Clear
			case  8: m=12; n=0; k=(Sp>0 && Hs<25)?2:0;			break;	// Tape Clear
			case  9: m=15; n=1; k=(Sp>0 && Hs<25)?2:0;			break;	// Write
			case 10: m=15; n=0; k=(Sp>0 && Hs<25)?2:0;			break;	// Read
		}
		dsp_g(Bx[i],By[i],m+((c==0)?k:c),n,1,8);						// ボタンの表示
	}

	public void dsp_key(int m, int n, int c)							// キー(1個)の表示
	{
		int j=n%13, k=n/13;
		switch(m)
		{
			case 0: dsp_g(Kx+j*30,Ky[0]+k*24,1,c,1,2);					// 状態キーの表示
					dsp_g(Kx+j*30+6,Ky[0]+k*24+4,n,0,0,0); break;		// 文字の表示
			case 1: dsp_g(Kx+n*30,Ky[1],1,c,1,2);						// 入力キーの表示
					dsp_g(Kx+n*30+10,Ky[1]+3,n,0,0,1); break;			// 文字の表示
			case 2: dsp_g(Kx+n*30,Ky[2],0,c,1,2);						// 出力キーの表示
					dsp_g(Kx+n*30+10,Ky[2]+3,n,0,0,1); break;			// 文字の表示
			case 3: dsp_g(Kx+n*30,Ky[3],0,c,1,2);						// 移動キーの表示
					dsp_g(Kx+n*30+10,Ky[3]+3,n+9,0,0,1); break;			// 文字の表示
			case 4: dsp_g(Kx+j*30,Ky[4]+k*24,0,c,1,2);					// 状態キーの表示
					dsp_g(Kx+j*30+6,Ky[4]+k*24+4,n,0,0,0); break;		// 文字の表示
		}
	}
	
	public void dsp_keys(int m, int c)									// キー(一組)の表示
	{
		int i;
		switch(m)
		{
			case 0: for(i=0;i<26;i++) dsp_key(m,i,c); break;			// 状態キーの表示
			case 1: for(i=0;i<8;i++) dsp_key(m,i,c); break;				// 入力キーの表示
			case 2: for(i=0;i<8;i++) dsp_key(m,i,c); break;				// 出力キーの表示
			case 3: for(i=0;i<2;i++) dsp_key(m,i,c); break;				// 移動キーの表示
			case 4: for(i=0;i<26;i++) dsp_key(m,i,c); break;			// 状態キーの表示
		}
	}
	
	public void dsp_tbl()												// ルール表 (罫線) の表示
	{
		int i;
		for(i=0;i<5;i++) dsp_g(i*60, 152,i,0,1,7);						// 表の見出しの表示
		Graphics gx=getGraphics();
		gx.clearRect(0,169,300,221);
		gx.setColor(new Color(0xcccccc));								// 表 (罫線) を描く
		for(i=0;i<12;i++) gx.drawLine(0,186+i*17,300,186+i*17);
		for(i=1;i<5;i++)
		{
			gx.setColor(new Color((i==2)?0:0xcccccc));
			gx.drawLine(i*60,170,i*60,390);
		}
		gx.setColor(new Color(0x000000));
		gx.drawRect(0,169,300,221);
		gx.dispose();
	}

	public void draw_rect(int x, int y, int m, int c)					// テープ、ルール表入力位置の表示
	{
		Graphics	gx=getGraphics();
		gx.setColor(new Color((c==0)?Bgc:0xff9999));					// 
		switch(m)
		{
			case 0: gx.drawRect(x,y,22,19); break;						// テープ
			case 1: gx.drawRect(x,y,58,15); break;						// ルール表
		}
		gx.dispose();
	}
	
	public void run()
	{
		int i;
		while(true)
		{
			try
			{
				th.sleep(Wait);
			}
			catch (InterruptedException e){}
			if(Run)
			{
				tur_calc();
				dsp_g(Hx,0,1,0,1,4);									// ヘッドの消去
				dsp_head();         		
				dsp_tape();												// テープデータの表示
				dsp_rules();											// ルール表 の表示
				if(Hs==25)												// 停止 (H)
				{
					Run=false;
					for(i=0;i<11;i++) dsp_btn(i,0);						// ボタンの表示
				}
			}
		}
	}
	
	public void stop()
	{
		if(th!=null)
		{
			th.stop();
			th=null;
		}
	}
	
	public void tur_calc()												// 計算の実行
	{
		int i, m=-1;
		Ar[Sp][0]=Ra;													// 履歴:ルール No.
		Ar[Sp][1]=Rd;													//       ルールの表示開始位置
		Ar[Sp][2]=Td;													//       テープの表示開始位置
		Ar[Sp][3]=Hp;													//       ヘッドの位置
		Ar[Sp][4]=Tape[Hp];												//       テープのデータ
		for(i=0; i=0) Tape[Hp]=Rt[Ra][2];									// テープデータ
		Hs=Rt[Ra][4];													// ヘッドの状態
		Hp+=(Rt[Ra][3]==0)?-1:1;										// ヘッドの位置
		Sp++;
	}
	
	public boolean mouseDown(Event e, int mx, int my)					// マウスがクリックされたときの処理
	{
		int i, j, k, l, m=-1, n=0;
		String p,q,s;
		boolean f=false;
		Kc=-1;
		Dx=mx; Dy=my;
		if(Mc==1 && Te>=0)												// テープクリック後であれば…
		{
			draw_rect((Te-Td)*24+13,Ty+1,0,0);							// テープの編集位置表示を消す
		}
		if(Mc==3) draw_rect(Rm*60+1,170+Rn*17,1,0);						// ルール編集位置赤表示を元に戻す
		for(i=0;i<5;i++) dsp_keys(i,(i==Rx)?1:0);						// 入力キーを元に戻す
		if(inside(my,38,58))											// テープをクリック
		{
			Mc=1;
			Te=(mx+12)/24+Td-1;											// テープ編集位置
			draw_rect((Te-Td)*24+13,Ty+1,0,1);							// テープの編集位置表示
			Rx=1;
		}
		if(inside(mx,Hx,Hx+33) && my<38) Mc=0;							// ヘッドをクリック
		if(inside(mx,70,176) && inside(my,93,114))						// ポップアップメニューをクリック
		{
			Mc=4;
			Dy=my;
			dsp_g(70,93,1,0,1,13);										// ポップアップメニューの表示
			dsp_g(72,96,0,Pn,1,12);										// メニュー選択項目の表示
			for(i=0; i<5; i++) dsp_g(71,115+i*15,(i==Pn)?1:0,i,1,11);	// メニューリストの表示
		}
		if(inside(mx,71,175) && inside(my,115,190))						// メニューリストをクリック
		{
			Mc=-1;
			Pn=(my-115)/15;
			dsp_g(70,93,0,0,1,13);										// ポップアップメニューの表示
			dsp_g(72,96,0,Pn,1,12);										// メニュー選択項目の表示
			rule_init(Pn);
			dsp_g(Hx,0,1,0,1,4);										// ヘッドの消去
			dsp_head();			
			dsp_tape();													// テープデータの表示
			dsp_tbl();
			dsp_rules();												// ルール表 の表示
			for(i=0;i<11;i++) dsp_btn(i,0);								// ボタンの表示
		}
		for(m=0;m<11;m++) if(inside(mx,Bx[m],Bx[m]+26) && inside(my,By[m],By[m]+23))	// ボタンをクリック?
		{
			Mc=2;
			Rx=-1;
			switch(m)
			{
				case 0:													// ルールのクリア
					dsp_btn(m,1);
					for(i=0;i<256;i++) Rt[i][0]=-1;						// ルールのクリア
					dsp_rules();
					break;
				case 1: if(Wait<4096) {									// Slow ボタンをクリック
					Wait*=2; Mx--;				
					dsp_btn(m,1);
					dsp_g(Bx[1]+Mx*10+32,84,0,0,1,10);} break;			// ドットの表示
				case 2: if(Hs<25 && !Err) {								// RUN ボタンをクリック
					dsp_g(Bx[2],By[2],4,(Run)?1:0,1,8);					// ボタンの表示
					Run=!Run;} break;
				case 3: if(Wait>16) {									// Fast ボタンをクリック
					Wait/=2; Mx++; 
					dsp_btn(m,1);
					dsp_g(Bx[1]+Mx*10+32,84,0,0,1,10);} break;			// ドットの表示
				case 4: if(Sp>0) {Sp--;									// 戻るボタンをクリック
					Ra=Ar[Sp][0];										// 履歴:ルール No.
					Rd=Ar[Sp][1];										//       ルールの表示開始位置
					Td=Ar[Sp][2];										//       テープの表示開始位置
					Hp=Ar[Sp][3];										//       ヘッドの位置
					Hs=Rt[Ra][0];										// ヘッドの状態
					Tape[Hp]=Ar[Sp][4];									// テープのデータ
					Err=false;
					f=true;} break;
				case 5: if(Hs<25 && !Err) {								// ステップボタンをクリック
					tur_calc();											// 計算の実行
					f=true;} break;
				/*
				case 6: if(Sp>0) {										// リセットボタンをクリック
					for(i=0;i<34;i++) dsp_g(i*24-12,Ty,0,0,1,3);		// テープの表示
					for(i=0;i<24;i++) dsp_g(i*33,0,1,0,1,4);			// ヘッドの消去
					Sp=0;
					Err=false;
					f=true;} break;
				*/
				case 7: if(Sp>0) {										// クリアボタンをクリック
					rule_init(Pn);
					for(i=0; i<24; i++) dsp_g(i*33,0,1,0,1,4);			// ヘッドの消去
					Sp=0;
					Err=false;
					f=true;} break;
				case 8:
					dsp_btn(m,1);
					for(i=0; i<512;i++) Tape[i]=6;						// テープのクリア
					dsp_tape();											// テープデータの表示
					break;
				case 9:
					dsp_btn(m,1);
					for(i=0,j=0;i<512;i++) if(Tape[i]!=6) j++;
					s=Integer.toString(Hs+Hp*0x100+Td*0x10000+j*0x1000000,16);
					for(j=s.length();j<8;j++) s="0"+s;
					Rtxt.appendText(s+"\n");
					for(i=0;i<512;i++)
					{
						if(Tape[i]!=6)
						{
							s=Integer.toString(i*0x100+Tape[i],16);
							for(j=s.length();j<5;j++) s="0"+s;
							Rtxt.appendText(s+"\n");
						}
					}
					for(i=0;i170)											// ルール表をクリック
		{
			Mc=3;														// ルール表をクリック
			Rx=mx/60; Ry=(my-170)/17;
			draw_rect(Rx*60+1,170+Ry*17,1,1);							// 編集位置を赤表示
			for(i=0;i<5;i++) dsp_keys(i,(i==Rx)?1:0);					// キーの表示
		}
		if(mx>Kx && my>Ky[0] && Rx>=0)									// キーをクリック
		{
			for(i=0;i=0)
			{
				Rx++; Rx%=5;
				if(Rx==0) Ry++;
				if(Ry==13)
				{
					Rd++;
					Ry--;
					for(i=0;i<13;i++) for(j=0;j<5;j++) if(i+Rd戻る