void trainOnTurn(ArimaaState myState, ArimaaEngine myEngine) throws IOException {
		ArimaaMove expertMove = myState.getNextMove();
		
		// Extract features for the expert move
		FeatureExtractor myExtractor = new FeatureExtractor(myState.getCurr(), myState.getPrev(), myState.getPrevPrev(), myState.getPrevMove(), myState.getPrevPrevMove());
		BitSet featureVector = myExtractor.extractFeatures(expertMove); // extract features from expert move
		outputToFile(featureVector, true);
		numExpertMoves++;
		
		// Extract features for all non-expert possible moves
		MoveList allPossibleMoves = myEngine.genRootMoves(myState.getCurr()); // upper limit of 400,000 possible moves
		// Note: for optimization, we should consider reducing this number from 400,000 to 40,000-50,000
		
		randomlyPermuteFirstK(allPossibleMoves, MIN_NON_EXPERT_MOVES);
		ArimaaMove[] allMoves = allPossibleMoves.move_list;
		
		//always consider these moves -- NOTE: we consider 1 less if the expert move falls in the first k
		int nonExpertBound = Math.min(MIN_NON_EXPERT_MOVES, allPossibleMoves.size());
		for (int move = 0; move < nonExpertBound; move++) {
			ArimaaMove possibleMove = allMoves[move];
			if (!possibleMove.equals(expertMove)){
				featureVector = myExtractor.extractFeatures(possibleMove); // extract features from non-expert move
				outputToFile(featureVector, false);
				numNonExpertMoves++;				
			}
		}
		
		//randomly discard at the discard rate the rest of the moves
		for (int move = MIN_NON_EXPERT_MOVES; move < allPossibleMoves.size(); move++) {
			ArimaaMove possibleMove = allMoves[move];
			if (!possibleMove.equals(expertMove)){
				// skip the move if we are discarding, with expectation DISCARD_RATE
				if (DISCARDING && rgen.nextDouble() < DISCARD_RATE) continue;
				
				featureVector = myExtractor.extractFeatures(possibleMove); // extract features from non-expert move
				outputToFile(featureVector, false);
				numNonExpertMoves++;			
			}
		}
		
		writer.flush();
	}