2016-12-26 7 views
5

के भीतर आप लेजर बीम के साथ एक लक्ष्य को कैसे मार सकते हैं आप आयताकार आकार वाले कमरे के भीतर एक दुश्मन के साथ सामना कर रहे हैं और आपको केवल एक लेजर बीम हथियार मिला है, कमरे में इसमें कोई बाधा नहीं है और दीवारें लेजर बीम को पूरी तरह से प्रतिबिंबित कर सकती हैं। हालांकि लेजर बेकार हो जाने से पहले केवल एक निश्चित दूरी की यात्रा कर सकता है और यदि यह एक कोने पर पहुंच जाता है तो यह उसी दिशा में वापस दिखाई देगा जो यह आया था।पहेली: चार प्रतिबिंबित दीवारों

इस प्रकार पहेली जाती है और आपको अपने स्थान के समन्वय और लक्ष्य के स्थान, कमरे के आयाम और बीम यात्रा की अधिकतम दूरी प्रदान की जाती है। उदाहरण के लिए, तो कमरे में 2 से 3 है और अपने स्थान है (1, 1) और लक्ष्य है (2, 1) तो संभव समाधान हैं:

All possible ways to hit the target (2, 1) from (1, 1) in 3x2 room

मैं निम्नलिखित दृष्टिकोण की कोशिश की, से शुरू स्रोत (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)। क्या ऐसा करने के लिए कोई बेहतर तरीका या शायद कुछ प्रकार का एल्गोरिदम है?

+0

क्या आप सभी दीवारों पर लक्ष्य मिरर द्वारा शुरू किया है; फिर सभी दीवारों पर दर्पण छवियों को दर्पण करें और तब तक लेजर के लक्ष्य तक पहुंचने के लिए दूरी बहुत बड़ी हो जाती है? लक्षित लक्ष्य की किसी भी दिशा में किसी भी लेजर शॉट ने उस लक्ष्य को मारा होगा। –

+0

@hiroprotagonist बहुत रोचक, लेकिन मैं टैगेट दर्पण स्थानों की गणना करने के बारे में कैसे जा सकता हूं? – user7342539

+0

क्या इस मामले पर विचार किया जाना चाहिए कि बीम मूल को हिट करता है? या यह हस्तक्षेप के बिना बस इसके माध्यम से जाना होगा? – trincot

उत्तर

3

क्या होगा यदि आपने सभी दीवारों पर लक्ष्य को प्रतिबिंबित करना शुरू किया; फिर सभी दीवारों पर दर्पण छवियों को दर्पण करें और तब तक लेजर के लक्ष्य तक पहुंचने के लिए दूरी बहुत बड़ी हो जाती है? लक्षित लक्ष्य की किसी भी दिशा में किसी भी लेजर शॉट ने उस लक्ष्य को मारा होगा। (यह ऊपर से मेरी टिप्पणी है; उत्तर को और अधिक आत्मनिर्भर बनाने के लिए यहां दोहराया गया है ...)

यह उत्तर का मिररिंग हिस्सा है: get_mirroredpoint की चार दर्पण छवियों को वापस दर्पण-बॉक्स के साथ वापस कर देगा BOTTOM_LEFT और 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)] 

जो लक्ष्य एक बार नजर आता।

तो आप तब तक पुन: सक्रिय कर सकते हैं जब तक कि सभी प्रतिबिंबित लक्ष्य सीमा से बाहर न हों। सीमा के भीतर सभी दर्पण छवियां आपको एक दिशा देगी जिसमें आपके लेजर को इंगित किया जाए।


इस

एक तरह से कैसे आप iteratively एक दिया 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 
+1

नहीं मारना चाहिए शूटर और दर्पण लक्ष्य के बीच की लंबाई यह शूटर के बीच परिलक्षित बीम की कुल लंबाई के बराबर है और वास्तविक लक्ष्य? – user7342539

+0

बिंदु मिररिंग 'प्रक्षेपण को सीधा करना' है। तो हाँ! –

+0

मेरे 'रेट्रेस' समारोह के मुताबिक बीम (1,1) से (4,3) बीम इन बिंदुओं (1,1), (2.5,2), (3,1.67), (2,1) के माध्यम से गुजरता है '' 5.4' '[[[(1, 1), 34.0] की कुल लंबाई के साथ, [(2.5, 2.0), 33.6 9], [(3.0, 1.67), 326.31], [(2, 1)]], 5.41] 'जबकि (1,1) और (4,3) के बीच की दूरी' 3.6' – user7342539

संबंधित मुद्दे