Java语言程序设计基础篇_编程练习题***18.33 (游戏:骑士旅途的动画)

news2024/11/14 21:42:50

目录

***18.33 (游戏:骑士旅途的动画)

习题思路

代码示例

动画演示


***18.33 (游戏:骑士旅途的动画)

  为骑士旅途的问题编写一个程序,该程序应该允许用户将骑士放到任何一个起始正方形,并单击Solve按钮,用动画展示骑士沿着路径的移动,如图18-16所示

  • 习题思路

  1. 初始化棋盘和骑士位置

    1. Board类:这个内部类继承自Pane,用于绘制棋盘和骑士。棋盘通过绘制水平和垂直线来创建,而骑士则通过红色圆圈表示。
    2. draw方法:此方法用于绘制棋盘和骑士。首先清除所有子节点,然后绘制棋盘网格和初始骑士位置(红色圆圈)。骑士有两个圆圈表示:theKnight(静态位置)和movingKnight(用于动画的移动位置)。
    3. startX和startY:这两个变量用于记录骑士的起始位置。初始时,它们被设置为(0, 0),即棋盘的左上角。但用户可以通过点击棋盘上的任意格子来改变这些值。
  2. 点击事件处理

    1. 当用户在棋盘上点击时,Board类中的setOnMouseClicked事件处理器会被触发。
    2. 事件处理器计算点击位置对应的格子索引(startXstartY),这是通过将鼠标点击的坐标除以每个格子的大小(棋盘宽度/SIZE或棋盘高度/SIZE)并取整来实现的。
    3. 随后,重置moves列表,即骑士的移动历史,为新的求解过程做准备。
  3. 求解按钮点击事件

    1. 当用户点击“Solve”按钮时,会触发一个事件处理器,该处理器执行以下步骤:
    2. 初始化棋盘状态:创建一个boolean[][] moves数组来跟踪哪些格子已被访问。将起始位置标记为已访问。
    3. 重置和添加起始移动:调用resetMoves()addMove(startX, startY)来重置移动历史并添加起始位置到历史中。
    4. 递归求解:调用solvePuzzle(moves, 1, startX, startY)开始递归求解过程。该方法尝试从当前位置出发,找到所有可能的下一步,并评估哪一步能导致最少的未访问格子数(通过lookAheadCount方法)。然后,它选择最优的下一步,并递归地尝试解决剩余的问题。
    5. 动画展示:如果找到解决方案,draw方法会被再次调用以更新棋盘上的骑士位置(尽管在这个实现中,movingKnight并未在动画中实际移动),然后调用playAnimation方法来展示骑士的移动路径。
  4. 动画展示

    1. playAnimation方法:此方法使用SequentialTransitionPathTransition来创建动画,展示骑士沿着求解路径移动的过程。对于moves列表中的每一对相邻点,它创建一个PathTransition,该过渡使一个红色圆圈沿着两点之间的直线移动。所有这些过渡被添加到一个SequentialTransition中,以便按顺序播放。
  • 代码示例

编程练习题18_33TheKnightJourney.java

package chapter_18;  
  
import java.util.ArrayList;
import javafx.animation.PathTransition;
import javafx.animation.SequentialTransition;
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;  
import javafx.scene.Scene;  
import javafx.scene.control.Button;  
import javafx.scene.layout.BorderPane;  
import javafx.scene.layout.Pane;  
import javafx.scene.paint.Color;  
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Duration;  
  
public class 编程练习题18_33TheKnightJourney extends Application {
	private static final int SIZE = 8;
	private int startX = 0;
	private int startY = 0;
	private ArrayList<Point2D> moves = null;
	private ArrayList<Line> pathList;
	public static void main(String[] args) {  
		Application.launch(args);  
	}  
    @Override  
    public void start(Stage primaryStage) throws Exception {
    	pathList = new ArrayList<Line>();
    	BorderPane pane = new BorderPane();
    	Board board = new Board();
    	pane.setCenter(board);
    	Button btSolve = new Button("Solve");
    	pane.setBottom(btSolve);
    	BorderPane.setAlignment(btSolve, Pos.CENTER);
    	
    	Scene scene = new Scene(pane,400,400);
    	primaryStage.setTitle("编程练习题18_33TheKnightJourney");
    	primaryStage.setScene(scene);
    	primaryStage.show();
    	
    	board.draw();
    	
    	btSolve.setOnAction(e -> {
    		boolean[][] moves = new boolean[SIZE][SIZE];
    		moves[startX][startY] = true;
    		resetMoves();
    		addMove(startX,startY);
    		solvePuzzle(moves,1,startX,startY);
    		board.draw();
    		board.playAnimation(pathList);
    	});
    }
   
