ห้องนี้สว่างแค่ไหน? 🔥 pt 1


25

เกี่ยวข้องกับคำถามนี้

ห้องพักที่ถูกกำหนดให้เป็น (ไม่จำเป็นต้องนูน) ไม่ใช่ตัดเหลี่ยมหลายรูปแสดงเป็นรายการสั่งซื้อของพิกัด 2 มิติ หลอดไฟที่สว่างเพียงพอจะถูกวางไว้ที่จุดเฉพาะภายในห้องและปล่อยแสงในทุกทิศทาง งานของคุณคือการหาพื้นที่ที่สว่างรวมของห้อง คุณสามารถป้อนข้อมูลในรูปแบบที่เหมาะสม จุดต่างๆบนรูปหลายเหลี่ยม / ห้องรวมถึงพิกัดของแหล่งกำเนิดแสงนั้นเป็นจำนวนตรรกยะ พวกเขาสามารถนำมาในทวนเข็มนาฬิกาหรือทวนเข็มนาฬิกาทั้งสองรูปแบบเป็นเรื่องปกติ กรณีทดสอบในปัญหาได้รับทวนเข็มนาฬิกา

ภาพต่อไปนี้แสดงห้องตัวอย่างสองห้องโดยที่จุดสีม่วงแสดงถึงแหล่งกำเนิดแสงและพื้นที่แรเงาแสดงพื้นที่ที่ส่องสว่างภาพวาดของห้องที่มีแสง - บริเวณที่แรเงาจะติดสว่าง

กรณีทดสอบ:

(1/2, 18)
(1,3)
(5,1/2)
(7,5)
(12,7)
(16,3)
(15,11)
(8,19)
(3,7)
Light source located at (5,8)
Answer: 815523/6710 ≈ 121.538

นี่เป็นภาพกราฟิกของคำตอบของกรณีทดสอบ จุดสองจุดที่กำหนดโซลูชันที่ไม่ได้อยู่ในรูปหลายเหลี่ยมดั้งเดิมคือ (55/61, 363/61) และ (856/55, 357/55) ป้อนคำอธิบายรูปภาพที่นี่

สูตรนี้อาจมีประโยชน์ในการคำนวณพื้นที่ https://en.wikipedia.org/wiki/Shoelace_formula

เนื่องจากนี่คือรหัสที่สั้นที่สุดเป็นไบต์จะเป็นผู้ชนะ


สำหรับผู้ที่อยากรู้อยากเห็นส่วนที่ 2 อาจใช้เวลาสักครู่ในการโพสต์เพราะมันจะพาฉันไปตลอดกาลเพื่อวาดภาพและฉันก็ไม่รู้วิธีแก้มัน
หัวเรือใหญ่

จุดต่างๆบนรูปหลายเหลี่ยม / ห้องรวมถึงพิกัดของแหล่งกำเนิดแสงนั้นเป็นจำนวนตรรกยะ
หัวเรือใหญ่

มีขอบเขตบนของจำนวนจุดยอดหรือโปรแกรมของคุณควรจะสามารถจัดการกับจำนวนไม่ จำกัด ในทางทฤษฎีหรือไม่? นอกจากนี้แท็กโค้ดกอล์ฟของคุณก็ใช้งานไม่ได้ มันคือ[tag:code-golf]
Veskah

3
อาสูตรเชือกผูกรองเท้าที่ดีเก่า! โดยวิธีการที่เรามี MathJax ดังนั้นคุณไม่จำเป็นต้องฝังสูตรเป็นภาพ
Giuseppe

1
ใช่พวกเขาสามารถรับประกันการสั่งซื้อตามเข็มนาฬิกาแล้ว กรณีทดสอบได้รับคำสั่งทวนเข็มนาฬิกา แต่ฉันคิดว่านี่อยู่ภายใต้“ รูปแบบที่เหมาะสมใด ๆ ”
rigged

คำตอบ:


12

Python 3 , 388 398 408 409 415 417 493ไบต์


เพื่อให้แม่นยำยิ่งขึ้น n

