/*
 * tchess.java (Triangle Chess)
 * 
 * written by F.Camel 2002/01/10
 * ( sorry, the code is very terrible )
 */
import java.lang.*;
import java.io.*;
import java.util.*;
import java.net.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Image;


public class tchess extends JApplet
{
	//
	// min-max game tree
	//
	boolean obj[] = new boolean[15];
	int maxlen;
	boolean lastLose;
	boolean comFirst;
	int randomSteps;

	int state;

	int willSet[] = new int[5];
	//
	// GUI
	// 
	JButton b1 = new JButton("button test 1");
	JButton b2 = new JButton("button test 2");
	JTextField txt = new JTextField(30);
	//TextArea txt = new TextArea("lala", 2, 40);
	// checkboxs
	Checkbox cb[] = new Checkbox[5];
	CheckboxGroup cbg = new CheckboxGroup();
	Checkbox first = new Checkbox("You First", true);
	Checkbox rule = new Checkbox("Get Last Lose", true);
	// buttons
	Button start = new Button("New Game");
	// labels
	myLabel oo[] = new myLabel[15];
	// list
	java.awt.List list = new java.awt.List(5, false);
	// Image Icon
	ImageIcon live = null;
	ImageIcon dead = null;
	// data for Playing
	int head=-1, tail=-1;	// user pressed

	// toolkit for encode/decode
	// [Begin]
	int myabs(int n)
	{
		return n > 0 ? n : -n;
	}

	boolean islegal(int sx, int sy, int ex, int ey)
	{
		int dx = myabs(sx - ex);
		int dy = myabs(sy - ey);
		return (dx <= maxlen && dy <= maxlen) && (sx==ex || sy==ey || sx-ex==sy-ey);
	}

	int n2xy(int n)
	{
		int begin[] = { 0, 1, 3, 6, 10, 15 };
		int i;

		for (i=1; i<=5; i++)
			if (n < begin[i])
				return i-1 + (n-begin[i-1])*10;	// x*10 + y
		return -1;
	}

	int xy2n(int x, int y)
	{
		int begin[] = { 0, 1, 3, 6, 10 };
		int i;

		return begin[y] + x;
	}

	boolean isLive(int n, int state)
	{
		return ((1<<n) & state) != 0;
	}

	int unLive(int n, int state)
	{
		return state - (1<<n);
	}
	// [End]
	

	// start / end /state
	int legalMove(int s, int e, int state)
	{
		int sx, sy, ex, ey;
		int wx, wy;
		int t, i, j;

		t = n2xy(s);
		sx = t / 10;
		sy = t % 10;
		t = n2xy(e);
		ex = t / 10;
		ey = t % 10;
		if (islegal(sx, sy, ex, ey) == false)
			return -1;
		willSet[0] = xy2n(sx, sy);
		if (isLive(willSet[0], state) == false)
			return -1;
		t = 1;

		wx = sx < ex ? 1 : -1;
		wy = sy < ey ? 1 : -1;
		if (sx != ex || sy != ey) {
			i = 0;
			if (sx != ex)
				i = myabs(sx-ex);
			else if (sy != ey)
				i = myabs(sy-ey);
			for (; i>0; i--) {
				if (sx != ex)
					sx += wx;
				if (sy != ey)
					sy += wy;
				willSet[t++] = xy2n(sx, sy);
				if (isLive(willSet[t-1], state) == false)
					return -1;
			}
		}
		for (i=0; i<t; i++) {
			state = unLive(willSet[i], state);
		}
		return state;
	}

	int win[] = new int[(1<<15)];
	int child[] = new int[(1<<15)];
	int go(int mystate, int dep)
	{
		int tmp;
		int tState;
		int i, j, k;
		int x, y;

		if (win[mystate] != 0) {
			return win[mystate];
		} else if (mystate == 0) {
			if (lastLose)
				return 1;
			else
				return -1;
		}
		for (i=0; i<15; i++)
			for (j=i; j<15; j++) {
				tmp = legalMove(i, j, mystate);
				if (tmp < 0)
					continue;
				child[mystate] = tmp;
				if ((k=go(tmp, dep+1)) < 0) {
					win[mystate] = 1;
					return 1;
				}
			}
		win[mystate] = -1;
		return -1;
	}
	
