Follow up Implementation on Monty Hall Simulation
Positive Feedback

I liked how you follow the rules of Clean Code, that you write small methods and small classes and give all readable names!

You've introduced your own data types that make the code more readable. The MontyHall-Algorithm can now be read like a poem:

montyHall.chooseDoor();
montyHall.openDoor();
if (player.preferresChange()){
   montyHall.changeDoor();
}
if (Price.CAR == montyHall.getPrice()){
   player.increaseWinCounter();
}


And all your methods have only one intention level what makes them so easy to understand.

Some Criticism

Class Names Refer to Unexpected Behavior

I read on Wikipedia: 


  You [the player] pick a door, say No. 1, and the host, who knows what's behind the doors, opens another door, say No. 3


After I read your code I was a little bit confused at some places. But not because of the quality of your code, which is for me very high, but because of the quote above.

In your game the Player can't pick a Door. Instead the Player gets picked a door by MontyHall: (montyHall.chooseDoor()).

Additional to that the Player has a winCounter, but actually the Simulation should track how often a Player wins the MontyHall.

No Outcome

What would you expect your main to do without any knowledge about our code base?

public static void main(String[] args) {
    Simulator simulator = new Simulator();
    simulator.simulate(10000, 3);
}


It could run something like a game loop or start a GUI to interact with but instead it writes data to the console.

Much cleaner would be:

public static void main(String[] args) {
    Simulator simulator = new Simulator();
    simulator.printSimulations(10000, 3);
}


But now imagine you want to compare a "Changer" and a "Stayer". You can't do it because you have no outcome! You through your outcome away by printing it to the console instead of storing and returning it.

public static void main(String[] args) {
    Simulator simulator = new Simulator();
    SimulationResult result = simulator.simulate(10000, 3);
    int average = result.calculateAverageOfStayer();
    System.out.println(average);
}


Feature Envy


  A method accesses the data of another object more than its own data.


The method playOneRound in playOneRound is in my eyes a feature envy. All the tasks should be done by MontyHall. So the method playOneRound should look like:

private void playOneRound(Player player, MontyHall montyHall) {
    montyHall.playGameWith(player);
}


Use Methods instead of Getters and Operations

In your code I can find code structure like x.getValue == something, but much better to read would be x.isSomething()

Some inspiration for you:

Price.GOAT == d.getPrice() means door.isHidingGoat()

Price.CAR == montyHall.getPrice() means montyHall.isWon()

!d.equals(selected) means door.notEquals(selected)



In your older post @Simon Forsberg mentioned:


  I have a feeling that using a class for StraightPlayer, ChangePlayer and ShowMaster will be a bit overkill. 


I know you still have the flag argument in Player. But that's fine. In general, refactoring can be an overkill at all. And you can see that for this little problem you can divide the logic into so many different classes and methods. When you write code, you have to find a balance between all OOP/clean code and your task.

Thanks for this cool problem and that you let me review it. I learned a lot while read your code :]