    private boolean solvePuzzle(boolean[][] moves,int numberMoves,int x,int y) {
    	int nextX = 0;
    	int nextY = 0;
    	int bestMoveX = 0;
    	int bestMoveY = 0;
    	int bestMoveX2 = 0;
    	int bestMoveY2 = 0;
    	int minMoveCount = SIZE;
    	int moveCount = 0;
    	
    	for(int i = 2;i >= -2;i += -4) {
    		for(int j = 1;j >= -1;j += -2) {
    			nextX = x + i;
    			nextY = y + j;
    			if(nextX >= 0&&nextX <= SIZE-1&&nextY >= 0&&nextY <= SIZE-1
    					&&!moves[nextX][nextY]) {
    				moveCount = lookAheadCount(moves,nextX,nextY);
    				if(moveCount <= minMoveCount) {
    					minMoveCount = moveCount;
    					bestMoveX2 = bestMoveX;
    					bestMoveY2 = bestMoveY;
    					bestMoveX = nextX;
    					bestMoveY = nextY;
    				}
    			}
    			nextX = x + j;
    			nextY = y + i;
    			if(nextX >= 0&&nextX <= SIZE-1&&nextY >= 0&&nextY <= SIZE-1
    					&&!moves[nextX][nextY]) {
    				moveCount = lookAheadCount(moves,nextX,nextY);
    				if(moveCount <= minMoveCount) {
    					minMoveCount = moveCount;
    					bestMoveX2 = bestMoveX;
    					bestMoveY2 = bestMoveY;
    					bestMoveX = nextX;
    					bestMoveY = nextY;
    				}
    			}
    		}
    	}
    	moves[bestMoveX][bestMoveY] = true;
    	addMove(bestMoveX,bestMoveY);
    	numberMoves++;
    	if(numberMoves == (SIZE * SIZE))
    		return true;
    	if(moveCount > 0&&solvePuzzle(moves, numberMoves, bestMoveX, bestMoveY))
    		return true;
    	moves[bestMoveX][bestMoveY] = false;
    	moves[bestMoveX2][bestMoveY2] = true;
    	removeLastMoveHistory();
    	addMove(bestMoveX2,bestMoveY2);
    	if(moveCount > 1&&solvePuzzle(moves, numberMoves, bestMoveX2, bestMoveY2)) {
    		return true;
    	}
    	moves[bestMoveX2][bestMoveY2] = false;
    	removeLastMoveHistory();
    	numberMoves--;
    	return false;
    }
    private int lookAheadCount(boolean[][] moves,int x,int y) {
    	int maxCount = 0;
    	for(int i = -2;i<=2;i+=4) {
    		for(int j = -1;j <= 1;j += 2) {
    			int nextX = x + i;
    			int nextY = y + j;
    			if(nextX >= 0&&nextX <= SIZE-1&&nextY >=0 && nextY <= SIZE-1
    					&&!moves[nextX][nextY]) {
    				maxCount++;
    			}
    			nextX = x + j;
    			nextY = y + i;
    			if(nextX >= 0&&nextX <= SIZE-1&&nextY >= 0&&nextY <= SIZE-1&&
    					!moves[nextX][nextY])
    				maxCount++;
    		}
    	}
    	return maxCount;
    }
    public void resetMoves() {
    	moves = new ArrayList(63);
    }
    public void addMove(int x,int y) {
    	moves.add(new Point2D(x, y));
    }
    public void removeLastMoveHistory() {
    	moves.remove(moves.size()-1);
    }
    private class Board extends Pane{
    	Circle theKnight = new Circle();
    	Circle movingKnight = new Circle();
    	
