Skip to content

Commit

Permalink
Seemingly fix the geometry, I hope
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Jul 9, 2023
1 parent 671fb78 commit b2befcd
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Icfpc2023.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ let ``Scoring yields the expected score for the sample problem from the spec`` (
Volumes = [||]
}

Assert.Equal(5343.0, CalculateScore problem solution)
Assert.Equal(5343.0, Scoring.CalculateScore problem solution)

[<Fact>]
let ``Stadium detects intersection when blocking musician is right on the line`` () =
Expand Down
83 changes: 34 additions & 49 deletions Icfpc2023/Geometry.fs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Rectangle =
}
member private this.UpperRight: PointD =
this.BottomLeft + PointD(this.Width, this.Height)

member this.Contains(p: PointD): bool =
let (PointD(x, y)) = p
let (PointD(x0, y0)) = this.BottomLeft
Expand Down Expand Up @@ -117,54 +118,38 @@ type Stadium =
let sin = sin radians
PointD(x * cos - y * sin, x * sin + y * cos)

member this.RectanglePoints = [|
this.Center1 + (Stadium.NormalizeVector(this.Center2 - this.Center1) |> Stadium.RotateVector(Math.PI/2.0)) * this.Radius
this.Center1 + (Stadium.NormalizeVector(this.Center2 - this.Center1) |> Stadium.RotateVector(-Math.PI/2.0)) * this.Radius
this.Center2 + (Stadium.NormalizeVector(this.Center2 - this.Center1) |> Stadium.RotateVector(Math.PI/2.0)) * this.Radius
this.Center2 + (Stadium.NormalizeVector(this.Center2 - this.Center1) |> Stadium.RotateVector(-Math.PI/2.0)) * this.Radius
|]

/// https://stackoverflow.com/a/10965077/2684760
static member DoPolygonsIntersect(a: PointD[], b: PointD[]): bool =
let mutable foundNoIntersection = false
for polygon in [|a; b|] do
for i1 in 0 .. polygon.Length - 1 do
if not foundNoIntersection then
let i2 = (i1 + 1) % polygon.Length
let p1 = polygon[i1]
let p2 = polygon[i2]

let normal = PointD(p2.Y - p1.Y, p1.X - p2.X)

let mutable minA = Nullable<double>()
let mutable maxA = Nullable<double>()
for p in a do
let projected = normal.X * p.X + normal.Y * p.Y
if not minA.HasValue || projected < minA.Value then
minA <- projected
if not maxA.HasValue || projected > maxA.Value then
maxA <- projected

let mutable minB = Nullable<double>()
let mutable maxB = Nullable<double>()
for p in b do
let projected = normal.X * p.X + normal.Y * p.Y
if not minB.HasValue || projected < minB.Value then
minB <- projected
if not maxB.HasValue || projected > maxB.Value then
maxB <- projected

if Nullable.Compare(maxA, maxB) < 0 || Nullable.Compare(maxB, minA) < 0 then
foundNoIntersection <- true

if foundNoIntersection then false else true
// https://stackoverflow.com/a/18292964/2684760
static member LineIntersectsRect(struct(a, b), rect: Rectangle): bool =
let (PointD(x1, y1)) = a
let (PointD(x2, y2)) = b

let minX = rect.BottomLeft.X
let maxX = rect.BottomLeft.X + rect.Width
let minY = rect.BottomLeft.Y
let maxY = rect.BottomLeft.Y + rect.Height

let k = (y2 - y1) / (x2 - x1)
let y = k * (minX - x1) + y1
if y > minY && y < maxY then true
else
let y = k * (maxX - x1) + y1
if y > minY && y < maxY then true
else
let x = (minY - y1) / k + x1
if x > minX && x < maxX then true
else
let x = (maxY - y1) / k + x1
if x > minX && x < maxX then true
else false

member this.RectangularPartIntersectsWith(rect: Rectangle): bool =
let p1Points = [|
rect.BottomLeft
rect.BottomLeft + PointD(rect.Width, 0.0)
rect.BottomLeft + PointD(rect.Width, rect.Height)
rect.BottomLeft + PointD(0.0, rect.Height)
|]
let p2Points = this.RectanglePoints
Stadium.DoPolygonsIntersect(p1Points, p2Points)
let radiusVector = Stadium.NormalizeVector(this.Center2 - this.Center1) * this.Radius
let line1 = struct (
this.Center1 + Stadium.RotateVector(Math.PI / 2.0) radiusVector,
this.Center2 + Stadium.RotateVector(Math.PI / 2.0) radiusVector
)
let line2 = struct (
this.Center1 - Stadium.RotateVector(Math.PI / 2.0) radiusVector,
this.Center2 - Stadium.RotateVector(Math.PI / 2.0) radiusVector
)
Stadium.LineIntersectsRect(line1, rect) || Stadium.LineIntersectsRect(line2, rect)
15 changes: 10 additions & 5 deletions Icfpc2023/Scoring.fs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ type SectoredIndex(problem: Problem) =
sector.Add point

member _.GetPointsIn(s: Stadium): PointD seq =
getSectorSquares s
let squares = getSectorSquares s |> Seq.toArray

squares
|> Seq.collect(fun (struct(x, y)) -> sectors[x, y])
|> Seq.filter(s.Contains)

let private CalculateAttendeeMusicianScore(attendee: Attendee, musician: Musician, closeness: ClosenessFactor): Score =
let d_squared = (attendee.X - musician.Location.X) ** 2.0 + (attendee.Y - musician.Location.Y) ** 2.0
Expand All @@ -57,10 +60,12 @@ let private AnyOtherMusicianBlocksSound(index: SectoredIndex,
let blockZone = { Center1 = musician; Center2 = attendee; Radius = 5.0 }
let candidates = index.GetPointsIn blockZone |> Seq.toArray // TODO REMOVE TOARRAY

candidates
|> Seq.filter(fun p -> p <> musician)
|> Seq.tryHead
|> Option.isSome
let blocking =
candidates
|> Seq.filter(fun p -> p <> musician)
|> Seq.toArray

blocking.Length > 0

let private AnyPillarBlocksSound (pillars: Pillar[]) (musician: Musician) (attendee: Attendee): bool =
let musician = PointD(musician.Location.X, musician.Location.Y)
Expand Down

0 comments on commit b2befcd

Please sign in to comment.