	void setupGame()
	{
		int i;

		state = (1<<15) - 1;
		maxlen = list.getSelectedIndex();
		for (i=4; i>=0; i--)
			if (cb[i].getState()) {
				randomSteps = i;
				break;
			}
		lastLose = rule.getState();
		comFirst = ! first.getState();

		for (i=(1<<15)-1; i>=0; i--)
			win[i] = 0;

		//
		// computer play
		//
		if (comFirst) {
			if (randomSteps > 0) {
				randomSteps--;
				state -= 1;
				oo[0].setIcon(dead);
			} else {
			if (go(state, 0) > 0) {
				state = child[state];
				for (i=0; i<15; i++) {
					if (isLive(i, state) == false)
						oo[i].setIcon(dead);
				}
			} else {
				for (i=0; i<15; i++)
					if (isLive(i, state)) {
						state = unLive(i, state);
						oo[i].setIcon(dead);
						break;
					}
			}
			}
		}
	}

	public class myLabel extends JLabel
	{
		myLabel(String str)
		{
			setText(str);
		}

		myLabel(ImageIcon img)
		{
			setIcon(img);
		}

		public void setIndex(int n)
		{
			index = n;
		}

		public int getIndex()
		{
			return index;
		}

		private int index;
	}
	
	public class BL implements ActionListener
	{
		public void actionPerformed(ActionEvent e)
		{
			String name = ((Button)e.getSource()).getLabel();
			txt.setText(name);
		}
	}
	// OO's Listener
	public class OOL implements MouseListener
	{
		public void mouseClicked(MouseEvent e){}
		public void mousePressed(MouseEvent e)
		{
			myLabel tmp = (myLabel)e.getSource();

			head = tmp.getIndex();
		}

		public void mouseReleased(MouseEvent e)
		{
			int sx, sy, ex, ey;
			int i, j, t, wx, wy;	//wayx, wayy

			if (tail == -1)
				return;
			t = n2xy(head);
			sx = t / 10;
			sy = t % 10;
			t = n2xy(tail);
			ex = t / 10;
			ey = t % 10;
			if (islegal(sx, sy, ex, ey) == false) {
				txt.setText("Illegal Action");
				return;
			}

			willSet[0] = xy2n(sx, sy);
			if (isLive(willSet[0], state) == false) {
				txt.setText("Illegal Action");
				return ;
			}
			t = 1;

			wx = sx < ex ? 1 : -1;
			wy = sy < ey ? 1 : -1;
			if (sx != ex || sy != ey) {
				i = 0;
				if (sx != ex)
					i = myabs(sx-ex);
				else if (sy != ey)
					i = myabs(sy-ey);
				for (; i>0; i--) {
					if (sx != ex)
						sx += wx;
					if (sy != ey)
						sy += wy;
					willSet[t++] = xy2n(sx, sy);
					if (isLive(willSet[t-1], state) == false) {
						txt.setText("Illegal Action");
						return ;
					}
				}
			}

			for (i=0; i<t; i++) {
				oo[ willSet[i] ].setIcon(dead);
				state = unLive(willSet[i], state);
			}

			if (state == 0) {
				if (lastLose) {
					txt.setText("You Lose");
				} else {
					txt.setText("You Win");
				}
				return;
			}
			//
			// computer play
			//
			if (randomSteps-- <= 0 && go(state, 0) > 0) {
				state = child[state];
				for (i=0; i<15; i++) {
					if (isLive(i, state) == false)
						oo[i].setIcon(dead);
				}
			} else {
				for (i=0; i<15; i++)
					if (isLive(i, state)) {
						state = unLive(i, state);
						oo[i].setIcon(dead);
						break;
					}
			}
			if (state == 0) {
				if (lastLose) {
					txt.setText("You Win");
				} else {
					txt.setText("You Lose");
				}
				return;
			}
		}

		public void mouseEntered(MouseEvent e)
		{
			myLabel tmp = (myLabel)e.getSource();

			tail = tmp.getIndex();
		}

		public void mouseExited(MouseEvent e)
		{
			myLabel tmp = (myLabel)e.getSource();

			tail = -1;
		}
	}

	BL al = new BL();	//action listern
	OOL ool = new OOL();
	public void init()
	{
		int i, j, k, t;

		// init Image
		URL img_url = null;
		URL img_url2 = null;
											
		try {
			img_url = new URL(getCodeBase(), "live.gif");
			if (img_url != null)
				live = new ImageIcon(img_url);
			img_url2 = new URL(getCodeBase(), "dead.gif");
			if (img_url2 != null)
				dead = new ImageIcon(img_url2);
			if (live == null || dead == null)
				txt.setText("cannot load image");
		} catch (Exception e) {
		}

		// Main Layout
		Container cp = getContentPane();
		Box bn = Box.createHorizontalBox();	// Level bar
		Box bw = Box.createVerticalBox();	// select first, rule, start
		Box bes = Box.createVerticalBox();	// include be[]
		Box be[] = new Box[5];
		Box bs = Box.createHorizontalBox();	// message

		// North
		bn.add(Box.createVerticalGlue());
		bn.add(new JLabel("  Level        "));
		cb[4] = new Checkbox("easy", cbg, false);
		cb[3] = new Checkbox("normal", cbg, false);
		cb[2] = new Checkbox("hard", cbg, true);
		cb[1] = new Checkbox("nightmare", cbg, false);
		cb[0] = new Checkbox("hell", cbg, false);
		for (i=4; i>=0; i--)
			bn.add(cb[i]);
		cp.add(BorderLayout.NORTH, bn);
		// East
		bes.add(Box.createVerticalGlue());
		for (k=0; k<5; k++) {
			be[k] = Box.createHorizontalBox();
			for (i=k*(k+1)/2; i<(k+1)*(k+2)/2; i++) {
				if (live != null)
					oo[i] = new myLabel(live);
				else
					oo[i] = new myLabel("O");
				oo[i].setIndex(i);
				oo[i].addMouseListener(ool);
				be[k].add(oo[i]);
				be[k].add(Box.createVerticalBox().add(new JLabel("     ")));
			}
			bes.add(be[k]);
			bes.add(Box.createHorizontalBox().add(new JLabel(" ")));
		}
		bes.add(Box.createVerticalGlue());
		bes.add(Box.createVerticalGlue());
		bes.add(Box.createVerticalGlue());
		// West
		start.addActionListener(new ActionListener()	// !!! New SYNTAX to learn
				{
					public void actionPerformed(ActionEvent e)
					{
						int i;

						for (i=0; i<15; i++)
							oo[i].setIcon(live);
						setupGame();
						txt.setText("New Game");
					}
				});
		bw.add(first);
		bw.add(rule);
		bw.add(new JLabel("Max Cut per Round                   "));
		list.add("1");
		list.add("2");
		list.add("3");
		list.add("4");
		list.add("5");
		list.select(3);
		bw.add(list);
		bw.add(Box.createVerticalGlue());
		bw.add(start);
		bw.add(Box.createVerticalGlue());
		bw.add(Box.createVerticalGlue());
		bw.add(Box.createVerticalGlue());
		bw.add(Box.createVerticalGlue());
		bw.add(Box.createVerticalGlue());
		bw.add(Box.createVerticalGlue());
		cp.add(BorderLayout.WEST, bw);cp.add(BorderLayout.CENTER, bes);
		// South
		bs.add(txt);
		cp.add(BorderLayout.SOUTH, bs);

		//
		// prepare every arguments
		//
		setupGame();

		
	}
}
