¡Más cencerro ...!

42

Usted está proporcionando soporte técnico a la Bruce Dickenson ya que produce una sesión de grabación Blue Öyster Cult. Cuando pide más cencerro , puedes dárselo.

Tu tarea

Escriba un programa o función que tome una cadena (o equivalente en su idioma) como entrada y genere una cadena relacionada que contenga un cencerro más.

¿Cuántos cencerros contiene una cuerda?

El número de cencerros que contiene una cadena es igual al número máximo de copias distintas de "cencerro" que se pueden obtener al permutar los caracteres de la cadena. Por ejemplo, "bbbccceeellllllooowwwwwwwww"consta de 3 cowbells, mientras que "bbccceeellllllooowwwwwwwww"y "bbbccceeelllllooowwwwwwwww"contienen cada uno 2 cencerros, y "cowbel"contiene 0 cowbells.

¿Cómo debe relacionarse la salida con la entrada?

La salida debe consistir en la concatenación, en este orden, de la cadena de entrada y el prefijo más corto de la cadena de entrada necesaria para aumentar el número de cencerros.

Por ejemplo, "bbbccceeelllllooowwwwwwwww"solo necesita uno adicional "l"para contener 3 cencerros en lugar de 2; el prefijo más corto que contiene ese "l"es "bbbccceeel". Por lo tanto, si la entrada es "bbbccceeelllllooowwwwwwwww", entonces la salida debería ser "bbbccceeelllllooowwwwwwwwwbbbccceeel".

Tecnicismos

  • Puede suponer que la entrada contiene solo caracteres ASCII imprimibles. Si hay uno o dos caracteres que son molestos para el procesamiento de cadenas de su idioma (como líneas nuevas o \), puede suponer que la entrada no los contiene, solo mencione esta restricción.
  • Además, puede suponer que los caracteres alfabéticos en la entrada están en minúsculas o en mayúsculas. Si elige no asumir uno de estos, cuente los cencerros sin distinción entre mayúsculas y minúsculas.
  • Se puede suponer, además, que la entrada contiene al menos una copia de cada uno de los personajes b, c, e, l, o, y w. Esto es equivalente a suponer que se puede concatenar algún prefijo de la cadena para producir una cadena que contenga más cencerro. (Tenga en cuenta que la cadena de entrada en sí no necesita contener un cencerro).
  • Si su idioma tiene una solución integrada que resuelve este problema ... entonces úsela totalmente, en serio, cuán increíble es eso.

Pañales bañados en oro

Como el tiempo de grabación en el estudio es costoso, su código debe ser lo más breve posible. ¡La entrada con la menor cantidad de bytes es la ganadora!

Casos de prueba

( enlace de pastebin para copiar / pegar más fácilmente)

Entrada de prueba n. ° 1: "christopher walken begs for more cowbell!"

Salida de prueba n. ° 1: "christopher walken begs for more cowbell!christopher wal"

Entrada de prueba # 2: "the quick brown fox jumps over the lazy dog"

Prueba de salida # 2: "the quick brown fox jumps over the lazy dogthe quick brown fox jumps over the l"

Entrada de prueba # 3: "cowbell"

Prueba de salida # 3: "cowbellcowbell"

Entrada de prueba # 4: "cowbell cowbell cowbell"

Prueba de salida # 4: "cowbell cowbell cowbellcowbell"

Entrada de prueba # 5: "cowbell cowbell cowbel"

Prueba de salida # 5: "cowbell cowbell cowbelcowbel"

Entrada de prueba # 6: "bcelow"

Prueba de salida # 6: "bcelowbcel"

Entrada de prueba # 7: "abcdefghijklmnopqrstuvwxyz"

Prueba de salida # 7: "abcdefghijklmnopqrstuvwxyzabcdefghijkl"

Entrada de prueba # 8: "cccowwwwbbeeeeelllll"

Prueba de salida # 8: "cccowwwwbbeeeeelllllccco"

Entrada de prueba # 9: "be well, programming puzzles & code golf"

Prueba de salida # 9: "be well, programming puzzles & code golfbe well, programming puzzles & c"

Entrada de prueba # 10: "lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. wow!"

Prueba de salida # 10: "lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. wow!lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut lab"

