20
\$\begingroup\$

Doorknobs are great and all, but when you open a door, it always dents the walls around it. I need you to take input of ASCII art of a room, like this:

+---------+--X  --X    --+-----+
|       \     \   |\     |   \ |
|        \     \  | \    |    \|
|         X       |  \   |     X
|      /  |       |   \  X      
|     /   |     \       /       
|    /    |      \     /       |
+---X   --+-------X------+-----+

And output the room with doorstops, like this:

+---------+--X  --X    --+-----+
|       \  .  \   |\     |   \.|
|        \     \  | \   .|    \|
|         X       |  \   |     X
|      /  |       |.  \  X      
|     /  .|     \       /       
|.   /    |     .\     /       |
+---X   --+-------X------+-----+

Specification:

  • The ASCII room (input) will consist of +, -, and |. These characters are purely cosmetic; they could all be +s but that would look horrible. It will also contain hinges (X) and doors (/ or \).
  • Doors are made up of / or \. Starting from the "hinge" character, which is X, they will go directly diagonally (change of 1 in x and 1 in y) for 2 or more units (characters).
  • To find where to put the doorstop for a door (there is always only one doorstop per door), find the doorway for the door. The doorway will always start at one hinge, and go the same amount of spaces as the door's length up, down, left, or right from there. The next space after that will always be a wall. For example, in this door, the doorway is marked by Ds:

       \
        \
    ---DDX-----
    

    One the doorway is found, find out whether you need to go clockwise or counterclockwise to reach the door. For example, in that example door above, you have to go clockwise, and in this one, you must go counterclockwise:

       \ <-
        \  )
    -----X  ---
    

    Once you know which way to go, keep going that way (ignoring the door) until you reach a wall.

    Here's a visualization of that for the example door above:

    visualization

    The blue is the doorway, the orange is finding that you must go clockwise, and the red is continuing to go clockwise until a wall is reached.

    Once you reach a wall, go (the door's length) spaces from the hinge (X) on that wall, move one space away from the wall towards the door (so you don't place the doorstop right on the wall), and insert a . there. Here's the same example door showing how the doorstop is placed:

       \
        \  .
    ---DDX12---
    

    Repeat for every door, and output the result! Use the example input at the top of this post as a test case to check if your program is valid.

    Note that you do not have to handle doors that don't fit on their walls, such as:

    |     /
    |    /
    |   /
    |  /
    +-X    --
    

    Or:

         /
        /
       /
    +-X   --
    |
    |
    
  • This is , so the shortest code in bytes will win.
\$\endgroup\$
  • \$\begingroup\$ What are the rules for doorways? They must be orthogonal, the same length as their doors, and surrounded by a wall on one side, and a hinge (for the right door) on the other side? \$\endgroup\$ – John Dvorak Mar 30 '14 at 22:18
  • \$\begingroup\$ @JanDvorak Ok, edited for clarification \$\endgroup\$ – Doorknob Mar 30 '14 at 22:21
  • 3
    \$\begingroup\$ Can we assume that the wall starting at the hinge is at least of the same length as the door and that no other walls (not starting at the hinge) interfere with that specific door? \$\endgroup\$ – Howard Mar 31 '14 at 7:52
  • \$\begingroup\$ @Howard I'm not sure what you're talking about. Are you asking if you can assume that the opposite wall from the doorway is the same length as the doorway? If so, then no, since the door could only swing 90 degrees like the second one in the test case (counting by hinge placement starting from the top left). \$\endgroup\$ – Doorknob Mar 31 '14 at 12:53
  • 1
    \$\begingroup\$ Huh? The door is diagonal. All of those strings are 6 chars wide, so there isn't a middle column. \$\endgroup\$ – Peter Taylor Mar 31 '14 at 15:34
4
\$\begingroup\$

Scala, 860 bytes

