Flaming Doorknob Keyboards!

21

Well, turns out Doorknob's username on GitHub, Reddit, and other sites is KeyboardFire. That gives me an idea...

The task

You work at KeyboardFire Inc., a company that makes special keyboards. And, by "special", I mean that, whenever you press a key, something in your house lights on fire! With the new KeyboardFire Doorknob series, the objects that light on fire are doorknobs.

However, because of stupid government regulations, your users need to know which doorknobs in their house wil light on fire.

Consider this ASCII art of a portion of a QWERTY keyboard:

1|2|3|4|5|6|7|8|9|0
 q|w|e|r|t|y|u|i|o|p
  a|s|d|f|g|h|j|k|l
   z|x|c|v|b|n|m

(The |'s represent the boundaries between keys.)

We can treat this exact ASCII drawing as a "graph" of sorts, where each character in the range [a-z0-9] has an x (horizontal) and y (vertical) index, where (0,0) is 1. For instance, the letter d has the coordinates (2,6) (pipes and spaces are included in the coordinate calculation).

Now let's think about each user's house. Every house can be drawn top-down view as a 20x4 ASCII art (in this world where it's legal to sell destructive keyboards, every house is the same size). We can use D's to mark the positions of each doorknob in the house. Here's an example:

D         D  D     D
    D               

              D  D  

We'll call this the "house map". (Yes, that's a lot of doorknobs!)

Pressing any key will light the nearest doorknob on fire. For instance, if we take the previous coordinates of the letter d, the nearest doorknob (by Manhattan distance) is at the coordinates (1,4). This is the doorknob that will light on fire when the letter d is hit. If we were to mark the flaming doorknob with an F, the result would be:

D         D  D     D
    F               

              D  D  

The specs

Your program will take two inputs:

  • A string that matches the pattern [a-z0-9]+.
  • A house map. This can be a string, a list of strings, or something equivalent.

You need to go through each letter of the string and light the respective doorknob on fire (change its letter to an F). If the nearest doorknob is already on fire, leave it as-is. If there is more than 1 doorknob that could be lit on fire using the this method, you can light whichever one you want.

After the whole string is processed in this manner, you need to print the resulting house map.

Code-golf, so shortest program wins. Standard loopholes banned as usual.

Example

String:

helloworld123

House map:

D    D       D     D
    D

              D  D  

Possible results:

F    F       F     D
    F

              D  F

Or:

F    D       F     D
    F

              D  F

Or:

F    F       D     D
    F

              F  F

Or:

F    D       D     D
    F

              F  F

EDIT: Uh...is there a reason I have one answer, even with a +50 bounty? If you find the directions complicated/vague, I'd be glad if you posted in the comments or something...or of I'm doing anything wrong...

EDIT 2: Bounty expires in under a day! Post something else! Please! PLEASE!!!! :(

kirbyfan64sos

Posted 2015-11-17T22:17:21.073

Reputation: 8 730

1There are a few things I find confusing: 1) Why is d's coords (2, 6) and not (2, 2)? 2) Why does the example have so many possible answers? 3) When you explain how things will light on fire, why are you even talking about d? Why not just straight up say that pressing a will light some house on fire? Does d do it, too? – Quelklef – 2015-11-23T02:45:13.463

@Quelklef Is this a bit better? Thanks for the feedback! – kirbyfan64sos – 2015-11-23T23:24:45.440

If 'h' ends up exactly between two doorknobs and 'h' is called twice, should both doorknobs be on fire? or can the program choose to fire the same doorknob? – Grant Davis – 2015-11-24T15:59:12.487

@GrantDavis The program can choose to fire the same doorknob. – kirbyfan64sos – 2015-11-24T16:05:29.833

Answers

3

JavaScript (ES6), 204 bytes

(s,h)=>[...s].map(c=>(o="1234567890qwertyuiopasdfghjkl_zxcvbnm".search(c),y=o/10|0,x=o%10*2+y,n=a=Math.abs,h.map((k,i)=>k.match(/\s/)||(d=a(x-i%21)+a(y-i/21|0))>n||(n=d,p=i)),h[p]="F"),h=[...h])&&h.join``

Fine, I'll answer it. ;)

Explanation

(s,h)=>
  [...s].map(c=>(                     // iterate through each character of the input

    // Get X and Y coordinates of the character input
    o="1234567890qwertyuiopasdfghjkl_zxcvbnm".search(c),
    y=o/10|0,
    x=o%10*2+y,

    // Find the nearest doorknob
    n=                                // n = Manhattan distance to nearest doorknob
      a=Math.abs,
    h.map((k,i)=>                     // iterate through each character of the house
      k.match(/\s/)||                 // do not check distance to whitespace characters
        (d=a(x-i%21)+a(y-i/21|0))>n|| // d = distance to the current doorknob
          (n=d,                       // set the nearest doorknob to this one
          p=i)                        // p = position of the doorknob
    ),
    h[p]="F"                          // update the doorknob to "F" in the house string
  ),h=[...h])&&h.join``               // return the house map as a string

Test

<input type="text" id="input" value="helloworld123" /><br />
<textarea id="house" rows="4" cols="20">D    D       D     D
    D               
                    
              D  D  </textarea><br />
<button onclick='result.innerHTML=(

(s,h)=>[...s].map(c=>(o="1234567890qwertyuiopasdfghjkl_zxcvbnm".search(c),y=o/10|0,x=o%10*2+y,n=a=Math.abs,h.map((k,i)=>k.match(/\s/)||(d=a(x-i%21)+a(y-i/21|0))>n||(n=d,p=i)),h[p]="F"),h=[...h])&&h.join``

)(input.value,house.value)'>Go</button>
<pre id="result"></pre>

user81655

Posted 2015-11-17T22:17:21.073

Reputation: 10 181

2I finally got another answer!!! :D – kirbyfan64sos – 2015-11-27T01:07:28.220

12

Ruby, 229 bytes

->s,m{c=m.flat_map.with_index{|x,i|x.size.times.select{|j|x[j]==?D}.map{|y|[i,y]}}
s.chars{|h|x='1234567890qwertyuiop*asdfghjkl*zxcvbnm'.index h
x,y=(x%10)*2,x/10
a,b=c.min_by{|a,b|(y-a).abs+((y%2>0?x+1:x)-b).abs}
m[a][b]='F'}
m}

Not very good, but I just had to get the first answer in.

Slightly ungolfed / commented version:

#!/usr/bin/ruby

f = -> s, m {
    # get knob coords
    c = m.flat_map.with_index {|x, i| x.size.times.select{|j| x[j] == ?D }.map{|y| [i, y] } }
    # for each char in the string
    s.chars {|h|
        # note the asterisks to correct for offsets
        x = '1234567890qwertyuiop*asdfghjkl*zxcvbnm'.index h
        # get un-"staggered" x and y coords
        x, y = (x % 10) * 2, x / 10
        # add one to x for every other row to fit keyboard
        x += 1 if y % 2 > 0
        # find closest knob by Manhattan distance
        a, b = c.min_by{|a, b| (y - a).abs + (x - b).abs }
        # LIGHT IT ON FIRE!
        m[a][b] = 'F'
    }
    # return new map
    m
}

puts f['helloworld123', ['D    D       D     D', '    D', '', '              D  D']]

Doorknob

Posted 2015-11-17T22:17:21.073

Reputation: 68 138