谜题:在四个反射墙内,激光束可以通过多少种方式击中目标

2024-01-09

你在一个长方形的房间里遇到敌人,你只有一把激光武器,房间里没有任何障碍物,墙壁可以完全反射激光束。然而,激光只能传播一定的距离,然后就变得毫无用处,如果它撞到角落,它会沿着它来的方向反射回来。

这就是谜题的进行方式,您将获得自己所在位置和目标位置的坐标、房间尺寸以及光束可以传播的最大距离。例如,如果房间是 3 x 2,您的位置是 (1, 1),目标是 (2, 1),那么可能的解决方案是:

我尝试了以下方法,从源 (1, 1) 开始并以角度 0 弧度创建一个矢量,跟踪矢量路径和反射,直到它击中目标或矢量的总长度超过最大允许长度,重复以0.001弧度为间隔,直到完成一个完整的循环。这是我到目前为止的代码:

from math import *

UPRIGHT = 0
DOWNRIGHT = 1
DOWNLEFT = 2
UPLEFT = 3
UP = 4
RIGHT = 5
LEFT = 6
DOWN = 7

def roundDistance (a):
    b = round (a * 100000)
    return b / 100000.0

# only used for presenting and doesn't affect percision
def double (a):
    b = round (a * 100)
    if b / 100.0 == b: return int (b)
    return b / 100.0

def roundAngle (a):
    b = round (a * 1000)
    return b / 1000.0

def isValid (point):
    x,y = point
    if x < 0 or x > width or y < 0 or y > height: return False
    return True

def isCorner (point):
    if point in corners: return True
    return False

# Find the angle direction in relation to the origin (observer) point
def getDirection (a):
    angle = roundAngle (a)
    if angle == 0: return RIGHT
    if angle > 0 and angle < pi / 2: return UPRIGHT
    if angle == pi / 2: return UP
    if angle > pi / 2 and angle < pi: return UPLEFT
    if angle == pi: return LEFT
    if angle > pi and angle < 3 * pi / 2: return DOWNLEFT
    if angle == 3 * pi / 2: return DOWN
    return DOWNRIGHT

# Measure reflected vector angle
def getReflectionAngle (tail, head):
    v1 = (head[0] - tail[0], head[1] - tail[1])
    vx,vy = v1
    n = (0, 0)
    # Determin the normal vector from the tail's position on the borders
    if head[0] == 0: n = (1, 0)
    if head[0] == width: n = (-1, 0)
    if head[1] == 0: n = (0, 1)
    if head[1] == height: n = (0, -1)
    nx,ny = n
    # Calculate the reflection vector using the formula:
    # r = v - 2(v.n)n
    r = (vx * (1 - 2 * nx * nx), vy * (1 - 2 * ny * ny))
    # calculating the angle of the reflection vector using it's a and b values
    # if b (adjacent) is zero that means the angle is either pi/2 or -pi/2
    if r[0] == 0:
        return pi / 2 if r[1] >= 0 else 3 * pi / 2
    return (atan2 (r[1], r[0]) + (2 * pi)) % (2 * pi)

# Find the intersection point between the vector and borders
def getIntersection (tail, angle):
    if angle < 0:
        print "Negative angle: %f" % angle
    direction = getDirection (angle)
    if direction in [UP, RIGHT, LEFT, DOWN]: return None
    borderX, borderY = corners[direction]
    x0,y0 = tail
    opp = borderY - tail[1]
    adj = borderX - tail[0]
    p1 = (x0 + opp / tan (angle), borderY)
    p2 = (borderX, y0 + adj * tan (angle))
    if isValid (p1) and isValid (p2):
        print "Both intersections are valid: ", p1, p2
    if isValid (p1) and p1 != tail: return p1
    if isValid (p2) and p2 != tail: return p2
    return None

# Check if the vector pass through the target point
def isHit (tail, head):
    d = calcDistance (tail, head)
    d1 = calcDistance (target, head)
    d2 = calcDistance (target, tail)
    return roundDistance (d) == roundDistance (d1 + d2)

