// Arup Guha
// Solution to 2012 South East Regional D1 Problem: Funhouse
// Started Fall 2014, finished 11/21/2014

import java.util.*;

public class e {

	public static int n;
	final public static int INF = 2000000;

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);
		n = stdin.nextInt();

		// Go through each case.
		while (n != 0) {

			// Set up list for edges.
			room.allSegs = new ArrayList<seg>();

			// Read in the edge list - store both ways.
			for (int i=0; i<n; i++) {
				pt a = new pt(stdin.nextInt(), stdin.nextInt());
				pt b = new pt(stdin.nextInt(), stdin.nextInt());
				String type = stdin.next();
				room.allSegs.add(new seg(a, b, i, type));
				room.allSegs.add(new seg(b, a, i, type));
			}

			// Initialize next lists.
			setNextLists();

			// Now, form rooms.
			ArrayList<room> rooms = getAllRooms();

			// Form network flow graph.
			int[][] graph = formGraph(rooms);

			// Run flow.
			networkflow myFlow = new networkflow(graph, graph.length-2, graph.length-1);

			// Get flow and print it.
			int doubleFlow = myFlow.getMaxFlow();
			System.out.printf("%.1f\n", doubleFlow/2.0);

			// Get next case.
			n = stdin.nextInt();
		}
	}

	public static int[][] formGraph(ArrayList<room> rooms) {

		// Will store flows here - two nodes per room plus source and sink.
		int v = rooms.size();
		int[][] g = new int[2*v+2][2*v+2];

		// All flows from source and to sink.
		for (int i=0; i<v; i++) {
			if (rooms.get(i).isEntrance) g[2*v][2*i] = INF;
			if (rooms.get(i).isExit) g[2*i+1][2*v+1] = INF;
			g[2*i][2*i+1] = rooms.get(i).doubleArea();
		}

		// All other edges are doors - and doors that connect rooms are adjacent from how they were read in.
		for (int i=0; i<room.allSegs.size(); i+=2) {
			if (room.allSegs.get(i).type.equals("D") && room.allSegs.get(i+1).type.equals("D")) {
				if (room.allSegs.get(i).origID == room.allSegs.get(i+1).origID) {
					int v1 = room.allSegs.get(i).roomNumber;
					int v2 = room.allSegs.get(i+1).roomNumber;
					g[2*v1+1][2*v2] = INF;
					g[2*v2+1][2*v1] = INF;
				}
			}
		}

		return g;
	}

	// Puts together list of all rooms using sharpest turns.
	public static ArrayList<room> getAllRooms() {

		// Store rooms here.
		ArrayList<room> roomList = new ArrayList<room>();
		int roomIndex = 0;

		// Keeps track of segments used in rooms formed.
		boolean[] used = new boolean[2*n];

		// Loop through finding edges that haven't been used in rooms yet.
		for (int i=0; i<2*n; i++) {

			if (used[i]) continue;

			String type = room.allSegs.get(i).type;

			// We only build rooms off doors, which always belong to exactly two rooms.
			if (!type.equals("D")) continue;
			room theRoom = getRoom(i, roomIndex);
			theRoom.updateUsed(used);
			roomList.add(theRoom);
			roomIndex++;
		}

		// Add rooms with only entrances AND exits.
		for (int i=0; i<2*n; i+=2) {

			// Can't build off these.
			if (used[i] || used[i+1]) continue;

			String type = room.allSegs.get(i).type;

			// Only try E's or X's/
			if (type.equals("E") || type.equals("X")) {

				// Temporarily build the two possible rooms.
				room leftRoom = getRoom(i, -1);
				room rightRoom = getRoom(i+1, -1);
				if (leftRoom.hasDoor()) continue;
				if (rightRoom.hasDoor()) continue;

				// Pick the right one, fill out the number and add it.
				if (leftRoom.doubleArea() < rightRoom.doubleArea()) {
					leftRoom.setRoomNumber(roomIndex);
					leftRoom.updateUsed(used);
					roomIndex++;
					roomList.add(leftRoom);
				}
				else {
					rightRoom.setRoomNumber(roomIndex);
					rightRoom.updateUsed(used);
					roomIndex++;
					roomList.add(rightRoom);
				}
			}
		}

		return roomList;
	}

	// Returns the room starting at curEdge and sets each edge in the list to belong to roomIndex,
	// if roomIndex >= 0.
	public static room getRoom(int curEdge, int roomIndex) {

		// Set up list of edges for this room.
		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(curEdge);
		if (roomIndex >= 0) room.allSegs.get(curEdge).roomNumber = roomIndex;
		pt startPt = room.allSegs.get(curEdge).ptArray[0];
		pt nextPt = null;

		// Continue adding until we get back to our original segment.
		int nextSeg = room.allSegs.get(curEdge).nextIndex;
		while (!startPt.equals(nextPt)) {
			list.add(nextSeg);
			if (roomIndex >= 0) room.allSegs.get(nextSeg).roomNumber = roomIndex;
			nextSeg = room.allSegs.get(nextSeg).nextIndex;
			nextPt = room.allSegs.get(nextSeg).ptArray[0];
		}
		return new room(list);
	}

	// Sets the next segment for each segment.
	public static void setNextLists() {

		// Find each neighbor of seg[i], in counter-clockwise order.
		for (int i=0; i<2*n; i++) {

			// Go through each candidate neighbor.
			for (int j=0; j<2*n; j++) {

				// Can't meet itself.
				if (room.allSegs.get(i).origID == room.allSegs.get(j).origID) continue;

				// Get meeting pt.
				if (room.allSegs.get(i).meet(room.allSegs.get(j))) {
					int nextI = room.allSegs.get(i).nextIndex;
					if (nextI == -1 || room.allSegs.get(i).angle(room.allSegs.get(j)) < room.allSegs.get(i).angle(room.allSegs.get(nextI)))
						room.allSegs.get(i).nextIndex = j;
				}
			}
		}
	}
}

