月神之箭(Elune’s Arrow)

本文介绍了Dota游戏中的月神之箭问题,将其转化为数学几何问题,探讨如何判断POM能否射中目标敌人。通过遍历多边形顶点并计算向量的正交分量来确定射线是否穿过多边形,从而实现算法。程序通过读取输入文件,利用点、向量和多边形类进行计算,并输出结果。
摘要由CSDN通过智能技术生成

月神之箭(Elune’s Arrow)

(10102510352)

问题描述

    在游戏dota(TheDefense of Ancients,暴风雪集团的一款RPG游戏,深受广大青少年的喜爱,本人曾经在一段时间内十分欣赏该款游戏)中,有一个英雄叫月亮之神(以下简称POM),她的第二个招数叫“月神之箭”,这招能给敌人带来巨大的伤害。当POM的箭沿着直线飞出后,击中敌人便会消失。

    题目现在假设,POM躲在树林里,想使用第二招射杀一个很重要的一个敌人。在敌人的周围有其他敌方单位,当POM的箭射错了方向或者是射到了敌方的其他单位,敌人将不会被射中。现在给出一个箭射出的指定方向,我们得去判断这个敌人是否会被集中。

    已知:敌方单位的个数,包括目标敌人(一个整数);POM所在的位置(两个整数,代表POM所在位置的平面坐标);POM的箭射出的方向(两个整数(x0,y0),表示射箭方向的向量);若干个敌人单位(每个敌人的表示方法为:m x1 y1 x2 y2… xm ym,敌方单位为一个凸多边形,m表示多边形的顶点个数,x1 y1,x2 y2…分别表示每个顶点的平面坐标。并且,POM不在多边形内,也不再多边形的边上。

    求解:POM是否能射中目标敌人。能的话,输出“HIT”,不能则输出“MISS”。

解题思路

    这是一道从游戏中挖掘的题目,但是不难看出,这是一道很纯粹的数学几何题。POM是一个点,射箭的方向便是一条射线,敌方单位是多边形,于是题目便可翻译成数学几何题:已知一个定点以及从该点发出的射线,求解该射线能不能从给定的几个多边形中通过。于是,一个游戏题目,就完全可以使用我们所学的数学只是来解答。

我们可以先关注该射线是否能穿过一个多边形这个问题,多个多边形只需要采取同样的方法便可得出结果。先给出一个图:

                                                                                                

                                                                                         

    P0是题目给出的定点,n0是射线的向量,s和r分别表示p0到两个点的向量,不难看出s和r向量在n0的正交向量即P’0上的分量的符号是相反的,也就是说s* P’0与r* P’0的符号是相反的。

    从以上结论出发,我们便很快可以思考出解决该问题的算法。我们只需要遍历多边形的不同的两个顶点,遍历的同时判断该两点与定点P0的向量在射线的正交向量的分向量之积为正数还是负数,如果遍历的时候出现一次负数,则表示射线肯定经过该多边形,于是可以停止遍历。如果全部正数,则表示射线与多边形不相交。当然,如果正好为0,则表示某个顶点在射线的方向上,但是,这个时候必须注意,当定点在射线的相反方向是,结果也等于0,因此不能直接判断该点就在射线上。观察得知,当某个定点在射线上时,另外一个顶点与定点连接的向量与射线向量的积必然为正数,所以据此可以判断为0的情况。

算法与分析

    由解题思路分析得到的结果,可以很快的设计出算法。

    首先,我们需要去遍历每一个敌方单位,第一个遍历的对象为目标敌人,如果目标敌人都无法击中,则表示POM根本无法射中,停止遍历,输出结果为“MISS”,伪代码如下:

for e:enemies[enemyNum]
     if 射不中
	break 停止程序
  else
	continue 继续遍历

    如果能够击中目标敌人,我们也不能立即就输出“HIT”,因为POM也有可能及击中其他单位,于是目标敌人便击不中了。我们下一步需要遍历其他地方单位,如果遍历到有一个敌方单位被击中,则停止遍历,输出“MISS”,表示POM击中了其他敌人。伪代码如下:

for e:otherenemies[enemyNum]
     if 射中
	break 停止程序
  else
	continue 继续遍历

    如果遍历后发现只有目标敌人能被击中,则输出“HIT”,表示目标敌人能够被POM击中。至此,我们所有逻辑都已经确定,但是最重要的判断是否射中的算法还未给出。判断是否射中,主要是去判断每一个敌人的每两个顶点与定点的向量还有射线的正交向量之积是否存在符号相反的情况,如果出现,可立即判断该敌方单位能被射中,如果出现积为0的情况,需要计算顶点与定点连接的向量与射线向量的积是否有一个为正数,如果有,则能够射中,如果不能,则无法射中。具体算法,请看伪代码:

 

for i:vertices[m]
  for j:vertices[m]
	v0 := i与定点连接的向量
	v1 := j 与定点连接的向量
	p’0 := 射线的正交向量
	r := (v0*p’0)*(v1*p’0)
	if r<0
	   射中
	else if r=0
	   p0 :=射线的正交向量
	   r1 :=(v0*p0)
	   r2 :=(v1:p0)
	   if r1>0 或者r2>0
		射中
	    else
		射不中

至此,所有关键的算法都已经讨论并且实现完毕。

程序说明

1、classPoint

   点对象,该对象有两个类变量,x和y,分别表示点的横坐标和纵坐标

2、classPolygon

   多边形对象,该对象有一个类变量,vertices[],其类型为point数组,即多边形有点的数组表示

3、classVector

   向量对象,该对象有两个类变量,a和b,分别表示向量的横坐标和纵坐标。

4、intenemyNum

   敌方单位的数量

5、PointpomPlace

   POM所在的位置

6、VectorflyDirection

   POM射箭的方向

7、Polygon[]enemy[]

   敌方单位的数组

8、voidmain()

   程序的主函数,也是程序的入口,负责整个程序的逻辑控制,以及核心算法的实现。

9、voidgetInput()

   从一个txt文件中获取输入信息

程序清单

 

package sei.zwf.main;

 

import java.io.BufferedReader;

 

import java.io.File;

import java.io.FileNotFoundException;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值