# Measure distance between two points
def calcDistance (p1, p2):
    x1,y1 = p1
    x2,y2 = p2
    return ((y2 - y1)**2 + (x2 - x1)**2)**0.5

# Trace the vector path and reflections and check if it can hit the target
def rayTrace (point, angle):
    path = []
    length = 0
    tail = point
    path.append ([tail, round (degrees (angle))])
    while length < maxLength:
        head = getIntersection (tail, angle)
        if head is None:
            #print "Direct reflection at angle (%d)" % angle
            return None
        length += calcDistance (tail, head)
        if isHit (tail, head) and length <= maxLength:
            path.append ([target])
            return [path, double (length)]
        if isCorner (head):
            #print "Corner reflection at (%d, %d)" % (head[0], head[1])
            return None
        p = (double (head[0]), double (head[1]))
        path.append ([p, double (degrees (angle))])
        angle = getReflectionAngle (tail, head)
        tail = head
    return None

def solve (w, h, po, pt, m):
    # Initialize global variables
    global width, height, origin, target, maxLength, corners, borders
    width = w
    height = h
    origin = po
    target = pt
    maxLength = m
    corners = [(w, h), (w, 0), (0, 0), (0, h)]
    angle = 0
    solutions = []
    # Loop in anti-clockwise direction for one cycle
    while angle < 2 * pi:
        angle += 0.001
        path = rayTrace (origin, angle)
        if path is not None:
            # extract only the points coordinates
            route = [x[0] for x in path[0]]
            if route not in solutions:
                solutions.append (route)
                print path

# Anser is 7
solve (3, 2, (1, 1), (2, 1), 4)

# Answer is 9
#solve (300, 275, (150, 150), (185, 100), 500)

该代码以某种方式工作,但它没有找到所有可能的解决方案,我有一个很大的精度问题,我不知道在比较距离或角度时应该考虑多少位小数。我不确定这是否是正确的方法,但这是我能做到的最好的方法。

如何修复我的代码以提取所有解决方案?我需要它高效,因为房间可能会变得很大(500 x 500)。有没有更好的方法或者某种算法来做到这一点?


如果您首先在所有墙壁上镜像目标会怎样?然后在所有墙壁上镜像镜像,依此类推,直到距离太大而激光无法到达目标?向镜像目标任何方向发射的任何激光都会击中该目标。 (这是我上面的评论;在这里重复以使答案更加独立......)

这是答案的镜像部分:get_mirrored将返回四个镜像point镜盒受限于BOTTOM_LEFT and TOP_RIGHT.

BOTTOM_LEFT = (0, 0)
TOP_RIGHT = (3, 2)

SOURCE = (1, 1)
TARGET = (2, 1)

def get_mirrored(point):
    ret = []

    # mirror at top wall
    ret.append((point[0], point[1] - 2*(point[1] - TOP_RIGHT[1])))
    # mirror at bottom wall
    ret.append((point[0], point[1] - 2*(point[1] - BOTTOM_LEFT[1])))
    # mirror at left wall
    ret.append((point[0] - 2*(point[0] - BOTTOM_LEFT[0]), point[1]))
    # mirror at right wall
    ret.append((point[0] - 2*(point[0] - TOP_RIGHT[0]), point[1]))
    return ret

print(get_mirrored(TARGET))

这将返回给定点的 4 个镜像:

[(2, 3), (2, -1), (-2, 1), (4, 1)]

这是镜像一次的目标。

然后你可以迭代,直到所有镜像目标都超出范围。范围内的所有镜像都会为您提供激光指向的方向。


这是一种如何在给定的时间内迭代地到达镜像目标的方法DISTANCE

def get_targets(start_point, distance):

    all_targets = set((start_point, ))  # will also be the return value
    last_targets = all_targets          # need to memorize the new points

    while True:
        new_level_targets = set()  # if this is empty: break the loop
        for tgt in last_targets:   # loop over what the last iteration found
            new_targets = get_mirrored(tgt)
            # only keep the ones within range
            new_targets = set(
                t for t in new_targets
                if math.hypot(SOURCE[0]-t[0], SOURCE[1]-t[1]) <= DISTANCE)
            # subtract the ones we already have
            new_targets -= all_targets
            new_level_targets |= new_targets
        if not new_level_targets:
            break
        # add the new targets
        all_targets |= new_level_targets
        last_targets = new_level_targets  # need these for the next iteration

    return all_targets