    	Board(){
    		this.setOnMouseClicked(e ->{
    			startX = (int)(e.getX()/(getWidth()/SIZE));
    			startY = (int)(e.getY()/(getHeight()/SIZE));
    			resetMoves();
    			draw();
    		});
    	}
    	protected void draw() {
    		this.getChildren().clear();
    		this.getChildren().add(theKnight);
    		theKnight.setCenterX(startX * getWidth()/SIZE +15);
    		theKnight.setCenterY(startY * getHeight()/SIZE + 15);
    		theKnight.setRadius(5);
    		theKnight.setFill(Color.RED);
    		movingKnight.setCenterX(startX * getWidth()/SIZE +15);
    		movingKnight.setCenterY(startY * getHeight()/SIZE + 15);
    		movingKnight.setRadius(5);
    		movingKnight.setFill(Color.RED);
    		this.getChildren().add(movingKnight);
    		
    		for(int i = 1;i <= SIZE;i++) {
    			this.getChildren().add(
    					new Line(0,i*getHeight()/SIZE,getWidth(),
    							i*getHeight()/SIZE));			                     
    			this.getChildren().add(
    					new Line(i*getWidth()/SIZE,0,i*getWidth()/SIZE,
    							getHeight()));
    		}
    		if(moves != null) {
    			for(int i = 1;i < moves.size();i++) {
    				Point2D p1 = moves.get(i - 1);
    				Point2D p2 = moves.get(i);
    				Line line = new Line(p1.getX()*(getWidth()/SIZE)+(getWidth()/SIZE/2),
    								p1.getY()*(getHeight()/SIZE)+(getHeight()/SIZE/2),
    								p2.getX()*(getWidth()/SIZE)+(getWidth()/SIZE/2),
    								p2.getY()*(getHeight()/SIZE)+(getHeight()/SIZE/2));
    				pathList.add(line);
    			}
    		}
    	}
    	 private void playAnimation(ArrayList<Line> lines) {
    		 int i = 0;
    		 SequentialTransition sequentialTransition = new  SequentialTransition();
    		 Circle c;
    		 c = new Circle(5);
    		 c.setFill(Color.RED);
    		 getChildren().add(c);
    	    for(Line l: lines) {
    	    	PathTransition transition = new PathTransition(Duration.seconds(1), l, c);
    	    	transition.setOnFinished(e->{
    	    		if(i<lines.size()-2) {
    	    			getChildren().add(l);
    	    		}
    	    	});
    	    	sequentialTransition.getChildren().add(transition);
    	    }
    	    sequentialTransition.play();
    	}
    }
}
  • 动画演示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2159694.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024年信息安全企业CRM选型与应用研究报告

数字化的生活给人们带来便利的同时也带来一定的信息安全隐患&#xff0c;如网络侵权、泄露用户隐私、黑客攻击等。在互联网高度发展的今天&#xff0c;信息安全与我们每个人、每个组织甚至每个国家都息息相关。 信息安全行业蓬勃发展。根据智研咨询数据&#xff0c;2021年&…

3DMAX乐高建筑生成器插件LegoBuilding使用方法详解

3DMAX乐高建筑生成器插件LegoBuilding使用教程 3DMAX乐高建筑生成器插件LegoBuilding&#xff0c;一键批量生成随机的乐高积木样式建筑群&#xff0c;可作为配景楼建模使用。可根据闭合样条线画定范围或地形&#xff08;网格&#xff09;对象表面范围和起伏批量生成随机形状的乐…

深入理解音视频pts,dts,time_base以及时间数学公式

引入 首先介绍一下基础名词 DTS&#xff08;Decoding Time Stamp&#xff09;&#xff1a;即解码时间戳&#xff0c;这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。当数据没b帧时&#xff0c;dts pts&#xff0c;有兴趣可参阅我前面视频知识类文章。 PTS&a…

MyBatis - 动态SQL

前言 我们在某网站填写个人信息时&#xff0c;时常会遇到可以选填的空&#xff08;即可填&#xff0c;可不填&#xff09;&#xff0c;由于之前讲过的Java中的SQL语句都是固定的&#xff0c;且我们不可能对所有情况都写出与之对应的插入语句&#xff08;太过繁琐&#xff09;&…

虚幻引擎的三种输入模式和将控件显示到屏幕上

首先要知道一个概念 , HUD 和 Input 都是由 PlayerController 来控制的 而虚幻的Input控制模式有三种 Set Input Mode Game Only (设置输入模式仅限游戏): 视角会跟着鼠标旋转 , 就是正常游戏的模式 , 这也是游戏默认输入模式 Set Input Mode UI Only (设置输入模式仅限UI): …

【操作系统强化】王道强化一轮笔记

第一章 计算机系统概述 考点1 操作系统的概念、特征和功能 1. 2. 考点2 内核态与用户态 1. 2.用户态和内核态之间的切换本质上就是应用程序和操作系统对CPU控制器的切换 考点3 中断和异常 1. 2. 考点4 系统调用 1. 2. 3.C 考点5 操作系统引导 1. 2. ①磁盘的物理格式化&…

APP自动化中 ADB Monkey用法

一、monkey是干什么的&#xff1f; 我们可以使用monkey做手机端性能的压力测试&#xff0c;稳定性测试 二、monkey在使用的时候&#xff0c;他的运行特性 monkey默认配置下执行&#xff0c;会在手机中随机的点击或者轻触我们的手机中应用&#xff0c;不过这个时候&#xff0…

在Windows系统上安装的 flatbuffers C++ 库