Entrada de prueba # 11:

"c-c-b-c

i have a cow, i have a bell.
uh! bell-cow!
i have a cow, i have a cowbell.
uh! cowbell-cow!

bell-cow, cowbell-cow.
uh! cow-cowbell-bell-cow.
cow-cowbell-bell-cow!
"

Prueba de salida # 11:

"c-c-b-c

i have a cow, i have a bell.
uh! bell-cow!
i have a cow, i have a cowbell.
uh! cowbell-cow!

bell-cow, cowbell-cow.
uh! cow-cowbell-bell-cow.
cow-cowbell-bell-cow!
c-c-b-c

i have a cow, i have a bell"
Greg Martin
fuente
23
Cualquier persona que contesta en VACA gana puntos de Internet diez.
Pavel
3
Creo que sería mucho más fácil para las personas manejar los casos de entrada / salida si los formatea en un solo bloque de código. Tal como está, ocupa mucho espacio y no es muy fácil de copiar y pegar.
FryAmTheEggman
Enlace de Pastebin agregado para copiar / pegar. Si hay una manera de ocultar / contraer / mostrar los casos de prueba en esta publicación, ahorrando así espacio vertical, me encantaría aprenderlo.
Greg Martin el
2
Bueno, normalmente la gente usa test case -> resulten un gran bloque de código preformateado. Es mucho más agradable estéticamente y más fácil copiar y pegar.
FlipTack
1
@MatthewRoh Aparte del hecho de que hay dos Ls en la palabra, esto no es lo que pide el desafío.
Martin Ender

Respuestas:

13

Pip , 50 42 38 bytes

