沃克三角拼图

时间:2018-08-10 22:44:31

标签: algorithm scala trigonometry

我整个星期都在为编码平台解决此问题的方法而苦苦挣扎。目前,这并不是要在那儿获得积分,而是要更多地了解我在解决方案/推理中的错误之处。

这是作业:

  

步行者从O点开始,沿着OA,AB和BC步行。当他是   在C中(C将在上半平面中),距离CO是多少?   tOC的正角度,分钟,秒是多少?

     

角度tOA为alpha(此处为45度),角度hAB为beta(此处为30)   度),uBC角为伽马(此处为60度)。

     

带有参数的任务函数solve(a,b,c,alpha,beta,gamma)

     

a,b,c:以距离alpha,beta,gamma为单位的正整数:   以度为单位的正整数(正角为逆时针方向)   返回一个数组

     

第一个元素:距离CO(四舍五入到最接近的整数),然后是角度   tOC具有以下三个元素:数组的第二个元素:   角度tOC的度数(正整数)   数组的元素:角度tOC中的分钟数(截断了)   正整数)数组的第四个元素:秒数   tOC角(截断正整数)

这是展示上述内容的小图像: enter image description here

基本上每个步骤都会创建一个矩形三角形。我的方法是使用正弦规则逐步找到A,B和C的坐标,然后轻松找到CO和角度COt。根据测试,我得到了正确的CO段,但是角度似乎是错误的:

Test Failed
Expected Array(15, 135, 49, 18), but got Array(15, 143, 2, 45)

Test Failed
Expected Array(20, 141, 4, 23), but got Array(20, 139, 51, 47)

下面,我粘贴解决方案,该站点提供了测试用例:

object Walker {

  case class Point(x: Double, y: Double){
    def moveLeft(by: Double) = Point(by - x, y)
    def moveRight(by: Double) = Point(by + x, y)
    def moveUp(by: Double) = Point(x, by + y)
    def moveDown(by: Double) = Point(x, by - y)
    def inverse() = Point(y, x)
  }

  implicit def roundUp(d: Double): Int = math.ceil(d).toInt

  def solve(a: Int, b: Int, c: Int, alpha: Int, beta: Int, gamma: Int): Array[Int] = {
    val pointA = pointHypotenuse(a, alpha)
    val pointB = pointHypotenuse(b, beta).inverse().moveLeft(pointA.x).moveUp(pointA.y)
    val pointC = pointHypotenuse(c, gamma).moveLeft(pointB.x).moveDown(pointB.y)
    val coHypotenuse: Int = math.sqrt(math.pow(pointC.x, 2) + math.pow(pointC.y, 2))
    val sinC = math.sin(math.abs(pointC.x)/coHypotenuse)
    val tOC = 180 - sinC.toDegrees
    coHypotenuse +: degrees(tOC)
  }

  def pointHypotenuse(coteHypotenuse: Int, angleHypotenuse: Int): Point = {
    val sinDuAngle = math.sin(math.toRadians(angleHypotenuse))
    val coteOppose = sinDuAngle * coteHypotenuse
    Point(math.sqrt(math.pow(coteHypotenuse, 2) - math.pow(coteOppose, 2)), coteOppose)
  }

  def degrees(deg: Double): Array[Int] = {
    Stream.iterate((deg.toInt, deg - deg.toInt)){
      case (_, r) =>
        val by60 = r*60
        (by60.toInt, by60 - by60.toInt)
    }.map(_._1).take(3).toArray
  }
}

测试(来自平台):

class WalkerTest extends FlatSpec { 
  it should "pass basic tests" in {
    dotest(12, 20, 18, 45, 30, 60, Array(15, 135, 49, 18))
    dotest(15,15,19,50,29,55, Array(12, 133, 18, 44))
    dotest(14,25,17,41,35,59, Array(20, 129, 41, 57))

  }
}

object WalkerTest {
  private def dotest(a: Int, b: Int, c: Int, aa: Int, bb: Int, cc: Int, expect: Array[Int]): Unit = {
    val actual: Array[Int] = Walker.solve(a, b, c, aa, bb, cc)
    assertResult(expect){actual}
  }
}

我不认为这是一个舍入错误(由断言导致所有Doubles乘以Ints距离替换)。我通常不会问这个,但是我似乎对此确实很受阻。

2 个答案:

答案 0 :(得分:1)

val sinC = math.sin(math.abs(pointC.x)/coHypotenuse)

得到某个段比率的正弦,但是这个比率是余弦
要获得一个角度,应该使用arccos

答案 1 :(得分:0)

您必须传递beta(90+given)gamma(180+given)的角度,因为所有角度都将从positive x-axis沿逆时针方向传递。然后,似乎不需要moveLeft,moveRight,moveUp,moveDowninverse函数。代替所有它们,您只能在案例类moveTo(p:Point)中使用一个函数Point,并且此修改可以提供准确的测试结果,如下面的scala REPL所示:

object Walker {
  case class Point(x: Double, y: Double){
    def moveTo(p:Point) = {val t = this.x+p.x;val t1 = this.y+p.y;Point(t,t1) }
  }
  def solve(a: Double, b: Double, c: Double, alpha: Double, beta: Double, gamma: Double):Array[Int]= {
    val pointA = movedPoint(a, alpha)
    val pointB = pointA.moveTo(movedPoint(b,beta))
    val pointC = pointB.moveTo(movedPoint(c,gamma))
    val co = math.sqrt( math.pow(pointC.x, 2) + math.pow(pointC.y, 2))
    val angletOC = Math.asin(math.abs(pointC.y)/co).toDegrees
    val tOC = if(pointC.x<=0 && pointC.y>=0)
        180 - angletOC
    else if(pointC.x<=0 && pointC.y<=0)
        180 + angletOC
    else if(pointC.x>0 && pointC.y<0)
       270 + angletOC
    else angletOC
    Math.round(co).toInt +: convDegMinSec(tOC)
  }
 def movedPoint(dist:Double,angle:Double):Point = {
  val yCo = dist*Math.sin(Math.toRadians(angle))
  val xCo = dist*Math.cos(Math.toRadians(angle))
  Point(xCo,yCo)
 }
 def convDegMinSec(deg: Double): Array[Int] = {
     val degs = deg.toInt
     val mins = (deg - deg.toInt)*60
     val secs =  (mins-mins.toInt)*60
     val arr = Array(degs,mins.toInt,secs.toInt)
     arr
  }
}

在Scala REPL中:

scala> Walker.solve(12,20,18,45,90+30,180+60)
res58: Array[Int] = Array(15, 135, 49, 18)

scala> Walker.solve(15,15,19,50,90+29,180+55)
res59: Array[Int] = Array(12, 133, 18, 44)

scala> Walker.solve(14,25,17,41,90+35,180+59)
res60: Array[Int] = Array(20, 129, 41, 57)