from random import*
u=uniform
c=lambda A,B,C:(C[1]-A[1])*(B[0]-A[0])>(B[1]-A[1])*(C[0]-A[0])
I=lambda A,B,C,D:c(A,C,D)!=c(B,C,D)and c(A,B,C)!=c(A,B,D)
def a(l,v,n=9**6,s=0):
 g=lambda i:(min(x[i]for x in v),max(x[i]for x in v))
 for _ in'x'*n:
  h=((u(*g(0)),u(*g(1))),l);s+=any([I(*f,*h)for f in list(zip(v,v[1:]+[v[0]]))])^1
 return(abs(g(0)[0]-g(0)[1])*abs(g(1)[0]-g(1)[1]))*float(s/n)

วิธีการพื้นฐานของ Monte-Carlo ขั้นตอนด้านล่าง

  1. ค้นหาช่วง x และ y ที่รูปร่างนั้นมี
  2. สร้างรายการขอบที่สร้างโดยจุดยอด
  3. ซ้ำหลายครั้ง (ยิ่งมากยิ่งดี)
  4. สร้างจุดสุ่ม (j, k) ภายในช่วง x, y
  5. ตรวจสอบว่ามีการตัดขอบใด ๆ กับส่วนของเส้นที่สร้างโดยแสงและจุดสุ่ม หากมีการตัดขอบใด ๆ ให้เพิ่มตัวแปรs
  6. หารsด้วยตัวเลขทั้งหมดแล้วคูณด้วยพื้นที่ช่วงทั้งหมด

เวอร์ชันที่ไม่ถูกปรับแต่ง:

import random

def ccw(A,B,C):
    return (C[1]-A[1])*(B[0]-A[0]) > (B[1]-A[1])*(C[0]-A[0])

def intersect(A,B,C,D):
    return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)

def lit_area(light, vertices):
    # points: list of points
    # i     : x => i=0
    #       : y => i=1
    get_range = lambda i: (min(x[i] for x in vertices), max(x[i] for x in vertices))
    xr = abs(get_range(0)[0] - get_range(0)[1])
    yr = abs(get_range(1)[0] - get_range(1)[1])

    edges = list(zip(vertices, vertices[1:] + [vertices[0]]))

    num_sims = 1000000

    num_successes = 0
    for _ in range(num_sims):
        guess_x = random.uniform(*get_range(0))
        guess_y = random.uniform(*get_range(1))

        light_guess_line = ((guess_x, guess_y), light)

        if not any([intersect(*e, *light_guess_line) for e in edges]):
            num_successes += 1
    return float(num_successes / num_sims) * (xr * yr)


if __name__ == "__main__":
    points = [
    (1/2, 18),
    (1,3),
    (5,1/2),
    (7,5),
    (12,7),
    (16,3),
    (15,11),
    (8,19),
    (3,7)
    ]
    light_source = (5,8)
    print("Area lit by light: %f"% lit_area(light_source, points))

ลองออนไลน์!

สินเชื่อสำหรับอัลกอริทึมการตัดกันบรรทัด

นอกจากนี้ให้เครดิตกับผู้แสดงความคิดเห็นที่มีประโยชน์เกี่ยวกับวิธีการตีกอล์ฟให้ดียิ่งขึ้น


บรรทัดแรกสามารถกลายเป็นfrom random import*(ตัวแบ่งบรรทัด) u=uniformสำหรับ -2 ไบต์
Conor O'Brien

1
คุณสามารถโกนจำนวนไบต์ได้มากขึ้นโดยแทนที่ช่องว่างทั้ง 4 ช่องในฟังก์ชันด้วยช่องว่างเดียวและลบช่องว่างออกหลังg=lambda i:
Conor O'Brien

ไม่nจำเป็นต้องเป็นอำนาจของ 10 หรือไม่? มิฉะนั้นคุณสามารถบันทึกไบต์โดยใช้พลัง 9
Neil A.

ไม่จำเป็นต้องใช้กำลัง 10 ฉันจะใส่คำแนะนำของคุณในวันพรุ่งนี้! จนกว่าจะถึงวันนั้นทุกคนมีความสุขในวันวาเลนไทน์!
JPeroutek