T$<(MN{_NaM"lcowbe"}//^2M[aYa@<i])++iy

Pase la cadena como un argumento de línea de comandos, citado si es necesario. Pruébalo en línea!

Explicación

Voy a explicar esto en dos partes: la función cencerro y el programa completo. Primero, aquí está la función que calcula la cantidad de cencerro en una cadena:

MN{_NaM"lcowbe"}//^2

{...}define una función Muchos operadores Pip, cuando se aplican a una función, devuelven otra función; por ejemplo, -{a+1}es lo mismo que {-(a+1)}. Entonces lo anterior es equivalente a

{MN(_NaM"lcowbe")//^2}

que funciona de la siguiente manera:

{                    }  Function, in which a is the 1st argument (the string)
    _Na                 Lambda fn: returns number of times its argument occurs in a
       M"lcowbe"        Map that function to the characters of "lcowbe"
                   ^2   A devious way to get [2]: split the scalar 2 into characters
   (            )//     Int-divide the list of character counts by [2]
                        Since the lists are not the same length, this divides the first
                          element (# of l's) by 2 and leaves the others alone
 MN                     Take the min of the resulting list

Ahora que tenemos eso, aquí está el programa completo:

T$<(MN{_NaM"lcowbe"}//^2M[aYa@<i])++iy
                                        a is 1st cmdline arg, i is 0 (implicit)
T                                       Loop till condition is true:
                            a@<i        Slice leftmost i characters of a
                           Y            Yank that into y variable
                         [a     ]       List containing a and that value
                        M               To that list, map...
    MN{_NaM"lcowbe"}//^2                ... the cowbell function
                                        Result: a list containing the amount of cowbell
                                        in the original string and the amount in the slice
 $<(                             )      Fold on less-than: true if the first element is
                                        less than the second, otherwise false
                                  ++i   In the loop, increment i
                                     y  Once the loop exits, print y (the latest slice)
DLosc
fuente
Entré cowbell cowbell cowbeey la salida fue cowbellcowbelcowbelpero podría estar usando el IDE incorrecto (nuevo en PIP)
Albert Renshaw
@AlbertRenshaw me sale cowbell cowbell cowbeecowbell( pruébalo en línea ). ¿Estás utilizando TIO o una copia local?
DLosc
¡Oh bien! Lo estaba pegando debajo del campo "input" no debajo del argumento add. +1
Albert Renshaw
Realmente de primera clase. Lo porté a javascript.
edc65
6

C, 511 488 474 470 463 454

void f(char*a){char*s;int i=-1,c,o,w,b,e=b=w=o=c=1,l=3,n,r,z=i;for(;s=a[++i];c+=s==67,o+=s==79,w+=s==87,b+=s==66,e+=s==69,l+=s==76);r=~-l/2;n=c<o?c:o;n=w<n?w:n;n=b<n?b:n;n=e<n?e:n;n=r<n?r:n;c=c==n;o=o==n;w=w==n;b=b==n;e=e==n;if(l=r==n?l:0)if(l%2)l=2;else l=1,c=o=w=b=e=0;else l+=l%2;n=c+o+w+b+e+l;for(printf("%s",a);s=n?a[++z]:0;s==67&&c?n--,c--:0,s==79&&o?n--,o--:0,s==87&&w?n--,w--:0,s==66&&b?n--,b--:0,s==69&&e?n--,e--:0,s==76&&l?n--,l--:0,putchar(s));}

Pruébalo en línea


Formato legible + explicación:

void f(char*a){
//a = input

    char*s;

    int i=-1,c,o,w,b,e=b=w=o=c=1,l=3,n,r,z=i;//c,o,w,b,e all start at 1; L starts at 3

    for(;s=a[++i];c+=s==67,o+=s==79,w+=s==87,b+=s==66,e+=s==69,l+=s==76);
    //loop to obtain number of times each character C,O,W,B,E,L is found in string (using the ASCII numeric values of each letter)

    //to get an extra cowbell we need to increment C,O,W,B,E by 1 and L by 2 (two Ls in cowbell); except we don't have to because we already did that by starting them at c=1, o=1, w=1, b=1, e=1, L=3 when we declared them. 

    r=~-l/2;
    //r is half of (1 less the number of times L is in string (+ init value))

    n=c<o?c:o;n=w<n?w:n;n=b<n?b:n;n=e<n?e:n;n=r<n?r:n;
    //n is the number of times that the least occouring character appears in the string, (use R instead of L since cowbell has two L's in it and we just need ~-l/2)

    c=c==n;o=o==n;w=w==n;b=b==n;e=e==n;
    //convert c,o,w,b,e to BOOL of whether or not we need 1 more of that letter to create one more cowbell (logic for L handled below since it's trickier)

    if(l=r==n?l:0)//if L-1/2 is [or is tied for] least occurring character do below logic, else set l to 0 and skip to `else`
        if(l%2)//if l is divisible by 2 then we need 2 more Ls
            l=2;
        else //otherwise we just need 1 more l and no other letters
            l=1,c=o=w=b=e=0;
    else //add 1 to L if it's divisible by 2 (meaning just 1 more L is needed in addition to possibly other C,O,W,B,E letters) (*Note: L count started at 3, so a count of 4 would be divisible by 2 and there is only 1 L in the string)
        l+=l%2;

    n=c+o+w+b+e+l;
    //n = number of specific characters we need before we reach 1 more cowbell

    for(printf("%s",a);s=n?a[++z]:0;s==67&&c?n--,c--:0,s==79&&o?n--,o--:0,s==87&&w?n--,w--:0,s==66&&b?n--,b--:0,s==69&&e?n--,e--:0,s==76&&l?n--,l--:0,putchar(s));
    //loop starts by printing the original string, then starts printing it again one character at a time until the required number of C,O,W,B,E,L letters are reached, then break (s=n?a[++z]:0) will return 0 when n is 0. Each letter subtracts from n only when it still requires letters of its type (e.g. b?n--,b--:0)

}

Algunos trucos divertidos utilizados:

• Cuando verifico caracteres, escribo 'w'para el carácter que es de 3 bytes, pero para los caracteres 'c'y 'b'puedo escribir sus valores ASCII 99 y 98 respectivamente para guardar un byte cada vez. (Editar: Gracias a @Titus, sé hacer esto con todas las letras de COWBELL utilizando solo mayúsculas, que son valores ascii numéricos de 2 bytes)

r=~-l/2está r=(l-1)/2utilizando cambios de bits

a[++i]Estoy obteniendo el carácter en el índice (i) e iterando el índice todo al mismo tiempo. Solo comienzo ien i=-1lugar de i=0(hago lo mismo con zy lo inicio z=ipara guardar otro byte)

Albert Renshaw
fuente
1
Ahorre 8 bytes con entrada en mayúscula: todos los códigos ASCII por debajo de 100.
Titus
@Titus Brilliant! Gracias Titus, editando ahora
Albert Renshaw
1
Actualmente tenemos una pregunta con respecto a su declaración "El segundo int definido (en este caso c) siempre se establece como 1 [...]". Nos agradaría tener su declaración de por qué lo piensa así porque a algunos de nosotros nos parece extraño.
cadaniluk
@ Albert, ¿podría ser que su programa solo c,o,w,b,ese inicialice con el mismo valor, en lugar de 1? Debido a que su pista # 2 parece no ser cierta, al menos no para que CI lo sepa. ¿Puedes aclarar? Pregunta SO
Felix Dombek
1
@FelixDombek gracias por señalarlo también! Es def. comportamiento indefinido, acabo de simularlo (en bucle) en muchos IDEs y parece que siempre inicia el int como 0. Probablemente podría dejarlo después de todo, aunque mi lógica fue diseñada para tenerlos todos configurados en 1; Creo que el hecho de que los casos de prueba funcionen con él en 0 es una coincidencia. Saludos
Albert Renshaw
5

Python 2, 125 113 112 bytes

n=lambda s:min(s.count(c)>>(c=='l')for c in "cowbel")
def f(s,i=0):
 while n(s)==n(s+s[:i]):i+=1
 return s+s[:i]

n cuenta el número de cencerros


-12 bytes gracias a @Rod
-1 byte gracias a @Titus

ovs
fuente
no necesita []la comprensión de la lista cuando es el único parámetro, también puede descartar enumerate: ¿ min(s.count(c)/-~(c=='l')for c in"cowbel")dónde -~(n=='l')hay una forma más corta de escribir1+(n=='l')
Rod
1
¿No >>sería más corto que /-~?
Tito el
@Titus usted correcto
ovs
Hubo un intento de edición que habría eliminado un byte al reemplazar el último espacio de nueva línea con un solo punto y coma.
Wheat Wizard
@ Möbius ¿No returnestaría el en el bucle while entonces?
ovs
5

Perl 6 , 91 bytes

{my &c={.comb.Bag.&{|.<c o w b e>,.<l>div 2}.min}
first *.&c>.&c,($_ X~[\,](.comb)».join)}

Asume una entrada en minúscula.

Cómo funciona

Dentro de la lambda, otra lambda para contar el número de cencerros en una cadena se define como tal:

my &c={                                        }  # Lambda, assigned to a variable.
       .comb                                      # Split the string into characters.
            .Bag                                  # Create a Bag (maps items to counts).
                .&{                       }       # Transform it into:
                   |.<c o w b e>,                 #   The counts of those letters, and
                                 .<l>div 2        #   half the count of "l" rounded down.
                                           .min   # Take the minimum count.

El resto del código usa este lambda interno &cpara encontrar el resultado, así:

                     [\,](.comb)».join   # All prefixes of the input,
               ($_ X~                 )  # each appended to the input.
first         ,                          # Return the first one for which:
      *.&c>                              #   The cowbell count is greater than
           .&c                           #   the cowbell count of the input.
smls
fuente
4

MATL , 38 37 bytes

1 byte apagado gracias a la idea de @ DLosc de usar la cadena de plantilla en lcowbelugar decowbel

n`Gt@q:)hXK!'lcowbe'=s32BQ/kX<wy-Q]xK

Los caracteres de entrada son todos minúsculas. Si la entrada contiene nuevas líneas, el carácter de nueva línea debe ingresarse ya que su código ASCII se concatena con los caracteres normales (consulte la última entrada en el enlace con todos los casos de prueba).

Pruébalo en línea! O verificar todos los casos de prueba .

Luis Mendo
fuente
3

JavaScript (ES6), 106 107 113 126 141

Una transferencia a javascript de la respuesta Pip por @DLosc. Necesitaba algo de tiempo para entenderlo completamente, y es genial.

Edite -15 bytes siguiendo la sugerencia de @Titus, agregando caracteres directamente a la cadena de entrada ay evitando el retorno temprano (así que no for/if)

Edit 2 enumerando el valor 6 para la función Min guarda otros 13 bytes

Edit 3 cambió la función c nuevamente. Pensé en lo detallado lengthy splitsería demasiado largo. Estaba equivocado.

Asumiendo entrada en minúsculas

a=>[...a].some(z=>c(a+=z)>b,c=a=>Math.min(...[...'lcowbe'].map((c,i)=>~-a.split(c).length>>!i)),b=c(a))&&a

Menos golf

a=>{
  c=a=>{ // cowbell functions - count cowbells
    k = [... 'lcowbe'].map((c,i) => 
          (a.split(c).length - 1) // count occurrences of c in a
           / (!i + 1) // divide by 2 if first in list ('l')
    );
    return Math.min(...k);
  };
  b = c(a); // starting number of cowbells
  [...a].some(z => ( // iterate for all chars of a until true
    a += z,
    c(a) > b // exit when I have more cowbells
  ));
  return a;
}

Prueba

f=
a=>[...a].some(z=>c(a+=z)>b,c=a=>Math.min(...[...'lcowbe'].map((c,i)=>~-a.split(c).length>>!i)),b=c(a))&&a

;["christopher walken begs for more cowbell!"
,"the quick brown fox jumps over the lazy dog"
,"cowbell"
,"cowbell cowbell cowbell"
,"cowbell cowbell cowbel"
,"bcelow"
,"abcdefghijklmnopqrstuvwxyz"
,"cccowwwwbbeeeeelllll"
,"be well, programming puzzles & code golf"
,"lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. wow!"
,`c-c-b-c
 
i have a cow, i have a bell.
uh! bell-cow!
i have a cow, i have a cowbell.
uh! cowbell-cow!
 
bell-cow, cowbell-cow.
uh! cow-cowbell-bell-cow.
cow-cowbell-bell-cow!
`].forEach(x=>console.log(x+'\n\n'+f(x)))

edc65
fuente
Supongo que eso k[x]++fallaría debido a undefined. Pero estoy bastante seguro de que for(i=0;c(a)==c(a+=a[i++]);),afunciona.
Titus
@Titus No estoy seguro de entender. Lo intentaré
edc65
@Titus wow 15 bytes guardados, muchas gracias
edc65
>>!iahorra 3 bytes. ¿Por qué no lo usas c(a+=z)?
Tito
@Titus que uso c(a+=z). No en la versión menos golfizada , ya que es, ya ves, menos golfizada. Usando >>!iahorra 1 byte (en la versión de golf). Gracias de nuevo
edc65
2

Bash + Unix utilidades, 184 bytes

f()(tr -cd cowbel<<<"$1"|sed 's/\(.\)/\1\
/g'|sort|uniq -c|awk '{print int($1/(($2=="l")?2:1))}'|sort -n|head -1)
for((m=1;`f "$1${1:0:m}"`!=$[`f "$1"`+1];m++)){ :;}
echo "$1${1:0:$m}"

Pruébalo en línea!

Gracias a @AlbertRenshaw por jugar 2 bytes de descuento.

Mitchell Spector
fuente
Esto se puede jugar aún más, por ejemplo, simplemente eliminando los espacios antes y después del!=
Albert Renshaw
1
@AlbertRenshaw Gracias, pensé que lo había intentado y obtuve un error de sintaxis, pero tienes razón. La parte awk puede ser más golfable también; No estoy muy familiarizado con awk.
Mitchell Spector
Sí, intenté ingenuamente eliminar otros espacios y saltos de línea en su código y estaba recibiendo errores de sintaxis, pero en ese funcionó ¯_ (ツ) _ / ¯
Albert Renshaw
2

JavaScript (ES6), 124 114 bytes

Gracias a Neil por guardar unos pocos bytes.

a=>eval("for(c=0,d=a;(A=$=>Math.min([...'cowbel'].map(_=>($.split(_).length-1)>>(_=='l'))))(a)==A(d+=a[c++]););d")

Como esto es bastante diferente de la respuesta JavaScript ya existente, y dediqué bastante tiempo a esto, decidí crear una respuesta yo mismo.

Uso

f=a=>eval("for(c=0,d=a;(A=$=>Math.min([...'cowbel'].map(_=>($.split(_).length-1)>>(_=='l'))))(a)==A(d+=a[c++]););d")
f("cowbell")

Salida

"cowbellcowbell"
Luke
fuente
.sort()[0]Es una idea maravillosa. evales malvado : D
Titus
Gracias ;-) Lo usé por primera vez Math.min(), pero eso costó muchos personajes, y pensé que habría un camino más corto. Y sí, evales realmente bueno para jugar al golf.
Lucas
Si solo .sort()[0]funcionara, solo costaría 10 bytes, pero no lo hace, y .sort((a,b)=>a-b)[0]cuesta 20 bytes pero Math.min(...)solo cuesta 13.
Neil
2

Octava, 80 87 97 bytes

s=input('');k=1;do;until(x=@(A)min(fix(sum('cowbel'==A')./('111112'-48))))(b=[s s(1:++k)])>x(s);b

¡Pruébelo en línea!

rahnema1
fuente
1
Esto no funciona cuando necesitamos dos lsegundos para completar el cencerro adicional. Por ejemplo, en la entrada cowbell, devuelve incorrectamente en cowbellcowbellugar de cowbellcowbell. (Espero que pueda solucionarlo, ¡me gusta el algoritmo atípico!)
Greg Martin
@GregMartin Gracias! ¡Lo revisaré!
rahnema1
2

CJam, 37

q___S\+{+"cowbel"1$fe=)2/+:e<\}%()#)<

Pruébalo en línea

Si puedo excluir los caracteres "y \, entonces ...

35 bytes

q___`{+"cowbel"1$fe=)2/+:e<\}%()#)<

Pruébalo en línea

Explicación

El código agrega sucesivamente cada carácter de la cadena a la cadena inicial (va del original al doble), determina el número de cencerros para cada cadena (contando el número de apariciones de cada carácter en "cowbel" y dividiendo el de 'l' en 2, luego toma el mínimo), encuentra la posición de la primera cadena donde el número de cencerros aumenta en 1, luego toma el prefijo correspondiente de la entrada y lo coloca después de la cadena de entrada.

Para incluir también la cadena original (sin caracteres añadidos), el código antepone un carácter neutral a la cadena que se está iterando. La primera versión antepone un espacio, y la segunda versión utiliza la representación de cadena, es decir, la cadena entre comillas dobles.

q___          read input and make 3 more copies: one for output, one for prefix,
               one for appending and one for iterating
S\+           prepend a space to the iterating string
              or
`             get the string representation
{…}%          map each character of the string
  +           append the character to the previous string
  "cowbel"    push this string
  1$          copy the appended string
  fe=         get the number of occurrences of each "cowbel" character
  )2/+        take out the last number, divide by 2 and put it back
  :e<         find the minimum
  \           swap with the appended string
(             take out the first number (cowbells in the initial string)
)#            increment and find the index of this value in the array
)             increment the index (compensating for taking out one element before)
<             get the corresponding prefix
              another copy of the input is still on the stack
              and they are both printed at the end
aditsu
fuente
Estoy bien contigo excluyendo los caracteres "y \"
Greg Martin
1

PHP, 133 bytes

un puerto PHP del puerto JavaScript de @ edc65 de la respuesta Pip de DLosc.

function f($s){for(;$c=lcowbe[$i];)$a[$c]=substr_count($s,$c)>>!$i++;return min($a);}for($s=$argv[1];f($s)==f($s.=$s[$i++]););echo$s;

toma la entrada en minúscula del argumento de la línea de comando. Corre con -nr.

Descompostura

// function to count the cowbells:
function f($s)
{
    for(;$c=lcowbe[$i];)            # loop through "cowbel" characters
        $a[$c]=substr_count($s,$c)  # count occurences in $s
            >>!$i++;                # divide by 2 if character is "l" (first position)
        return min($a);             # return minimum value
}
for($s=$argv[1];    # copy input to $s, loop:
    f($s)               # 1. count cowbells in $s
    ==                  # 3. keep looping while cowbell counts are equal
    f($s.=$s[$i++])     # 2. append $i-th character of $s to $s, count cowbells
;);
echo$s;             # print $s
Titus
fuente