A torre equilibrará?

36

Introdução

Dada uma torre ASCII e a força do vento, escreva um programa ou função para determinar se a torre se equilibrará ou em que direção cairá.

Por exemplo, a primeira torre se equilibra, mas a segunda cai para a esquerda.

  # #            # #
  ###            ### 
 ###            ### 
 # #            # # 
#####          ##### 
 ###            ### 
 ###              #

Este é o meu primeiro desafio. Espero que você goste.

instruções

A torre consiste em blocos conectados, representados #e forma um objeto rígido . Cada bloco é um quadrado com largura e altura de uma unidade e tem uma densidade constante. Existem duas forças que atuam na torre, seu peso e a força do vento. Todas as forças atuam em cada bloco individualmente e passam pelo centro do bloco.

  • Devido ao seu peso, cada bloco possui uma força descendente de uma unidade atuando sobre ele.
  • Além disso, cada bloco que não possui outro bloco adjacente a ele no lado do vento tem uma força atuando horizontalmente na direção do vento. A magnitude dessa força é dada como uma entrada.
  • A direção do vento é indicada por uma bandeira ASCII em algum lugar da entrada. Haverá uma bandeira na entrada se e somente se o vento não for zero. A bandeira não afeta nenhuma força.

A bandeira ficará exatamente como aparece abaixo.

Flag design and corresponding wind direction:

 o~~        ~~o
 |~~        ~~|

--->        <---

Para esclarecer, a torre é um objeto sólido e não se quebra e não está presa ao chão. No entanto, seu programa deve calcular as forças de cada bloco individualmente para determinar se a torre se equilibra.

Exemplo

  o~~
  |~~
  # #              > > 
  ###              >## 
 ###              >##  
 # #              > >  
#####            >#### 
 ###              >##  
 ###              >##  

Wind force: 1    Wind direction: --->

O vento está soprando direito e empurrará os blocos mostrados com um >na direita acima. Observe que o vento atua no interior dos orifícios.

Suponha que o canto inferior esquerdo da torre tenha coordenadas (0,0). O momento em torno da base esquerda da torre em (0,0)é de 71 unidades no sentido horário, para que a torre não caia para a esquerda. O momento em torno da base direita da torre em (0,3) é de 8 unidades no sentido horário, para que a torre caia para a direita.

Se o vento soprasse para a esquerda, os momentos respectivos seriam 2 unidades no sentido horário e 61 unidades no sentido anti-horário nos mesmos pontos, para que a torre se equilibrasse.

Entrada

  • Seu programa ou função deve receber duas entradas, um número decimal e uma sequência separada por nova linha.
  • O número decimal será maior que zero e representa a força exercida pelo vento em cada bloco exposto, como no exemplo.
  • A sequência representará a torre de cima para baixo e pode conter espaços, #|o~caracteres e novas linhas. Opcionalmente, você pode assumir uma nova linha à direita e / ou preencher a torre com espaços à direita para formar um retângulo.
  • A torre terá pelo menos um #na linha inferior.
  • Você pode inserir o número e a string em qualquer ordem.
  • Se a magnitude da força do vento for diferente de zero, haverá uma bandeira em algum lugar da entrada, no solo ou conectada à torre. A bandeira terá a forma exata mostrada acima.
  • Os #blocos formarão uma forma conectada que pode conter orifícios. Em outras palavras, todos os blocos serão adjacentes a outro outro bloco, a menos que haja apenas um bloco.

Saída

  • Um dos caracteres B, Lou R, dependendo do equilíbrio da torre, cai para a esquerda (sentido anti-horário) ou cai para a direita (sentido horário).
  • A saída pode ter uma nova linha à direita opcional.

Isso é ; aplicam-se regras e brechas padrão.

B Casos de teste:

Wind: 1
    ~~o
    ~~|
      # #
      ###
     ###
     # #
    #####
     ###
     ###

Wind: 0
##
# ##
###

Wind: 1.7
o~~
|~~
#
##

Wind: 0.768
      o~~
      |~~
      # #
      ###
     ###
     # #
    #####
     ###
     ###

Wind: 0.1
#
#
#
#
#
# o~~
# |~~

Wind: 0
#

Wind: 0
############

Wind: 144
               o~~
############   |~~

Wind: 0
#######
 ##
 #
 ##

Wind: 0
                ############
           ############
       ############
    ############
   ############
 ############
############

Wind: 41
                 ############
            ############
        ############
     ############
    ############
  ############     ~~o
 ############      ~~|

L Casos de teste:

Wind: 0
#####
   #


Wind: 42
                 ############
            ############
        ############
     ############
    ############
  ############     ~~o
 ############      ~~|

Wind: 4
########
    ###
 ~~o# ##
 ~~|#  #

Wind: 3
########
    ###
 o~~# ##
 |~~   #

R Casos de teste:

Wind: 1
      o~~
      |~~
      # #
      ###
     ###
     # #
    #####
     ###
     ###

Wind: 2
o~~
|~~
#

Wind: 0.001
                 ############
            ############
        ############
     ############
    ############
  ############     o~~
 ############      |~~

Wind: 145
               o~~
############   |~~

Wind: 1
#
#
#
#
#
# o~~
# |~~

Wind: 0.26
#######
 ##
 #   o~~
 ##  |~~

Solução de referência (JavaScript)

Experimente online.

function balanced(tower, wind) {
    var rows = tower.split('\n').reverse(); // Reverse so row index matches height of row.
    var height = rows.length;
    var leftEdge = rows[0].indexOf('#'); // Find bottom left corner of tower.
    var rightEdge = rows[0].lastIndexOf('#') + 1; // Find bottom right corner of tower.
    var leftMoment = 0, rightMoment = 0; // Moments around the bottoms corners of tower.
    wind *= tower.indexOf('~o')>-1 ? -1 : 1; // Find direction of the wind.

    // Sum the moments for each block in the tower.
    for (var i = height - 1; i >= 0; i--) {
        rows[i].split('').map(function(ch, index, arr) {
            if (ch=='#') {
                // If there's not a block toward the windward side of the current one.
                if ((wind < 0 && arr[index-1] != '#') || (wind > 0 && arr[index+1]!='#')) {
                    // Add moments from wind.
                    leftMoment += (i+0.5)*-wind;
                    rightMoment += (i+0.5)*-wind; 
                }

                leftMoment += leftEdge - (index + 0.5);
                rightMoment += rightEdge - (index + 0.5);
            }
        }, 0);
    }
    if (leftMoment > 0) return 'L';
    else if (rightMoment < 0) return 'R';
    else return 'B';
}

Entre os melhores

Aqui está um snippet de pilha para gerar uma classificação regular e uma visão geral dos vencedores por idioma.

Para garantir que sua resposta seja exibida, inicie-a com um título, usando o seguinte modelo de remarcação:

# Language Name, N bytes

onde Nestá o tamanho do seu envio. Se você melhorar sua pontuação, poderá manter as pontuações antigas no título, identificando-as. Por exemplo:

# Ruby, <s>104</s> <s>101</s> 96 bytes

Se você quiser incluir vários números no cabeçalho (por exemplo, porque sua pontuação é a soma de dois arquivos ou você deseja listar as penalidades do sinalizador de intérpretes separadamente), verifique se a pontuação real é o último número no cabeçalho:

# Perl, 43 + 2 (-p flag) = 45 bytes

Você também pode transformar o nome do idioma em um link que será exibido no snippet da tabela de classificação:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

intrepidcoder
fonte
17
Bem-vindo ao PPCG; este é um primeiro desafio excelentemente escrito! :)
Maçaneta da porta

Respostas:

2

JavaScript (ES6), 239 bytes

Joguei minha implementação de referência. Consegui salvar bytes alterando o loop for para a map, usando &&e ||curto-circuito se, e usando o ,operador para ajustar tudo em uma instrução, a fim de evitar um retorno explícito na função.

(a,b)=>((c=a.split`
`.reverse(),d=c[f=g=0].indexOf`#`,e=c[0].lastIndexOf`#`+1),a.match`o~`&&(b*=-1),c.map((h,i)=>h.replace(/#/g,(j,k,l)=>(b>0&l[k-1]!='#'|b<0&l[k+1]!='#'&&(f+=(i+=0.5)*b,g+=i*b),f+=d-k-0.5,g+=e-k-0.5))),f>0?'L':g<0?'R':'B')

Ainda é possível jogar mais isso. Sugestões são bem vindas.

intrepidcoder
fonte
+1 muito melhor do que a minha solução ingênua
Conor O'Brien
1

JavaScript ES6, 297 293 bytes

Basicamente, uma versão compactada da implementação fornecida.

b=(n,e)=>{r=n.split`
`.reverse(),t=r.length,a=r[0].indexOf`#`,f=r[i=l=0].lastIndexOf`#`+1;e*=n.indexOf`~o`>-1?-1:1;for(d=t-1;d>=0;d--)r[d].split``.map((n,r,t)=>{(j="#")==n&&((0>e&&j!=t[r-1]||e>0&&j!=t[r+1])&&(i+=(d+.5)*-e,l+=(d+.5)*-e),i+=a-(r+.5),l+=f-(r+.5))},0);return i>0?"L":0>l?"R":"B"}

Semi-expandido:

b = (n, e) => {
    r = n.split `
`.reverse(), t = r.length, a = r[0].indexOf `#`, f = r[i = l = 0].lastIndexOf `#` + 1;
    e *= n.indexOf `~o` > -1 ? -1 : 1;
    for (d = t - 1; d >= 0; d--) r[d].split ``.map((n, r, t) => {
        (j = "#") == n && ((0 > e && j != t[r - 1] || e > 0 && j != t[r + 1]) && (i += (d + .5) * -e, l += (d + .5) * -e), i += a - (r + .5), l += f - (r + .5))
    }, 0);
    return i > 0 ? "L" : 0 > l ? "R" : "B"
}
Conor O'Brien
fonte