DISTANCE = 5    

all_targets = get_targets(start_point=TARGET, distance=DISTANCE)
print(all_targets)

all_targets现在是set包含所有可到达的点。

(这些都没有经过彻底测试......)


您的反例的小更新:

def ray_length(point_list):
    d = sum((math.hypot(start[0]-end[0], start[1]-end[1])
            for start, end in zip(point_list, point_list[1:])))
    return d

d = ray_length(point_list=((1,1),(2.5,2),(3,1.67),(2,1)))
print(d)  # -> 3.605560890844135

d = ray_length(point_list=((1,1),(4,3)))
print(d)  # -> 3.605551275463989
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

谜题:在四个反射墙内,激光束可以通过多少种方式击中目标 的相关文章

  • pywinauto 32位用户警告

    我正在尝试使用 pywinauto 在每次更新类文件时自动启动和停止 TomCat 但是 当我尝试运行它时 它会给出以下警告 UserWarning 32 bit application should be automated using
  • 如何有效地从连续字符串中提取文字单词? [复制]

    这个问题在这里已经有答案了 可能的重复 如何将没有空格的文本拆分为单词列表 https stackoverflow com questions 8870261 how to split text without spaces into li
  • Django:将博客条目查看次数增加一。这有效率吗?

    我的索引视图中有以下代码 latest entry list Entry objects filter is published True order by date published 10 for entry in latest ent
  • Pandas 字符串提取所有匹配项

    我正在学习 pandas 系列字符串方法中的正则表达式操作 我能够从字符串中提取第一个数字 但我的正则表达式与第二个数字不匹配 如何捕获这两个数字 注意第二行 第二个元素在这里是 NAN CODE import pandas as pd d
  • 如何测试使用 XCom 的 Apache Airflow 任务

    我正在尝试找出一种测试 DAG 的方法 其中有几个任务使用 XCom 进行通信 由于控制台命令只允许我从 DAG 运行任务 有没有一种方法可以测试通信而无需通过 UI 运行 DAG Thanks 这是一种对我有用的方法 尽管 Airflow
  • 如何使用 lxml 解析包含前缀但没有名称空间声明的 XML?

    我有一堆使用前缀但没有相应名称空间声明的 XML 文件 像这样的东西
  • 蜘蛛内的Scrapyd jobid值

    Scrapy 框架 Scrapyd 服务器 我在获取蜘蛛内部的 jobid 值时遇到一些问题 将数据发布到后http localhost 6800 schedule json http localhost 6800 schedule jso
  • Spyder 导入模块出错

    我正在尝试在 Spyder 中使用 sklearn 一开始 当我尝试导入它时 我收到 ImportError No module named sklearn 然后我用 PYTHONPATH 管理器设置 PATH 然后使用工具菜单中的 更新模
  • 使用 Pymongo 从 Windows 连接到 AWS 实例上的 MongoDB

    此行反复抛出错误 client MongoClient ec2 12 345 67 89 us east 2 compute amazonaws com 27017 ssl True ssl keyfile C mongo pem 由于显而
  • 从主机名中提取域名

    是否有一种编程方式可以从给定的主机名查找域名 给出 gt www yahoo co jp 返回 gt yahoo co jp 有效但非常慢的方法是 拆分为 并从左侧删除 1 个组 使用 dnspython 加入并查询 SOA 记录 当返回有
  • 使用 boto3 从 s3 下载时使用 filename 作为文件名

    我正在使用 boto3 上传文件 如下所示 client boto3 client s3 aws access key id id aws secret access key key client upload file tmp test
  • Flask 中的 import 和 extends 有什么区别?

    我正在阅读 Flask Web 开发 在例4 3中 extends base html import bootstrap wtf html as wtf 我想知道 extends 和 import 有什么区别 我认为它们在用法上很相似 在什
  • 如何删除 pandas 数据框中的唯一行?

    我遇到了一个看似简单的问题 在 pandas 数据框中删除唯一的行 基本上 相反drop duplicates https pandas pydata org pandas docs stable generated pandas Data
  • PyCharm - 如何挂起所有线程

    我们使用 PyCharm 5 0 1 进行多线程调试 当它在断点处停止时 只有特定线程停止 而所有其他线程继续 这使得 冻结时刻 和检查参数值以及其他线程的当前状态变得困难 当其中一个线程在断点处停止时 是否可以挂起所有线程 这在最新的 P
  • 在python中安装scipy模块时出错

    我正在尝试使用 pip 在 python 中安装 scipy 模块 它显示以下错误 Command c users sony appdata local programs python python35 32 python exe u c
  • Scrapy的redirect_urls异常.KeyError

    我是 Scrapy 和 Python 的新手 最近推出了我的第一个蜘蛛 有一个功能似乎以前有效 但现在它只适用于我试图废弃的一些网站 代码行是 item url direct response request meta redirect u
  • 使用 statsmodels.formula.api 中的 ols - 如何删除常数项?

    我正在遵循第一个例子statsmodels教程 http statsmodels sourceforge net devel http statsmodels sourceforge net devel 如何指定在 ols 中不使用常数项进
  • Python 队列 get()/task_done() 问题

    我的消费者端队列 m queue get queue task done
  • 如何限制scrapy请求对象?

    所以我有一个蜘蛛 我认为它正在泄漏内存 结果当我检查 telnet 控制台 gt gt gt prefs 时 它只是从链接丰富的页面中抓取了太多链接 有时它会超过 100 000 个 现在我已经一遍又一遍地浏览文档和谷歌 但我找不到一种方法
  • django admin 中内联模型的分页器

    我有这个简单的 django 模型 由一个传感器和特定传感器的值组成 每个日射强度计的值数量很多 gt 30k 是否可以以某种方式分页PyranometerValues在特定日期或一般情况下将分页器应用于管理内联视图 class Pyran

