@Override public Set<EvaluatedDecision> evaluateDecisions(Set<Decision> ds, State s) {
		initializeCaches(s);
		
		outOfTime = false;
		Timer t = new Timer();
		t.schedule(new TimerTask() {
			public void run() {
				outOfTime = true;
			}
		}, decision_time);

		Set<EvaluatedDecision> edsbest = null;
		int depth = 0;
		try {
			for (depth = 0; depth <= max_depth; depth++) {
				Set<EvaluatedDecision> eds = new HashSet<EvaluatedDecision>(ds.size());

				int ply = 0;
				boolean[] coalition = selectCoalition(s);

				for (Decision d: ds) {
					// calculate expected value of all possible outcomes of the decision
					double u = 0;
					Object[] outcomes = d.outcomeDesignators(s);
					for (int i = 0; i < outcomes.length; i++) {
						AppliedDecision ad = d.apply(s, outcomes[i], true);

						try {
							updateCaches(s, d, ad);

							// next ply if decision ended a turn
							int newply = ply;
							if (s.currentPlayer() != d.player)
								newply++;

							u += d.outcomeLikelihood(s, outcomes[i]) * minimax(s, depth, newply,
							                                                   Double.NEGATIVE_INFINITY,
							                                                   Double.POSITIVE_INFINITY,
							                                                   coalition).utility;
						} finally {
							// recursion might throw outoftime
							ad.undo();

							downdateCaches(s, d, ad);
						}
		 			}
					
					eds.add(new EvaluatedDecision(d, u));
				}

				edsbest = eds;
			}
		} catch (OutOfTimeException e) {
			if (verbose) System.out.println("out of time");
		} finally {
			total_depth += depth;
			total_depth_nterms++;
		}

		if (!outOfTime)
			t.cancel();

		total_ndecisions++;
		return edsbest;
	}