步骤一 下载:https://github.com/google/flatbuffers git clone gitgithub.com:google/flatbuffers.git步骤二 打开安装目录,然后再打开该目录下的powershell, 新建build目录 cd build cmake ..步骤三 进入步骤二生成的build目录里面,点击FlatBuffers.sln,打开vs2019 补充…

信息安全工程师(13)网络攻击一般过程

前言 网络攻击的一般过程是一个复杂且系统化的行为&#xff0c;其目标往往在于未经授权地访问、破坏或窃取目标系统的信息。 一、侦查与信息收集阶段 开放源情报收集&#xff1a;攻击者首先会通过搜索引擎、社交媒体、论坛等公开渠道获取目标的基本信息&#xff0c;如姓名、地址…

【经验分享】电商api接口——各类商品数据一键获取

目前&#xff0c;双十一促销活动正在火爆预热进行中。大促期间&#xff0c;消费者常常会做攻略以防被坑&#xff0c;而活动期间&#xff0c;品牌商家方也需要有所行动&#xff0c;避免一些不必要的损失。 大促期间&#xff0c;商家前前后后的改价活动往往比较频繁&#xff0c;…

超分之SPIN

Lightweight image super-resolution with superpixel token interaction[C]利用超像素token交互实现轻量级图像超分辨率Zhang A, Ren W, Liu Y, et al.Proceedings of the IEEE/CVF International Conference on Computer Vision. 2023: 12728-12737. 文章目录 摘要1. 引言2. …

【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)

本文项目编号 T 048 &#xff0c;文末自助获取源码 \color{red}{T048&#xff0c;文末自助获取源码} T048&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计 六、核…

元器件数据手册识别工具

数据手册识别方案&#xff0c;目前有多家厂商实现了这个功能&#xff0c;分别采用不同的技术路线实现。 基于AI方法&#xff1a;使用大量的数据手册进行训练&#xff0c;训练后的将模型文件提供给客户&#xff0c;用户在程序中加载模型文件和数据手册得到手册里面的数据结果。 …

Python中requests模块(爬虫)基本使用

Python的requests模块是一个非常流行的HTTP库&#xff0c;用于发送HTTP/1.1请求。 一、模块导入 1、requests模块的下载&#xff1a; 使用包管理器下载&#xff0c;在cmd窗口&#xff0c;或者在项目的虚拟环境目录下&#xff1a; pip3 install -i https://pypi.tuna.tsingh…

JUC高并发编程1:JUC概述

1 什么是JUC 1.1 JUC简介 JUC就是 java.util .concurrent 工具包的简称。这是一个处理线程的工具包&#xff0c;JDK 1.5 开始出现的。 1.2 进程与线程 进程&#xff08;Process&#xff09;和线程&#xff08;Thread&#xff09;是操作系统中用于实现多任务处理的两种基本概…

Linux 基本指令的学习

01. ls 指令 语法 &#xff1a; ls [ 选项 ][ 目录或文件 ] 功能 &#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 常用选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以 . 开头的隐含…

计算机二级C语言疑难

1.strcpy函数 在C语言中strcpy&#xff08;&#xff09;函数会将字符串2&#xff08;包括字符串结束字符/0&#xff09;的函数覆盖到字符串1&#xff0c;如果字符串1没有足够的空间容纳字符串会导致缓冲溢出的错误 例题&#xff1a;程序设计 规定输入的字符串中只包含字母和…

2.Spring-容器-注入

注册&#xff1a;将组件放入容器中&#xff1b; 注入&#xff1a;让容器按需进行操作&#xff1b; 一、Autowired&#xff1a;自动注入组件 原理&#xff1a;Spring调用容器的getBean 二、Qualifier 精确指定 精确指定&#xff1a;如果容器中组件存在多个&#xff0c;则使用…

在虚幻引擎中实现Camera Shake 相机抖动/震屏效果

在虚幻引擎游戏中创建相机抖动有时能让画面更加高级 , 比如 遇到大型的Boss , 出现一些炫酷的特效 加一些短而快的 Camera Shake 能达到很好的效果 , 为玩家提供沉浸感 创建Camera Shake 调整Shake参数 到第三人称或第一人称蓝图 调用Camera Shake Radius值越大 晃动越强

Nginx基础详解1(单体部署与集群部署、负载均衡、正反代理、nginx安装)

本阶段的任务 1.学会集群的操作概念 2.完成对Nginx的入门操作 3.使用Nginx实现集群和负载均衡 4.使用Nginx实现高可用的方案 目录 1.单体部署与集群部署 1.1单体部署的概念 1.2单体部署的优缺点 1.3集群部署的概念 1.4集群部署的优缺点 1.5集群部署需要注意的点 1.…