ตามที่@ ConorO'Brienพูดถึงคุณสามารถลบช่องว่างนำหน้าออกได้มากมาย และนอกเหนือจากพื้นที่ที่i:(minแล้วพื้นที่ที่x[i]forสามารถลบออกได้เช่นกัน นอกจากนี้ยังสามารถreturn float(s/n)*(r*t) return(r*t)*float(s/n)และฉันไม่แน่ใจทั้งหมด แต่ไม่สามารถเปลี่ยนตัวแปรrและeนำออกและใช้โดยตรงได้เนื่องจากคุณใช้เพียงครั้งเดียว มันให้ผลที่แตกต่างออกไปเล็กน้อยถึงแม้ว่าgจะไม่ได้รับการดัดแปลงดังนั้นส่วนนั้นทำให้ฉันสับสนเล็กน้อย (ฉันไม่คุ้นเคยกับ Python มากเกินไปที่จะเข้าใจว่าทำไมผลลัพธ์จึงแตกต่างกันเล็กน้อย)
Kevin Cruijssen

5

Haskell , 559 618 632ไบต์

r(a:b)=b++[a]
s=zip<*>r
(?)a=sum.zipWith(*)a
o(a,b)=r a?b-a?r b
(a,b)!(c,d)=(c-a,d-b)
(a,b)#(c,d)=a*d-b*c
x i a@(e,f)b j c d|let k@(g,h)=a!b;l=c!d;m=c!a;n=l#k;o=m#l/n;p=m#k/n;q|i>0=o<0||o>1|let=o<=0||o>=1;r|n==0||q||p<0||p*j>1=[]|let=[(e+o*g,f+o*h)]=r
(a&b)(c:e@(d:_))|let(f,g)=span(/=d)b;h=zip f$r$f++[d]=concat[[k,l]|(i,j)<-h,[[k],[l]]<-[x 1 i j 0 a<$>[c,d]],and[x 0 m n 1 a o==[]|o<-[k,l],(m,n)<-h,(m,n)/=(i,j)]]++(a&g)e
(_&_)_=[]
z a b=sum[o$unzip[c,a,d]|e@(f:_)<-[[c|c<-b,and[all(==c)$x 1 d e 1 a c|(d,e)<-s b]]],(c,d)<-s$a&until((f==).head)r b$e++[f]]/2

ทางออกที่แน่นอน (ยกเว้นข้อผิดพลาด) Haskell มีการคำนวณทางคณิตศาสตร์อย่างมีเหตุผลในตัว ลองออนไลน์!

โปรดทราบว่านี้จะช่วยให้815523/6710ไม่ได้สำหรับห้องตัวอย่างและสี่แยกผนังแรกจะถูกคำนวณเป็น814643/6710 (55/61, 363/61)ฉันค่อนข้างแน่ใจว่าสิ่งนี้ถูกต้องเพราะรายการ Monte Carlo (ช้า) มาบรรจบกับผลลัพธ์เดียวกัน

ตำนาน:

z light roomPoints
    -- Main function, returns lit area.
    -- Compute list of visible corners in the room, then calls (&).
(&) light roomPoints' visibleCorners
    -- Compute visibility polygon. visibleCorners is the subset of points
    -- that are visible from the light. The first point of roomPoints'
    -- must coincide with the first visibleCorner.
x pEndpoints p1 p2 qSegment q1 q2
    -- Intersect line segments (p1, p2) and (q1, q2).
    -- If pEndpoints, exclude endpoints p1, p2.
    -- If not qSegment, allow intersection to extend past q2 (i.e. raycast).
