Last active
January 22, 2016 14:03
-
-
Save james-d/7a188f0ce19c5febf3a3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.word { | |
-fx-font-family: sans-serif ; | |
-fx-font-size: 32pt ; | |
-fx-padding: 12 ; | |
-fx-min-width: 300 ; | |
} | |
.controls { | |
-fx-alignment: center ; | |
-fx-padding: 12 ; | |
} | |
.buttons { | |
-fx-hgap: 2; | |
-fx-vgap: 2; | |
-fx-padding: 12 ; | |
} | |
.letter-button { | |
-fx-max-width: infinity ; | |
-fx-max-height: infinity ; | |
} | |
.life-lost { | |
-fx-background-color: -fx-color, black, -fx-color ; | |
-fx-background-insets: 0, 2, 4 ; | |
-fx-min-width: 36 ; | |
-fx-min-height: 36 ; | |
-fx-font-size: 24 ; | |
-fx-font-family: "comic sans ms" ; | |
} | |
.life-lost .text { | |
-fx-fill: red ; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package hangman; | |
import java.util.function.Supplier; | |
import java.util.stream.Collectors; | |
import javafx.application.Application; | |
import javafx.beans.binding.Bindings; | |
import javafx.beans.binding.StringBinding; | |
import javafx.scene.Scene; | |
import javafx.scene.control.Button; | |
import javafx.scene.control.Label; | |
import javafx.scene.layout.BorderPane; | |
import javafx.scene.layout.HBox; | |
import javafx.scene.layout.StackPane; | |
import javafx.scene.layout.TilePane; | |
import javafx.stage.Stage; | |
public class Hangman extends Application { | |
private StringBinding wordBinding; | |
private StringBinding statusBinding; | |
@Override | |
public void start(Stage primaryStage) { | |
Supplier<String> wordGenerator = new WordGenerator(); | |
HangmanGameState game = new HangmanGameState(wordGenerator.get()); | |
BorderPane root = new BorderPane(); | |
Label word = new Label(); | |
wordBinding = Bindings.createStringBinding(() -> { | |
if (game.isWordGuessed() || game.isLost()) { | |
return game.getWord(); | |
} | |
return game.getWord() | |
.chars() | |
.map(c -> game.getGuesses().contains((char)c) ? (char)c : '?') | |
.mapToObj(c -> Character.toString((char)c)) | |
.collect(Collectors.joining()); | |
}, game.wordProperty(), game.getGuesses(), | |
game.wordGuessedProperty(), game.lostProperty()); | |
word.textProperty().bind(wordBinding); | |
HBox livesRemaining = new HBox(); | |
for (int i = 0 ; i < HangmanGameState.LIVES ; i++) { | |
Label lifeLost = new Label("X"); | |
StackPane lifeLostHolder = new StackPane(lifeLost); | |
lifeLostHolder.getStyleClass().add("life-lost"); | |
livesRemaining.getChildren().add(lifeLostHolder); | |
lifeLost.visibleProperty().bind( | |
game.wrongGuessesProperty().greaterThan(i)); | |
} | |
Label statusLabel = new Label(); | |
statusBinding = Bindings | |
.when(game.lostProperty()) | |
.then("You lost!") | |
.otherwise("You won!"); | |
statusLabel.textProperty().bind(statusBinding); | |
statusLabel.getStyleClass().add("status"); | |
Button playAgain = new Button("Play again"); | |
playAgain.setOnAction(e -> game.restartGame(wordGenerator.get())); | |
HBox controls = new HBox(5, statusLabel, playAgain); | |
controls.getStyleClass().add("controls"); | |
controls.visibleProperty().bind( | |
game.wordGuessedProperty().or(game.lostProperty())); | |
TilePane buttons = new TilePane(); | |
buttons.getStyleClass().add("buttons"); | |
for (char c = 'A'; c <= 'Z'; c++) { | |
Character ch = new Character(c); | |
Button button = new Button(ch.toString()); | |
button.disableProperty().bind(Bindings.createBooleanBinding( | |
() -> game.getGuesses().contains(ch), | |
game.getGuesses())); | |
button.visibleProperty().bind(button.disableProperty().not()); | |
button.setOnAction(e -> game.getGuesses().add(ch)); | |
button.getStyleClass().add("letter-button"); | |
buttons.getChildren().add(button); | |
} | |
StackPane wordHolder = new StackPane(word); | |
wordHolder.getStyleClass().add("word"); | |
root.setCenter(wordHolder); | |
root.setRight(buttons); | |
root.setTop(livesRemaining); | |
root.setBottom(controls); | |
Scene scene = new Scene(root); | |
scene.getStylesheets().add( | |
getClass().getResource("hangman.css").toExternalForm()); | |
primaryStage.setScene(scene); | |
primaryStage.show(); | |
} | |
public static void main(String[] args) { | |
launch(args); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package hangman; | |
import javafx.beans.binding.Bindings; | |
import javafx.beans.property.ReadOnlyBooleanProperty; | |
import javafx.beans.property.ReadOnlyBooleanWrapper; | |
import javafx.beans.property.ReadOnlyIntegerProperty; | |
import javafx.beans.property.ReadOnlyIntegerWrapper; | |
import javafx.beans.property.SimpleStringProperty; | |
import javafx.beans.property.StringProperty; | |
import javafx.collections.FXCollections; | |
import javafx.collections.ObservableList; | |
public class HangmanGameState { | |
private final StringProperty word ; | |
public final static int LIVES = 6 ; | |
public final StringProperty wordProperty() { | |
return this.word; | |
} | |
public final String getWord() { | |
return this.wordProperty().get(); | |
} | |
public final void setWord(final String word) { | |
this.wordProperty().set(word); | |
} | |
private final ObservableList<Character> guesses = | |
FXCollections.observableArrayList(); | |
public ObservableList<Character> getGuesses() { | |
return guesses ; | |
} | |
private final ReadOnlyIntegerWrapper wrongGuesses = | |
new ReadOnlyIntegerWrapper(); | |
public final ReadOnlyIntegerProperty wrongGuessesProperty() { | |
return this.wrongGuesses.getReadOnlyProperty(); | |
} | |
public final int getWrongGuesses() { | |
return this.wrongGuessesProperty().get(); | |
} | |
private final ReadOnlyBooleanWrapper wordGuessed = | |
new ReadOnlyBooleanWrapper() ; | |
public final ReadOnlyBooleanProperty wordGuessedProperty() { | |
return this.wordGuessed.getReadOnlyProperty(); | |
} | |
public final boolean isWordGuessed() { | |
return this.wordGuessedProperty().get(); | |
} | |
private final ReadOnlyBooleanWrapper lost = new ReadOnlyBooleanWrapper() ; | |
public ReadOnlyBooleanProperty lostProperty() { | |
return lost.getReadOnlyProperty() ; | |
} | |
public final boolean isLost() { | |
return lostProperty().get(); | |
} | |
public HangmanGameState(String initialWord) { | |
word = new SimpleStringProperty(initialWord); | |
wrongGuesses.bind(Bindings.createIntegerBinding(() -> { | |
return (int) guesses.stream() | |
.map(c -> c.toString()) | |
.filter(c -> ! word.get().contains(c)) | |
.count(); | |
}, word, guesses)); | |
wordGuessed.bind(Bindings.createBooleanBinding(() -> { | |
return word.get() | |
.chars() | |
.mapToObj((int c) -> Character.valueOf((char)c)) | |
.allMatch(guesses::contains); | |
}, word, guesses)); | |
lost.bind(wrongGuesses.greaterThanOrEqualTo(LIVES)); | |
} | |
public void restartGame(String newWord) { | |
guesses.clear(); | |
word.set(newWord); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package hangman; | |
import java.util.Arrays; | |
import java.util.Collections; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.function.Supplier; | |
public class WordGenerator implements Supplier<String> { | |
private final String allWords = "Accident agree arrive astronomy " | |
+ "atlas attention award aware Balance banner bare base " | |
+ "beach besides blast board bounce brain branch brave " | |
+ "bright Cage calf calm career center cheer chew claw " | |
+ "clear cliff club collect connect core corner couple crowd " | |
+ "curious Damp dangerous dash dawn deep demolish design " | |
+ "discard dive dome doubt dozen Earth enemy evening exactly " | |
+ "excess Factory fair famous feast field finally flap float " | |
+ "flood fold fresh frighten fuel Gap gaze gift gravity greedy " | |
+ "Harm herd Idea insect instrument invent island Leader leap " | |
+ "lizard local lonely luxury March mention motor Nervous net " | |
+ "nibble notice Ocean Pack pale parade past peak planet " | |
+ "present proof Reflect rumor Safe scholar seal search settle " | |
+ "share shelter shiver shy skill slight smooth soil stack " | |
+ "steady strand stream support Team telescope tiny tower " | |
+ "travel tremble Universe Village Warn weak wealthy whisper " | |
+ "wise wonder worry Yard Zigzag" ; | |
private final List<String> words ; | |
private Iterator<String> iterator ; | |
public WordGenerator() { | |
words = Arrays.asList(allWords.split(" ")) ; | |
Collections.shuffle(words); | |
iterator = words.iterator() ; | |
} | |
public String get() { | |
if (! iterator.hasNext()) { | |
Collections.shuffle(words); | |
iterator = words.iterator() ; | |
} | |
return iterator.next().toUpperCase() ; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment