import java.util.Random;

public class Solution {
	/* You may need to define static semaphore or other variables here. */
	/* Declaring them static makes them globally accessible. */
	static final int numShowers = 3;
	static final int male = 1;
	static final int female = 2;
	
	public static Semaphore shower; // Controls access to showers.
	public static Semaphore washroom; // Prevents cross gender entry. 
	public static Semaphore queue; // Makes people wait in a queue outside.
	public static Semaphore mutex; // Access to shared variables.
	public static Semaphore showerMutex; // To set showerId.
	
	static boolean showerOccupied[];
	public static int numPeople;
	public static int gender;
	public static boolean waiting;
	
  	public static void main (String args[]) {
		int arrivals = 0;
		
		try {
			arrivals = Integer.parseInt(args[0]);
		}
		catch (Exception e) {
			System.out.println("Usage: java Solution <number of arrivals>");
			System.exit(0);
		}
		
		/* You may need to define and initiate semaphores or other variables here. */
		showerOccupied = new boolean[numShowers];
		for (int i=0; i<numShowers; i++)
			showerOccupied[i] = false;
		numPeople = 0;
		gender = 0;
		waiting = false;
		
		shower = new Semaphore(3);
		washroom = new Semaphore(0);
		queue = new Semaphore(1);
		mutex = new Semaphore(1);
		showerMutex = new Semaphore(1);
		
		/* A man or a woman is generated randomly after every 1 second. */
		for (int i=0; i<arrivals; i++) {
			Random rand = new Random();
			
			if (rand.nextFloat() < 0.7) {
				Man man = new Man("M" + i);
				System.out.println("Man "+i+" enters system.");
				man.start();
			}
			else {
				Woman woman = new Woman("W" + i);
				woman.start();
				System.out.println("Woman "+i+" enters system.");
			}
			
			try {
				Thread.sleep (1000);
			}
			catch (InterruptedException e) {
				System.out.println("Fatal Error. Exiting.......");
				System.exit(0);
			}
		}
	}
	
	/* The person occupies the shower for a random amount of time between 0 and 1.5 seconds. */
	public static void shower (String personId) {
		showerMutex.enter();
		int showerId = -1;
		for (int i=0; i<numShowers; i++) {
			if (!showerOccupied[i]) {
				showerId = i;
				showerOccupied[showerId] = true;
				break;
			}
		}
		showerMutex.exit();
		
		System.out.println(personId + " enters shower " + showerId + ".");

		try {
			Random rand = new Random();
			Thread.sleep((long)(rand.nextFloat() * 3000));
		}
		catch (InterruptedException e) {
			System.out.println("Fatal Error. Exiting.......");
			System.exit(0);
		}		

		System.out.println(personId + " exits shower " + showerId + ".");
		
		showerMutex.enter();
		showerOccupied[showerId] = false;
		showerMutex.exit();
	}
}

class Man extends Thread {
	String id;
	
	public Man (String id) {
		this.id = new String(id);

		/* You may need to define and initiate semaphores or other variables here. */
	}
	
	public void run () {
		/* Your code for man goes here. */
		
		Solution.queue.enter(); // wait in the queue.
		
		Solution.mutex.enter();
		if (Solution.gender == Solution.female) {
			Solution.waiting = true;
			Solution.mutex.exit();
			
			Solution.washroom.enter(); // wait for females to leave.

			Solution.mutex.enter();
			Solution.waiting = false;
		}
		Solution.numPeople++;
		Solution.gender = Solution.male;
		Solution.mutex.exit();
		
		Solution.queue.exit(); // leave queue and enter washroom.
		
		Solution.shower.enter();
		Solution.shower(id);
		Solution.shower.exit();	
		
		Solution.mutex.enter();
		Solution.numPeople--;
		if (Solution.numPeople == 0) {
			Solution.gender = -1;
			if (Solution.waiting) {
				Solution.washroom.exit(); // allow waiting person to enter.
			}
		}
		Solution.mutex.exit();
	}
}

class Woman extends Thread {
	String id;
	
	public Woman (String id) {
		this.id = new String(id);

		/* You may need to define and initiate semaphores or other variables here. */
	}
	
	public void run () {
		/* Your code for woman goes here. */

		Solution.queue.enter(); // wait in the queue.
		
		Solution.mutex.enter();
		if (Solution.gender == Solution.male) {
			Solution.waiting = true;
			Solution.mutex.exit();
			
			Solution.washroom.enter(); // wait for females to leave.

			Solution.mutex.enter();
			Solution.waiting = false;
		}
		Solution.numPeople++;
		Solution.gender = Solution.female;
		Solution.mutex.exit();
		
		Solution.queue.exit(); // leave queue and enter washroom.
		
		Solution.shower.enter();
		Solution.shower(id);
		Solution.shower.exit();	
		
		Solution.mutex.enter();
		Solution.numPeople--;
		if (Solution.numPeople == 0) {
			Solution.gender = -1;
			if (Solution.waiting) {
				Solution.washroom.exit(); // allow waiting person to enter.
			}
		}
		Solution.mutex.exit();
	}
}