随机推荐

  • 使用JFrame作为自定义输入框

    我正在开发一个基于 java swing 的应用程序 其中我有两个JFrames A 这是主窗口 并且B 这被称为A 我需要做的是 在A call B 获取用户输入B并将该输入传递给A以某种方式 然后处理它 我尝试过的一切都失败了 据我所知
  • MySQL 连接器 NO_CIPHERS_AVAILABLE 错误

    我正在使用 MySQL 连接器为我的简单 python 应用程序创建连接 但是每次运行它时 它都会失败并返回以下错误 2055 Lost connection to MySQL server at databaseHost system e
  • ResourceManager 包 - 包未正确加载

    我在 VS2015 和 cordova 项目中遇到问题 当天早些时候 我的项目进展顺利 但是 我将一个项目移动到一个新文件夹 现在 VS2015 无法正常工作 它正在运行 但不知何故 webessentials 被卸载 我的 gulpfil
  • PowerShell :: Microsoft.Azure.Commands.Sql.Database.Model.AzureSqlDatabaseModel.DatabaseName [重复]

    这个问题在这里已经有答案了 我编写了一个脚本 允许我查询整个 Azure 数据库公园 ErrorActionPreference SilentlyContinue Connect to Azure azureAccount Connect
  • 为什么 runBlocking 不会阻塞调用线程

    我试图理解 kotlin 中的 runBlocking println before runBlocking Thread currentThread name runBlocking but this expression blocks
  • Avro在消费端通过kafka自定义解码UUID

    我编写了一个类来将 UUID 类型的对象自定义编码为要在 kafka 和 avro 之间传输的字节 为了使用这个类 我放了一个 AvroEncode using UUIDAsBytesEncoding class 在我的目标对象中的 uui
  • BLOC 状态更改后有状态小部件未重建

    我无法理解为什么我的 Stateful 小部件在重建后没有更新状态 我有一个有状态的小部件 负责每秒递减一个计数器 因此它收到一个初始值 我将此初始值传递给状态并开始递减它 它还具有一个按钮 当按下该按钮时 会向我的块发送一个事件 该块会使
  • NoClassDefFoundError(初始化失败) - Websphere 和 IBM MQ

    我在部署到 Websphere 并与 IBM MQ 交互的基于 Spring 的 Web 应用程序上遇到问题 一切都很好 直到我尝试一些故障测试 当 Web 应用程序启动并运行时 我停止 IBM MQ 然后 我调用 Web 应用程序发送 J
  • 如何使用 Java 获取 Linux 中的总磁盘空间?

    我能够获得可用磁盘空间 我如何获得总磁盘空间 我的代码是 import java io IOException import org apache commons io FileSystemUtils public class DiskSp
  • 此 linq 查询是否在 for-each 循环的每次迭代上运行?

    在关于 SO 的另一个问题中 我用如下代码回答 并得到一条评论 即 LINQ 查询可能在 for each 的每次迭代中进行评估 真的吗 我知道 LINQ 查询在其项目被评估之前不会执行 因此这种迭代结果的方式似乎可以使其在每次迭代中运行
  • SQL / PHP PDO 选择随机行

    我希望能够随机选择一名未参加考试的学生 N 并回显姓名和主题 我怎样才能实现这个目标 query db gt prepare SELECT name FROM exams WHERE faced array array N query gt
  • 使用 GSON 解析 JSON

    我在使用 GSON 时遇到了一些问题 主要是从 JSON 反序列化为 POJO 我有以下 JSON events event id 628374485 title Developing for the Windows Phone event
  • 无法绑定 GridView 列中的项目列表

    我正在构建一个应用程序 向用户显示系列比赛的实时结果 我设置数据结构如下 Countries gt Leagues gt Matches特别是在 ViewModel 中 我创建了一个可观察的国家 地区集合 如下所示 private Obse
  • Silverlight - 在 XAML 中而不是在构造函数中设置 DataContext?

    如何在 XAML 中而不是在构造函数中设置 Grid 上的 DataContext 以下是我在构造函数中执行此操作的方法 LayoutRoot 是 XAML 中定义的 XAML 网格 this LayoutRoot DataContext
  • 使用共享静态 WCF 代理客户端有哪些陷阱?

    我正在考虑将共享 读取静态 WCF 代理客户端用于高吞吐量应用程序 我相信这样做可以提高性能 但我还没有对此进行基准测试 这个想法有一些严重的缺陷吗 从我的研究中 我可以看到存在处理故障状态的问题 目前尚不清楚该状态对其他待处理请求的影响流
  • Django/Python - 每秒更新数据库

    我正在努力用 Django 和 Python 创建一个基于浏览器的游戏 并且我正在尝试为我遇到的问题之一找到解决方案 本质上 每一秒都需要更新多个用户变量 例如 有一个货币变量应该每秒增加一定数量 随着你的升级和所有这些爵士乐而逐渐变大 我
  • 在 Kotlin 中编写 React Native Android 模块?

    React Native 文档提供了吐司模块 https facebook github io react native docs native modules android html用java编写的例子 同样的例子在 Kotlin 中是
  • JSON和Unity,在游戏上显示图像[重复]

    这个问题在这里已经有答案了 我有一个测验游戏应用程序 并且我有游戏上的图像 我想显示图像 文本显示得很好 但图像却不是 这是我的 JSON C 代码 点击这里图片 https i stack imgur com AEaFB png 调用我的
  • 为什么 Rails 不断发回 Set-Cookie 标头?

    我遇到了弹性负载均衡器和清漆缓存的问题 涉及 cookie 和会话在 Rails 和客户端之间混淆 问题的一部分是 rails 几乎在每个请求上都添加了一个带有会话 ID 的 Set Cookie 标头 如果客户端已经发送session i
  • 谜题:在四个反射墙内,激光束可以通过多少种方式击中目标

    你在一个长方形的房间里遇到敌人 你只有一把激光武器 房间里没有任何障碍物 墙壁可以完全反射激光束 然而 激光只能传播一定的距离 然后就变得毫无用处 如果它撞到角落 它会沿着它来的方向反射回来 这就是谜题的进行方式 您将获得自己所在位置和目标