r   -- Rotate list by one, used to construct closed loops etc.
s   -- Construct closed loop
(!) -- Vector between two points
(?) -- Dot product
(#) -- Cross product
o   -- Polygon area

โบนัส: Gloss GUI สำหรับการทดสอบ คลิกถัดจากจุดเพื่อย้าย

import qualified Graphics.Gloss as G
import qualified Graphics.Gloss.Interface.IO.Interact as GI

solnPoly a b|let c@(d:_)=[c|c<-b,and[all(==c)$x 1 d e 1 a c|(d,e)<-s b]]=a&until((d==).head)r b$c++[d]
solnArea = z

main =
  let fromRatP (x, y) = (fromRational x, fromRational y)
      displayScale = 10
      scalePoints = G.scale (fromInteger displayScale) (fromInteger displayScale)
      displayMode = G.InWindow "" (512, 512) (0, 0)
      drawBasePoly pointSz ps =
          mconcat $ G.lineLoop ps :
                    [G.translate x y (G.circleSolid pointSz) | (x, y) <- ps]
      drawVisPolyOf light ps =
          G.color G.blue $ drawBasePoly 0.2 $ map fromRatP $ solnPoly light ps
      drawLight (x, y) =
          G.translate x y $
          G.color G.yellow (G.circleSolid 0.5) <> G.circle 0.5
      draw (light, ps) =
          mconcat [
              scalePoints $ drawLight (fromRatP light),
              scalePoints $ drawBasePoly 0.4 (map fromRatP ps),
              scalePoints $ drawVisPolyOf light ps,
              G.translate (-200) (-50) $ G.scale 0.2 0.2 $
                G.color G.blue $ G.text $ "Lit area: " ++ show (solnArea light ps)
          ]
      event (GI.EventKey (GI.MouseButton GI.LeftButton) GI.Down _ (curx_, cury_)) (light, ps) =
          let dist (x,y) (x',y') = (x'-x)^2 + (y'-y)^2
              curx = curx_ / fromInteger displayScale
              cury = cury_ / fromInteger displayScale
              cursorR = (fromInteger$round curx, fromInteger$round cury)
              maxDist = 3
              snapAmount = 1
              (d, i) = minimum [(dist p cursorR, i) | (p, i) <- zip (light : ps) [0..]]
              snapTo n a = fromInteger$n*round(a/fromInteger n)
              snapCursor = (snapTo snapAmount curx, snapTo snapAmount cury)
              light' | i == 0 && d < maxDist^2 = snapCursor
                     | otherwise = light
              ps' | i > 0 && d < maxDist^2 = take (i-1) ps ++ [snapCursor] ++ drop i ps
                  | otherwise = ps
          in (light', ps')
      event _ state = state
      state0 =
        ((2, 2), [(0, 0), (10, 0), (10, 5), (20, 0), (20, 20), (15, 5),
                  (10, 10), (6, 10), (10, 12), (0, 12), (4, 10), (0, 10)])
  in G.play displayMode G.white 60
            state0
            draw
            event
            (\_ -> id)

ภาพหน้าจอ


จริงๆแล้วคุณพูดถูก ฉันต้องพิมพ์ผิดนะ จะอัปเดตตัวเลขเหล่านี้เล็กน้อย
หัวเรือใหญ่

1

APL + WIN

นี่เป็นเวอร์ชันที่ท้าทายที่น่าสนใจซึ่งฉันเสนอเพื่อแสดงให้เห็นถึงตรรกะของฉัน APL + WIN เวอร์ชันเก่าของฉันไม่เหมาะกับการเล่นโครงสร้างการควบคุมที่ซ้อนกัน APL ที่ทันสมัยกว่าสามารถทำได้ดีกว่า - ท้าทายไหม

หากผู้อ่านตรวจสอบตรรกะฉันจะไปเล่นกอล์ฟที่โซลูชันนี้ หากตรรกะผิดฉันก็จะลบ

r←b Room v

⍝Separate x and y coordinates of vertices               
x←v[;1] ⋄ y←v[;2]

⍝Intercept and slope of each line segment and ray through each vertex
s←(y,¨1⌽y)⌹¨(1E¯9+1,[1.1]¨x,¨1⌽1E¯9+x)
l←(y,¨b[2])⌹¨(1E¯9+1,[1.1]¨x,¨b[1]+1E¯9)                          

⍝Coordinates of vertices
x←x,¨1⌽x ⋄ y←y,¨1⌽y                                                  

⍝Initialise intersection matrix
r←((⍴s),0)⍴0

⍝Evaluate intersection matrix 
:for i :in ⍳⍴l 
    t←0⍴0
    :for j :in ⍳⍴s
        t←t,⍎1⍕∊((↑∊l[i])-↑∊s[j])÷((1↓∊s[j])-1↓∊l[i]) 
    :endfor
    z←r←r,t
:endfor 

⍝Identify x coordinates of valid intersections in the direction of the ray
:for i :in ⍳⍴l 
    t←(r[i;i])
    :for j :in ⍳⍴s
        :if t<b[1] 
            r[j;i]←r[j;i]×(r[j;i]<t)^r[j;i]>⌊/∊x[i]
        :else
            r[j;i]←r[j;i]×(r[j;i]>t)^r[j;i]<⌈/∊x[i]
        :endif
    :endfor
 :endfor

⍝Identify the edges intersected
e←(+/r≠0)/⍳⍴l 

⍝Intersection x coordinates
cx←(+/r)[e]

⍝Intersection y coordinates
cy←⍎1⍕+/¨(s[e])× 1,¨(+/r)[e]

⍝Replace original coordinates that are in shadow
x[e]←(1↓¨x[e]),¨cx
y[e]←(1↓¨y[e]),¨cy

⍝Calculate lit area
r←+/.5×(|-/¨x)×|-/¨y                                               

0

R , 296 255 ไบต์

function(s,l,u=cbind(s,s[,1]),d=t(diff(t(u))),q=l-u,r=apply(s,1,range),g=c(diff(r)))mean(replicate(1e6,!any((q[i<-1:ncol(s)*2]*(p=runif(2)*g+r[1,]-u)[j<-i-1]>p[i]*q[j])!=(q[i+2]*p[i+1]>q[i+1]*p[i+2])&(p[i]*d[j]>p[j]*d[i])!=(q[i]*d[j]>q[j]*d[i]))))*prod(g)

ลองออนไลน์!

นี้เป็นรุ่นที่ลดลงต่อไปของคำตอบหลาม วิธีการหลักของ Monte Carlo เหมือนกัน แต่ฉันจัดเรียงฟังก์ชันบางอย่างใหม่เพื่อทำให้สั้นลง ในการทำซ้ำครั้งแรกของฉันฉันจะก้าวร้าวมากเกินไปในการจัดเรียงใหม่และจากนั้นฉันก็ตระหนักว่าฉันสามารถเพิ่มประสิทธิภาพทั้งความยาวและความเร็วด้วยการกลับสู่เวอร์ชันของอัลกอริทึมการตัดกันใกล้กับงูหลาม

ต่อไปนี้เป็นเวอร์ชันที่ไม่ได้รับการแต่งแต้มและยังวางแผนผลลัพธ์

find_lit_ungolf <- function(shape, light, plot = TRUE) {
  lines <- cbind(shape ,shape[,1])
  diffs <- t(diff(t(lines)))
  light_minus_lines <- light - lines
  shape_range <- apply(s,1,range)
  shape_range_diff <- c(diff(shape_range))
  successes <- t(replicate(
    n = 1e5,
    {
      random_point <- runif(2) * shape_range_diff + shape_range[1, ]
      random_minus_lines <- random_point - lines
      q <- light_minus_lines
      p <- random_minus_lines
      d <- diffs
      i <- 1:ncol(s)*2
      success <-
        !any((q[i]*p[i-1]>p[i]*q[i-1])!=(q[i+2]*p[i+1]>q[i+1]*p[i+2])&(p[i]*d[i-1]>p[i-1]*d[i])!=(q[i]*d[i-1]>q[i-1]*d[i]))
      c(random_point, success)
    }))
  colnames(successes) <- c("x", "y", "success")
  if (plot) {
    shape <- t(shape)
    colnames(shape) <- c("x", "y")
    print(ggplot(as_tibble(successes), aes(x, y)) +
      geom_point(aes(colour = factor(success)), alpha = 0.3) +
      geom_polygon(data = as_tibble(shape), alpha = 0.2) +
      annotate("point", light[1], light[2], col = "yellow"))
  }
  mean(successes[, 3]) * prod(shape_range_diff)
}
find_lit_ungolf(s, l)

พล็อตของแสงในห้อง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.