Golfed:

    object D extends App{val s=args(0)split("\n")
    val r=Seq(P(1,0),P(1,-1),P(0,-1),P(-1,-1),P(-1,0),P(-1,1),P(0,1),P(1,1))
    var m=r(0)
    val e=s.map(_.toCharArray)
    case class P(x:Int,y:Int){def u=x==0||h
    def h=y==0
    def p(o:P)=P(x+o.x,y+o.y)
    def o="\\/".contains(c)
    def w="-|+".contains(c)
    def c=try s(y)(x) catch {case _=>'E'}
    def n=r.filter(!_.u).map(d => d.j(p(d))).sum
    def j(t:P):Int=if(t.o)1+j(p(t))else 0
    def q=if(c=='X'){m=this
    r.filter(_.u).map{d=>if(p(d).c==' '&&p(P(d.x*(n+1),d.y*(n+1))).w)d.i}}
    def i:Unit=Seq(r++r,(r++r).reverse).map(l=>l.drop(l.indexOf(this)+1)).map(_.take(4)).filter(_.exists(a=>a.p(m)o))(0).grouped(2).foreach{p=>if(p(1)p(m)w){p(0)add;return}}
    def add=if(r.filter(_.h).map(p(_)p(m)).exists(_.w))e(y*m.n+m.y)(x+m.x)='.'else e(y+m.y)(x*m.n+m.x)='.'}
    val f=args(0).size
    Array.tabulate(f,f){(i,j)=>P(i,j)q} 
    e.map(_.mkString).map(println)}

Un-golfed:

    object DoorknobCleanVersion extends App {
            val s = args(0) split ("\n")

            val r = Seq(P(1, 0), P(1, -1), P(0, -1), P(-1, -1), P(-1, 0), P(-1, 1), P(0, 1), P(1, 1))
            val HorizontalDirections = r.filter(_.isHorizontal)

            var hinge = r(0)
            val result = s.map(_.toCharArray)

            type I = Int
            case class P(x: Int, y: Int) {
                    def isCardinal = x == 0 || isHorizontal
                    def isHorizontal = y == 0

                    override def toString = x + "," + y

                    def p(o: P) = P(x + o.x, y + o.y)

                    def isDoor = Seq('\\', '/').contains(charAt)
                    def isWall = Seq('-', '|', '+').contains(charAt)

                    def charAt = try s(y)(x) catch { case _ => 'E' }

                    def doorLength = r.filter(!_.isCardinal).map(d => d.recursion2(p(d))).sum

                    def recursion2(currentPosition: P): Int =
                            if (currentPosition.isDoor)
                                    1 + recursion2(p(currentPosition))
                            else
                                    0

                    def findDoorway =
                            if (charAt == 'X') {
                                    hinge = this
                                    r.filter(_.isCardinal).map { d =>
                                            if (p(d).charAt == ' ' && p(P(d.x * (doorLength + 1), d.y * (doorLength + 1))).isWall)
                                                    d.getCorrectRotation2
                                    }
                            }

                    def getCorrectRotation2: Unit = Seq(r ++ r, (r ++ r).reverse).map(l => l.drop(l.indexOf(this) + 1))
                            .map(_.take(4))
                            .filter(_.exists(a => a.p(hinge)isDoor))(0)
                            .grouped(2)
                            .foreach {
                                    p =>
                                            if (p(1) p (hinge)isWall) {
                                                    p(0)add;
                                                    return
                                            }
                            }

                    def add =
                            if (HorizontalDirections.map(p(_) p (hinge)).exists(_.isWall))
                                    result(y * hinge.doorLength + hinge.y)(x + hinge.x) = '.'
                            else
                                    result(y + hinge.y)(x * hinge.doorLength + hinge.x) = '.'

            }

            val size = args(0).size
            Array.tabulate(size, size) { (i, j) => P(i, j).findDoorway }

            result.map(_.mkString).map(println)
    }

Using OOP was definitely the wrong approach here, in hindsight. If I could do it again I would definitely go with a bunch of hardcoded truth tables.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.