class pt {

	public int x;
	public int y;

	public pt(int myx, int myy) {
		x = myx;
		y = myy;
	}

	public boolean equals(pt other) {
		if (other == null) return false;
		return x == other.x && y == other.y;
	}
}

class seg {

	public pt[] ptArray;
	public String type;
	public int nextIndex;
	public int roomNumber;
	public int origID;

	public seg(pt start, pt end, int ID, String t) {
		ptArray = new pt[2];
		ptArray[0] = start;
		ptArray[1] = end;
		type = t;
		origID = ID;
		nextIndex = -1;
		roomNumber = -1;
	}

	// Returns true iff other follows this segment.
	public boolean meet(seg other) {
		return this.ptArray[1].equals(other.ptArray[0]);
	}

	// If this meets other, then this returns the difference in angle, representing the turn from this to other.
	public double angle(seg other) {
		return map(this.getHeading()+Math.PI-other.getHeading());
	}

	// Maps angle to equivalent from 0 to 2pi.
	public static double map(double angle) {
		if (angle < 0) angle += 2*Math.PI;
		if (angle > 2*Math.PI) angle -= 2*Math.PI;
		return angle;
	}

	public double getHeading() {
		return Math.atan2(ptArray[1].y-ptArray[0].y, ptArray[1].x-ptArray[0].x);
	}
}

class room {

	public static ArrayList<seg> allSegs;
	public ArrayList<Integer> segOrder;
	public ArrayList<pt> ptOrder;
	public boolean isEntrance;
	public boolean isExit;

	// Just stores which segments are in order (counter-clockwise) for this room.
	public room(ArrayList<Integer> segs) {

		ptOrder = new ArrayList<pt>();
		isEntrance = false;
		isExit = false;
		segOrder = segs;

		for (int i=0; i<segs.size(); i++) {
			ptOrder.add(allSegs.get(segs.get(i)).ptArray[0]);
			if (allSegs.get(segs.get(i)).type.equals("E")) isEntrance = true;
			if (allSegs.get(segs.get(i)).type.equals("X")) isExit = true;
		}
	}

	// Returns true iff this room has a door.
	public boolean hasDoor() {
		for (int i=0; i<segOrder.size(); i++)
			if (allSegs.get(segOrder.get(i)).type.equals("D"))
				return true;
		return false;
	}

	// Sets the room number for each segment in this room to number.
	public void setRoomNumber(int number) {
		for (int i=0; i<segOrder.size(); i++)
			allSegs.get(segOrder.get(i)).roomNumber = number;
	}

	// Updates the used array to account for each segment in this room.
	public void updateUsed(boolean[] used) {
		for (int i=0; i<segOrder.size(); i++)
			used[segOrder.get(i)] = true;
	}

	// Returns the area of this room.
	public int doubleArea() {
		int ans = 0;
		for (int i=0; i<ptOrder.size(); i++) {
			int nextI = (i+1)%ptOrder.size();
			ans = ans + ptOrder.get(i).x*ptOrder.get(nextI).y - ptOrder.get(nextI).x*ptOrder.get(i).y;
		}
		return Math.abs(ans);
	}
}

/*** My slow network flow code - good enough for this problem...this is a sparse graph, not more than a few hundred edges... ***/

