Java 创建比数独游戏板更强大的游戏
你好,我想做一个比数独更好的解算器。我已经在Java中制作了回溯算法,它从不等式的数组输入中解决了比数独板更大的问题,现在我想为它制作图形界面,这就是问题所在 我想让我的游戏板看起来像这样。我曾试图在JavaFXonGridPane中这样做,但我认为我不允许更改网格的板线以将其更改为不等式(˄˅<>)。然后我试着制作一个普通的数独棋盘,在棋盘上只显示不相等的符号,但我无法使它们与线条匹配 在截图上有没有什么好方法可以制作这样的图板?我想从不相等的输入生成电路板,然后在单击“求解”后显示充满数字的电路板Java 创建比数独游戏板更强大的游戏,java,javafx,sudoku,Java,Javafx,Sudoku,你好,我想做一个比数独更好的解算器。我已经在Java中制作了回溯算法,它从不等式的数组输入中解决了比数独板更大的问题,现在我想为它制作图形界面,这就是问题所在 我想让我的游戏板看起来像这样。我曾试图在JavaFXonGridPane中这样做,但我认为我不允许更改网格的板线以将其更改为不等式(˄˅)。然后我试着制作一个普通的数独棋盘,在棋盘上只显示不相等的符号,但我无法使它们与线条匹配 在截图上有没有什么好方法可以制作这样的图板?我想从不相等的输入生成电路板,然后在单击“求解”后显示充满数字的电
我将非常感谢您的帮助。为每个单元格创建控件的一种可能方法是,使用较大/较低符号给出的定义形状和可编辑文本,如下所示: 对于任何给定的单个单元格,可以创建一个带有
路径
、文本
和文本字段
节点的方形区域
路径只会被笔划,不会被填充,并且不会离开方形区域,这便于在一个3x3的方形框中堆积9个单元格
如果单元侧需要更大的符号,则单元外的部分将由使用较低符号的相邻单元定义
例如,这三个单元:
可组合成一个3x1行:
再增加两行,我们将有一个3x3的盒子:
这完全符合要求。现在有了8个这样的盒子,我们就有了完整的数独游戏
让我们现在创建这个单元格
GreaterCell
为了方便起见,让我们定义三种可能的边类型:内侧的“大”和“低”,边界边的“等”
public enum Symbol {
GREATER, EQUAL, LOWER
}
让我们从路径开始。根据四边的类型,我们将使用MoveTo
和LineTo
private static final double SIDE = 60;
private Path path;
private void createPath() {
path.getElements().clear();
path.getElements().add(new MoveTo(0d, 0d));
// top
path.getElements().add(new LineTo(SIDE / 3d ,0));
switch (top) {
case GREATER: path.getElements().add(new MoveTo(2d * SIDE / 3d, 0d)); break;
case EQUAL: path.getElements().add(new LineTo(2d * SIDE / 3d, 0d)); break;
case LOWER: path.getElements().add(new LineTo(SIDE / 2d, SIDE / 5d));
path.getElements().add(new LineTo(2d * SIDE / 3d, 0d));
break;
}
path.getElements().add(new LineTo(SIDE, 0d));
// right
path.getElements().add(new LineTo(SIDE, SIDE / 3d));
switch (right) {
case GREATER: path.getElements().add(new MoveTo(SIDE, 2d * SIDE / 3d)); break;
case EQUAL: path.getElements().add(new LineTo(SIDE, 2d * SIDE / 3d)); break;
case LOWER: path.getElements().add(new LineTo(SIDE - SIDE / 5d, SIDE / 2d));
path.getElements().add(new LineTo(SIDE, 2d * SIDE / 3d));
break;
}
path.getElements().add(new LineTo(SIDE, SIDE));
// bottom
path.getElements().add(new LineTo(2d * SIDE / 3d, SIDE));
switch (bottom) {
case GREATER: path.getElements().add(new MoveTo(SIDE / 3d, SIDE)); break;
case EQUAL: path.getElements().add(new LineTo(SIDE / 3d, SIDE)); break;
case LOWER: path.getElements().add(new LineTo(SIDE / 2d, SIDE - SIDE / 5d));
path.getElements().add(new LineTo(SIDE / 3d, SIDE));
break;
}
path.getElements().add(new LineTo(0d, SIDE));
// left
path.getElements().add(new LineTo(0d, 2d * SIDE / 3d));
switch (left) {
case GREATER: path.getElements().add(new MoveTo(0d, SIDE / 3d)); break;
case EQUAL: path.getElements().add(new LineTo(0d, SIDE / 3d)); break;
case LOWER: path.getElements().add(new LineTo(SIDE / 5d, SIDE / 2d));
path.getElements().add(new LineTo(0d, SIDE / 3d));
break;
}
path.getElements().add(new LineTo(0d, 0d));
}
使用此路径,现在可以使用文本节点定义区域
重要的是要注意,我们添加了一个剪辑
,以切断从单元格出来的路径的半边框
public class GreaterCell extends Region {
public enum Symbol {
GREATER, EQUAL, LOWER
}
private static final double SIDE = 60;
private final Path path;
private final Text text;
private final Symbol top, right, bottom, left;
private final Rectangle clip;
public GreaterCell(String number, Symbol top, Symbol right, Symbol bottom, Symbol left) {
this.top = top;
this.right = right;
this.bottom = bottom;
this.left = left;
getStyleClass().add("greater-cell");
path = new Path();
path.getStyleClass().add("path");
createPath();
text = new Text(number);
text.getStyleClass().add("text");
getChildren().addAll(path, text);
clip = new Rectangle(SIDE, SIDE);
setClip(clip);
}
@Override
protected void layoutChildren() {
super.layoutChildren();
resizeRelocate(0, 0, SIDE, SIDE);
Bounds b = text.getBoundsInParent();
text.resizeRelocate(SIDE / 2d - b.getWidth() / 2d, SIDE / 2d - b.getHeight() / 2d, SIDE / 2d, SIDE / 2d);
}
}
现在可以将行定义为:
@Override
public void start(Stage primaryStage) throws Exception {
GreaterCell tile31 = new GreaterCell("3", LOWER, LOWER, GREATER, EQUAL);
GreaterCell tile41 = new GreaterCell("6", LOWER, GREATER, GREATER, GREATER);
GreaterCell tile51 = new GreaterCell("5", GREATER, EQUAL, LOWER, LOWER);
HBox root = new HBox(0, new Group(tile31), new Group(tile41), new Group(tile51));
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(40));
Scene scene = new Scene(root, 400, 250);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
我们将再次看到上面的图片:
添加TextField
以允许编辑现在是一项简单的任务
private final TextField textField;
private final Symbol top, right, bottom, left;
private final Rectangle clip;
public GreaterCell(String number, Symbol top, Symbol right, Symbol bottom, Symbol left) {
...
textField = new TextField();
textField.setVisible(false);
getChildren().addAll(path, textField, text);
setOnMouseClicked(e -> {
if (e.getClickCount() == 2) {
text.setVisible(false);
textField.setText(text.getText());
textField.setVisible(true);
textField.requestFocus();
}
});
textField.setOnAction(e -> {
textField.setVisible(false);
text.setVisible(true);
text.setText(textField.getText());
});
textField.focusedProperty().addListener((obs, ov, nv) -> {
if (! nv) {
textField.setVisible(false);
text.setVisible(true);
}
});
}
@Override
protected void layoutChildren() {
super.layoutChildren();
...
textField.resizeRelocate(SIDE / 4d, SIDE / 4d, SIDE / 2d, SIDE / 2d);
}
请注意,创建一个GreaterCellSkin
来管理渲染可能会更方便,而控件将只具有text属性,但现在这种简单的方法已经足够好了
Style.css
.greater-cell {
-fx-background-color: lightgray;
}
.greater-cell > .path {
-fx-stroke: black;
-fx-stroke-width: 1.4px;
-fx-fill: null;
}
.greater-cell > .text {
-fx-font-size: 2em;
-fx-alignment: center;
}
.greater-cell > .text-field {
}
框
要创建框,可以方便地使用GridPane
控件,该控件将布置3x3个单元格。这一部分被排除在这个答案之外
数独
最后,另一个
GridPane
将布置3x3个框。这一部分也被排除在这个答案之外 大家好,欢迎来到StackOverflow。请花些时间阅读帮助页面,特别是命名和的部分。更重要的是,请阅读。你可能还想了解。为什么你的问题不太好:问题太广泛,你没有表现出任何自己的尝试。或者换句话说:没有人会为你做工作;)GridPane
的网格线是用于调试的功能。你不应该依赖它。使用路径
/多段线
似乎可以轻松实现布局……非常感谢您的帮助!