public class HungryPhilosophers2 {
	public static void main(String argv[]) {				
		int hungryPhilosophers = Integer.parseInt(argv[0]);

		SemaphoreGroup accessForks = new SemaphoreGroup( hungryPhilosophers );
		int[] init = new int[ hungryPhilosophers ];
		for (int i=0; i< init.length; i++)
			init[i] = 1;
			
		accessForks.changeValues(init);
		
		Table table = new Table( hungryPhilosophers );
		for (int i=0; i<hungryPhilosophers; i++) {
			new Thread(new Philosopher(table, accessForks, i),""+(i+1)).start();
		} //for		
	} //main()
} //class HungryPhilosophers2

class Table {
	boolean forkInUse[];
	
	public Table(int seats)
	{
		forkInUse = new boolean[seats];
		for (int i=0; i<forkInUse.length; i++)
			forkInUse[i] = false;		
	} //constructor
	
	public int left(int i) {
		return i;
	} //left()

	public int right(int i) {
		if (i+1 < forkInUse.length)
			return (i+1);
		else
			return 0;
	} //right()
} //class Table

class Philosopher implements Runnable {
	SemaphoreGroup accessForks;
	Table table;
	int seat;
	
	public Philosopher(Table table, SemaphoreGroup accessForks, int seat) {
		this.accessForks = accessForks;
		this.table = table;
		this.seat = seat;
	} //constructor
	
	public void run() {
		int deltas[] = new int[accessForks.getNumberOfMembers()];
		
		while (true) {
			think(seat);
			deltas[table.left(seat)] = -1;
			deltas[table.right(seat)] = -1;
			accessForks.changeValues(deltas);
	
			eat(seat);
			deltas[table.left(seat)] = 1;
			deltas[table.right(seat)] = 1;
			accessForks.changeValues(deltas);
		} //loop endlessly
	} //constructor

	void think(int seat)	{
		System.out.println("Philosopher #"+Thread.currentThread().getName()+" is thinking");
		try {
			Thread.sleep( (int) (Math.random() * 20000) );
		} //try
		catch (InterruptedException ie) {
			System.out.println("An InterruptedException caught\n"+ie.getMessage());
			ie.printStackTrace();
			System.exit(1);
		} //catch()
	} //think()

	void eat(int seat){ 
		try {
			System.out.println("Philosopher #"+Thread.currentThread().getName()+" is eating");
			Thread.sleep( (int) (Math.random() * 20000) );
		} //try
		catch (InterruptedException ie) {
			System.out.println("An InterruptedException caught\n"+ie.getMessage());
			ie.printStackTrace();
			System.exit(1);
		} //catch()
		System.out.println("Philosopher #"+Thread.currentThread().getName()+" finished eating");
	} //eat()
} //class Philosopher