class Edge {

	private int capacity;
	private int flow;

	public Edge(int cap) {
		capacity = cap;
		flow = 0;
	}

	public int maxPushForward() {
		return capacity - flow;
	}

	public int maxPushBackward() {
		return flow;
	}

	public boolean pushForward(int moreflow) {

		// We can't push through this much flow.
		if (flow+moreflow > capacity)
			return false;

		// Push through.
		flow += moreflow;
		return true;
	}

	public boolean pushBack(int lessflow) {

		// Not enough to push back on.
		if (flow < lessflow)
			return false;

		flow -= lessflow;
		return true;
	}
}

class direction {

	public int prev;
	public boolean forward;

	public direction(int node, boolean dir) {
		prev = node;
		forward = dir;
	}

	public String toString() {
		if (forward)
			return "" + prev + "->";
		else
			return "" + prev + "<-";
	}
}

class networkflow {

	private Edge[][] adjMat;
	private int source;
	private int dest;

	// All positive entries in flows should represent valid flows
	// between vertices. All other entries must be 0 or negative.
	public networkflow(int[][] flows, int start, int end) {

		source = start;
		dest = end;
		adjMat = new Edge[flows.length][flows.length];

		for (int i=0; i<flows.length; i++) {
			for (int j=0; j<flows[i].length; j++) {

				// Fill in this flow.
				if (flows[i][j] > 0)
					adjMat[i][j] = new Edge(flows[i][j]);
				else
					adjMat[i][j] = null;
			}
		}
	}

	public ArrayList<direction> findAugmentingPath() {

		// This will store the previous node visited in the BFS.
		direction[] prev = new direction[adjMat.length];
		boolean[] inQueue = new boolean[adjMat.length];
		for (int i=0; i<inQueue.length; i++)
			inQueue[i] = false;

		// The source has no previous node.
		prev[source] = new direction(-1, true);

		LinkedList<Integer> bfs_queue = new LinkedList<Integer>();
		bfs_queue.offer(new Integer(source));
		inQueue[source] = true;

		// Our BFS will go until we clear out the queue.
		while (bfs_queue.size() > 0) {

			// Add all the new neighbors of the current node.
			Integer next = bfs_queue.poll();

			// Find all neighbors and add into the queue. These are forward edges.
			for (int i=0; i<adjMat.length; i++)
				if (!inQueue[i] && adjMat[next][i] != null && adjMat[next][i].maxPushForward() > 0) {
					bfs_queue.offer(new Integer(i));
					inQueue[i] = true;
					prev[i] = new direction(next, true);
				}

			// Now look for back edges.
			for (int i=0; i<adjMat.length; i++)
				if (!inQueue[i] && adjMat[i][next] != null && adjMat[i][next].maxPushBackward() > 0) {
					bfs_queue.offer(new Integer(i));
					inQueue[i] = true;
					prev[i] = new direction(next, false);
				}
		}

		// No augmenting path found.
		if (!inQueue[dest])
			return null;

		ArrayList<direction> path = new ArrayList<direction>();

		direction place = prev[dest];

		direction dummy = new direction(dest, true);
		path.add(dummy);

		// Build the path backwards.
		while (place.prev != -1) {
			path.add(place);
			place = prev[place.prev];
		}

		// Reverse it now.
		Collections.reverse(path);

		return path;
	}

	// Run the Max Flow Algorithm here.
	public int getMaxFlow() {

		int flow = 0;

		ArrayList<direction> nextpath = findAugmentingPath();

		// Loop until there are no more augmenting paths.
		while (nextpath != null) {

			// Check what the best flow through this path is.
			int this_flow = Integer.MAX_VALUE;
			for (int i=0; i<nextpath.size()-1; i++) {

				if (nextpath.get(i).forward) {
					this_flow = Math.min(this_flow, adjMat[nextpath.get(i).prev][nextpath.get(i+1).prev].maxPushForward());
				}
				else {
					this_flow = Math.min(this_flow, adjMat[nextpath.get(i+1).prev][nextpath.get(i).prev].maxPushBackward());
				}
			}

			// Now, put this flow through.
			for (int i=0; i<nextpath.size()-1; i++) {

				if (nextpath.get(i).forward) {
					adjMat[nextpath.get(i).prev][nextpath.get(i+1).prev].pushForward(this_flow);
				}
				else {
					adjMat[nextpath.get(i+1).prev][nextpath.get(i).prev].pushBack(this_flow);
				}
			}

			// Add this flow in and then get the next path.
			flow += this_flow;
			nextpath = findAugmentingPath();
		}

		return flow;
	}
}