- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在 JavaFX 中创建了一个迷宫游戏,用户可以在其中创建自己的迷宫并进行游戏。迷宫是使用带有 CSS ID 的按钮构建的,具体取决于关卡临时存储在其中的二维数组。
问题出现在项目的下一部分。我创建了一个生成随机迷宫的算法。为了使关卡成为可能,我需要检查迷宫是否可解(即您可以从起点 (0, 3) 到达终点 (6, 3))。
我已经用相同的显示算法创建了一个单独的项目,类如下:
主.java
import javafx.application.Application;
import javafx.scene.control.*;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
public class Main extends Application{
int[][] level = {{1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1}};
public static boolean[][] status = new boolean[7][7];
public static Button[][] blankButtons = new Button[7][7];
public static Runner[][] runners = new Runner[7][7];
boolean solvable = false;
GridPane buttonGrid = new GridPane();
public static void main(String[] args){launch(args);}
public void start(Stage primaryStage) throws Exception {
Stage window = primaryStage;
for (int i = 0; i < 7; i++){
for (int j = 0; j < 7; j++){
if (level[i][j] == 1){
status[i][j] = false;
} else if (level[i][j] == 0){
status[i][j] = true;
}
}
}
GridPane mazeGrid = new GridPane();
Scene maze = new Scene(mazeGrid, 700, 700);
maze.getStylesheets().add("Main.css");
for(int i = 0; i < 7; i++){
for(int j = 0; j < 7; j++){
makeBlankButton(i, j);
}
}
//MY PREVIOUS ATTEMPT AT A FLOOD SOLVER//
// for(int i = 0; i < 7; i++){
// for(int j = 0; j < 7; j++){
// runners[i][j] = new Runner(i, j);
// runners[i][j].alive = false;
// }
// }
// Runner finish = new Runner(3, 6);
// finish.alive = false;
//
//
// runners[3][0].alive = true;
// runners[3][0].run();
// for(int i = 0; i < 7; i++){
// for(int j = 0; j < 7; j++){
// if(runners[i][j].alive){
// runners[i][j].run();
// }
// if(runners[3][1].alive){
// solvable = true;
// System.out.println(solvable);
//
// }
// System.out.println(solvable);
// }
// }
mazeGrid.getChildren().add(buttonGrid);
window.setScene(maze);
window.show();
}
public void makeBlankButton(int row, int column){
blankButtons[row][column] = new Button();
GridPane.setConstraints(blankButtons[row][column], column, row);
if (level[row][column] == 1){
blankButtons[row][column].setId("button-array-clicked");
} else if (level[row][column] == 0) {
blankButtons[row][column].setId("button-array-blank");
}
buttonGrid.getChildren().add(blankButtons[row][column]);
GridPane.setConstraints(buttonGrid, 0, 1);
if (row == 3){
if (column == 0){
blankButtons[row][column].setId("button-start");
} else if(column == 6){
blankButtons[row][column].setId("button-end");
}
}
}
}
Runner.java
public class Runner {
int x, y;
boolean alive;
Runner(int x, int y){
this.x = x;
this.y = y;
this.alive = false;
if(this.alive) {
Main.blankButtons[x][y].setId("button-water");
}
}
public void run(){
if (this.alive) {
if (Main.status[x + 1][y]) {
// Main.runners[x + 1][y] = new Runner(x + 1, y);
Main.runners[y + 1][x].alive = true;
Main.status[x][y] = false;
this.alive = false;
} else if (Main.status[y][x + 1]) {
// Main.runners[x][y + 1] = new Runner(x, y + 1);
Main.runners[x][y + 1].alive = true;
Main.status[x][y] = false;
this.alive = false;
} else if (Main.status[y][x-1]) {
// Main.runners[x - 1][y] = new Runner(x - 1, y);
Main.runners[x - 1][y].alive = true;
Main.status[x][y] = false;
this.alive = false;
} else if (Main.status[y][x-1]) {
// Main.runners[x][y - 1] = new Runner(x, y - 1);
Main.runners[x][y - 1].alive = true;
Main.status[x][y] = false;
this.alive = false;
}
}
}
}
主.css
#button-array-clicked{
-fx-pref-width: 100px;
-fx-pref-height: 100px;
-fx-border-width: 1px;
-fx-border-color: #00aa00;
-fx-background-color: #000000;
-fx-font-size: 10px;
}
#button-array-blank{
-fx-pref-width: 100px;
-fx-pref-height: 100px;
-fx-border-width: 1px;
-fx-border-color: #00aa00;
-fx-background-color: #ffffff;
-fx-font-size: 10px;
}
#button-start{
-fx-pref-width: 100px;
-fx-pref-height: 100px;
-fx-border-width: 1px;
-fx-border-color: #00aa00;
-fx-background-color: #00bbff;
-fx-font-size: 10px;
}
#button-end{
-fx-pref-width: 100px;
-fx-pref-height: 100px;
-fx-border-width: 1px;
-fx-border-color: #00aa00;
-fx-background-color: #cc00aa;
-fx-font-size: 10px;
}
#button-water{
-fx-pref-width: 100px;
-fx-pref-height: 100px;
-fx-border-width: 1px;
-fx-border-color: #00aa00;
-fx-background-color: #0000ff;
-fx-font-size: 10px;
}
我怎样才能四处走动解决迷宫,同时显眼?如果迷宫是可解的,我希望它在完成后显示迷宫,但我希望程序生成一个新的迷宫来检查它是否不可解。
谢谢
最佳答案
这是一个非常基本的 Breadth First Search 实现.可以将其复制粘贴到一个文件 (Maze.java) 中并执行。它使用问题中发布的 Main.css
(尽管大多数情况下未使用)。
按钮处于 Activity 状态:单击按钮会更改状态并重新启动求解过程。请查看评论:
import java.util.*;
import java.util.concurrent.*;
import bfs.Cell.CellState;
import javafx.application.*;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class BsfVisualizationFx extends Application{
final int[][] level = {
{1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 0, 1},
{1, 0, 0, 0, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1}};
//represents moving in 4 directions
private final int[][] directions = {{1,0},{-1,0}, {0,1}, {0,-1}}; //down, up, right, left
private final Cell[][] cells = new Cell[level.length][level[0].length];
private final GridPane grid = new GridPane();
private BreadthFirst algo;
//Single Thread Executor guarantees that task (searches) do not run concurrently
final ExecutorService exService = Executors.newSingleThreadExecutor();
@Override
public void start(Stage primaryStage) throws Exception {
Stage window = primaryStage;
GridPane mazeGrid = new GridPane();
Scene maze = new Scene(mazeGrid);
maze.getStylesheets().add (getClass().getResource("BsfVisualizationFx.css").toExternalForm());
makeBlankButton();
mazeGrid.getChildren().add(grid);
window.setScene(maze);
window.show();
solve();
}
void solve(){
algo = new BreadthFirst(cells[5][5]) ;
exService.execute(()-> algo.solve(cells[1][1]));
}
void reSolve(){
stopSolve();
resetCellsState();
solve();
}
private void stopSolve(){
if(algo != null) {
algo.stop();
}
}
private void resetCellsState() {
for(int row = 0; row < level.length; row++){
for(int column = 0; column < level[0].length; column++){
if( cells[row][column].getState() != CellState.WALL) {
cells[row][column].setState(CellState.IDLE);
}
}
}
}
public void makeBlankButton(){
//listen to cell state changes. If cell changed from or to WALL restart solve
ChangeListener<CellState> listener = (obs , oldValue, newValue)->{
if(oldValue == CellState.WALL || newValue == CellState.WALL) {
reSolve();
}
};
for(int row = 0; row < level.length; row++){
for(int column = 0; column < level[0].length; column++){
Cell cell = new Cell(row, column);
GridPane.setConstraints(cell, column, row);
if (level[row][column] == 1){
cell.setState(CellState.WALL);
}
grid.getChildren().add(cell);
GridPane.setConstraints(grid, 0, 1);
if (row == 3){
if (column == 0){
cell.setId("button-start");
} else if(column == 6){
cell.setId("button-end");
}
}
cell.addStateListener(listener);
cells[row][column] = cell;
}
}
}
private List<Cell> getNeighbors(Cell cell) {
List<Cell> neighbors = new ArrayList<>();
int row = cell.getRow(), col = cell.getCol();
for(int[] dir : directions){
int newRow = row + dir[0] ; int newCol = col + dir[1];
if(isValidAddress(newRow, newCol)) {
neighbors.add(cells[newRow][newCol]);
}
}
return neighbors;
}
private boolean isValidAddress(int row, int col) {
if(row < 0 || col < 0) return false;
if(row >= level.length || col >= level[row].length) return false;
return true;
}
public static void main(String[] args){launch(args);}
class BreadthFirst {
private static final long DELAY = 1000;
private final LinkedList<Cell> path;
private final Cell target;
private volatile boolean isStopped;
public BreadthFirst(Cell target) {
this.target = target;
path = new LinkedList<>();
isStopped = false;
};
public boolean solve(Cell cell) {
if(cell == null || isStopped) return false;
// queue holds a nodes collections. each collection represents the path through
//which a cell has been reached, the cell being the last element in the collection
final Queue<List<Cell>> queue = new LinkedList<>(); //initialize queue
//a collection to hold the path through which a cell has been reached
//the cell it self is the last element in that collection
List<Cell> pathToCell = new ArrayList<>();
pathToCell.add(cell);
//queue does not hold a cell, but rather the whole path to a cell
//where the cell is stored as the last element
queue.add(pathToCell);
while (! queue.isEmpty() && ! isStopped) {
pathToCell = queue.remove();
//get cell (last element) from queue
cell = pathToCell.get(pathToCell.size()-1);
if(cell == null) return false;
//skip if cell is wall, or is/was explored or in path
if( cell.getState() != CellState.IDLE ) { continue; }
setCellState(cell, CellState.IS_EXPLORED);
addToPath(pathToCell);
Wait.millis(DELAY);
if(isSolved(cell)) return true;
List<Cell> nb = getNeighbors(cell);
Collections.shuffle(nb);
//loop over neighbors
for(final Cell nextCell : nb){
if(isStopped)
return false;
if(nextCell.getState() == CellState.WALL) { continue; }
final List<Cell> pathToNextCell = new ArrayList<>(pathToCell);
pathToNextCell.add(nextCell);
queue.add(pathToNextCell); //add collection to the queue
}
Collections.reverse(pathToCell);
for(final Cell c : pathToCell) {
backTrack(c);
}
}
return false;
}
private void setCellState(Cell cell, CellState state) {
Platform.runLater(()->cell.setState(state));
}
/**
* Append collection to path
*/
private void addToPath(Collection<Cell> pathToCell) {
for(Cell c : pathToCell) {
if(isStopped)
return;
addToPath(c);
}
}
/**
* Append Cell to path
*/
private void addToPath(Cell node) {
path.push(node);
setCellState(node, CellState.PATH);
}
/**
*Is maze solved
*/
private boolean isSolved(Cell cell) {
return cell.equals(target);
}
private void backTrack(Cell cell) {
//no backtracking if back to origin
if(path.size()<=1 || isStopped) return ;
setCellState(cell, CellState.WAS_EXPLORED);
//remove from stack
if( path.peek().equals(cell)) {
path.pop();
return;
}
throw new IllegalStateException(cell+" isn't at the top of the stack");
}
void stop(){
isStopped = true;
}
}
}
class Cell extends Button{
private final SimpleObjectProperty<CellState> stateProperty
= new SimpleObjectProperty<>(CellState.IDLE);
private final int row, col;
Cell(int row, int col){
this.row = row; this.col = col;
setOnAction(e -> toggleState());
}
public enum CellState {
WALL ("black"),
IDLE ("white") , //No activity is or was performed on node
IS_EXPLORED ("blue"), //node is evaluated by path finder
WAS_EXPLORED ("grey"), //node was evaluated by path finder
PATH ("green"); // node was evaluated by path finder and added to path
public String color;
CellState(String color) {this.color = color;}
}
void toggleState(){
setState(getState() == CellState. WALL ? CellState. IDLE : CellState. WALL );
}
void setState(CellState state){
stateProperty.set(state);
setStyle("-fx-background-color:" + state.color);
}
void addStateListener(ChangeListener<CellState> listener) {
stateProperty.addListener(listener);
}
@Override
public String toString() {
return getState()+" at "+ getRow() +" - " + getCol() ;
}
@Override
public boolean equals(Object cell) {
if (cell == null || !(cell instanceof Cell))
return false;
return ((Cell) cell).getRow() == row && ((Cell) cell).getCol() == col;
}
@Override
public int hashCode() {
return 31*(row+1) + 17*(col+1);
}
int getRow() { return row; }
int getCol() { return col;}
CellState getState() {return stateProperty.get();}
}
class Wait {
public static void millis(final long millis) {
try {
TimeUnit.MILLISECONDS.sleep(millis);
} catch (final InterruptedException ex) {ex.printStackTrace();}
}
}
关于java - JavaFX 中的寻路,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53840860/
粗略地说,单向数据绑定(bind)只是与 ng-model 绑定(bind)。当涉及 Controller 时,在页面内和 2-way 内。有人可以向我解释这个概念,以便我真正了解如何看待它吗?还有什
我想知道是否有任何替代 2 向 SSL 的方法。 2 向 SSL 是确保客户端和服务器可信通信的唯一选择吗?我有一个自签名证书供我的客户使用,我能否将自签名证书重新用于 2 种 SSL 方式,还是应该
如果是这样,你如何设置认证证书,你需要什么文件?是 .pfx 吗?您将如何在浏览器中安装它?一直试图通过浏览器测试 2 路 ssl。我有一个网络服务,尝试连接时总是返回认证身份验证失败。 最佳答案 扩
我希望能够对 XHTML 文档进行三向合并: 从文档的一些原始副本开始 一个用户编辑原始文档的副本 另一个用户编辑原始文档的单独副本 需要一个工具来合并(自动和/或可视化)两个用户所做的更改。 注意:
我有 4 张 table : ad (id, ...) website (id, title, URL, ...) space (id, website_id, ...) ad_space_count
我在 java 中有一个无状态服务,部署在 tomcat 网络服务器中,我还配置了 2 路 ssl 验证。到目前为止,一切正常。当我有一个新客户端时,我只需要将新客户端证书放入我的 trustore
我已经创建了一个带有证书的信任库和带有私钥的 keystore 。我已经放置了以下代码,加载了 trsustore 管理器和 keystore 管理器,然后创建了 SSL 上下文的实例。 每当我向网络
如果我在仅服务器身份验证中正确理解 SSL/TLS,握手后,服务器会向客户端发送它的公钥和由 CA 签名的数字签名证书。如果客户端有这个 CA 的公钥,它就可以解密证书并与服务器建立信任。如果它不信任
我有 Nginx,它使用双向 TLS 代理从客户端到 IBM DataPower 的请求。 从 Nginx 向 IBM DP 发送消息时出现错误:sll server (SERVER) ssl pee
我刚刚开始了一个项目,让我的雇主成为一个管理软件。我有一个琐碎但可能很简单的查询,我似乎找不到任何相关信息。 在对象之间建立“具有”关系的两种方式是否谨慎/良好做法。例如,Client 对象“有一个”
我在设置双向 SSL 身份验证时遇到问题。 我需要从 wso2 企业集成商访问 HTTPS 端点。 服务提供商给了我一个 pfx keystore ,其中包含我必须提供给服务器的证书和私钥。 我在我的
我正在为小型 PoC 构建 AWS Lambda 服务。 PoC 中的流程是: 通过 POST 获取(文本)输入, 执行小字符串操作 + 将操纵值存储到 DynamoDB 中,然后 通过 HTTP P
我的任务是在 Java 上下文中实现双向 TLS。我找到了一个示例 ( https://www.opencodez.com/java/implement-2-way-authentication-us
我正在尝试测试一个非常简单的双向 IM 应用程序。客户端在 android 上,服务器在我的 PC(java)上。我已经在 PC 到 PC 之间用 java 测试了这个应用程序,它工作正常。 但是在我
我有 java web 服务支持2-way ssl auth。所以我有客户端 keystore (client.p12),服务器证书在受信任的存储区中,服务器 keystore 中的客户端证书在受信任
通过 HTTPS 使用 Web 服务 我们有一个我们正在使用的网络服务。 Webservice 可以在 HTTP 和 HTTPS 协议(protocol)上运行。使用 HTTP 没问题,但如何使用 H
我在 Node.js 上有一个后端服务器,我正在尝试在 Nginx 和这个后端服务器之间设置 2 路 SSL。 但是我得到一个错误:2015/11/02 06:51:02 [错误] 12840#128
我一直在尝试连接到启用了 2 路 SSL 的服务端点。我正在使用 Spring resttemplate。我已将证书添加到 keystore 中,但出现以下错误: >org.springframewo
从 CherryPy 3.0 开始,只需指向服务器证书和私钥即可启用单向 SSL,如下所示: import cherrypy class HelloWorld(object): def ind
这个问题来自:MySQL Number of Days inside a DateRange, inside a month (Booking Table) 我有一个包含以下数据的表: CREATE
我是一名优秀的程序员,十分优秀!