Generar una cadena de lanzamiento de béisbol

11

Objetivo

Escriba un programa o función que tome un número entero positivo ny genere aleatoriamente una serie legal de tonos (de aquí en adelante llamada cadena de tono) de longitud n.

Entrada

Un entero positivo distinto de cero n<= 100

Salida

Devuelve una cadena aleatoria, o una lista de caracteres, que representan una posible cadena de tono válida de longitud n. Los caracteres utilizados serán:

  • B - Pelota. Si acumula 4 de estos, la masa se camina y termina de batear.
  • S - Huelga. Si acumula 3 de estos, la masa está fuera y terminó de batear.
  • F - Falta. También aumentará el recuento de golpes, pero no puede sacar al bateador. Es decir, no puede hacer que un Foul sea el último lanzamiento de una cadena válida. Cualquier falta después de dos golpes / faltas no aumentará el conteo de Golpes (el bateador ya tiene 2 golpes en ese punto y un tercero lo sacaría).
  • H - Hit. El bateador ha golpeado una pelota en juego y ha terminado de batear.

(Esto se simplifica ligeramente, pero no te preocupes por eso)

Las cuerdas de lanzamiento válidas son aquellas que terminan en un ponche, una caminata o un golpe.

Es decir, una cadena de tono inválida tiene

  • lanzamientos adicionales después de la 4ta bola, 3ra huelga o golpe
  • terminado antes de generar una cuarta bola, tercer golpe o golpe.

Reglas

  • Su programa debe poder producir todos los resultados posibles para una entrada dada.
  • Su programa no tiene que ser uniformemente aleatorio, pero debe seguir la regla anterior.
  • Este es el .

Ejemplos

Input => Possible Outputs
1 => [H] #Can only end with a hit
2 => [S,H], [B,H], [F,H] #Can only end with a hit
3 => [S,S,S], [F,F,S], [B,B,H], ... #Can now strike-out, otherwise must end with a hit
4 => [B,B,B,B], [S,B,S,S], [B,F,S,S], [B,B,B,H], ... #Can now be walked, struck-out, or get a hit
6 => [S,B,S,B,B,H], [F,F,F,F,F,S], ... #Can now have a full-count (3 balls, 2 strikes) before finishing 

Input => Invalid Outputs
1 => [S], [B]    #Not enough for a strike-out/walk
2 => [S,S]       #Not enough for a strike-out/walk
2 => [H,H]       #Batter has already scored a hit
3 => [S,S,F]     #Fouls will not cause a strike-out
4 => [S,S,S,H]   #Batter has already struck out
5 => [B,B,B,B,B] #Batter has already walked
Veskah
fuente
1
Entonces, ¿debemos ser capaces de producir desde 1 hasta F infinitos?
Quintec
La cadena tendrá como máximo 100 caracteres de longitud. Las faltas son lo que permite cuerdas de pitcheo tan largas, por ejemplo, 99 Fsy a Ses un
ponche
Oh, lo tengo, me perdí eso
Quintec
@Quintec Reescrito para que sea un poco más explícito por si acaso
Veskah

Respuestas:

4

Python 2 , 128 bytes

from random import*
def g(n):
 x=i=S=0;r=''
 while(S>2)+x<3>=i-S:x=randint(0,3);r+='BFSH'[x];S+=x>0;i+=1
 return(i==n)*r or g(n)

Pruébalo en línea!

Genere aleatoriamente la secuencia de tono hasta que la masa esté lista, envíela si resulta que tiene la longitud correcta y, de lo contrario, intente nuevamente desde cero.


Python 2 , 136 bytes

from random import*
def g(n):
 B=H=F=S=0;r=''
 while(F+S<3or'S'>x)>B/4+H:x=choice('BHFS');r+=x;exec x+"+=1"
 return(len(r)==n)*r or g(n)

Pruébalo en línea!

xnor
fuente
El puerto de Kevin de esto me hizo darme cuenta de que esto se desglosa para números más altos. n=8puede generar una cadena de Fs al final
Veskah
2
@Veskah Buena captura. No había tenido en cuenta el recuento de golpes (contando faltas) posiblemente subiendo a 6 y cambiando S/3para (S>2)arreglarlo.
xnor
4

05AB1E ,  44  50 44 bytes

Tachado ya &nbsp;44&nbsp;no es 44 :)

[õ0U.µ["BFSH"3ÝΩ©è«®ĀX+U¼X2›®+3@¾X-3›~#}I¾Q#

Puerto de la respuesta Python 2 de @xnor , ¡así que asegúrate de votarlo también si te gusta esta respuesta!
+6 bytes debido a una corrección de errores, y después de eso -6 bytes nuevamente gracias a @xnor al portar su solución más eficiente en comparación con mi solución temporal, como esperaba. ;)

Pruébelo en línea o verifique algunas salidas más aleatorias .

Explicación:

[                # Start an infinite loop:
 õ               #  (Re)set the result-string to an empty string ""
 0U              #  (Re)set variable `X` to 0
               #  Reset the counter_variable to 0
   [             #  Start an inner infinite loop:
    "BFSH"       #   Push string "BFSH"
          3ÝΩ    #   Push a random integer in the range [0,3]
             ©   #   Store this random integer in variable `r` (without popping)
              è  #   Index it into the string "BFSH"
               « #   Append it to the result-string
    ®Ā           #   If `r` is NOT 0:
      X+U        #    Increase `X` by 1
    ¼            #   Increase the counter_variable by 1
    X2›®+        #   Calculate `X`>2 (1 if truthy; 0 if falsey) + `r`
         3@      #   Check if this is larger than or equal to 3
    ¾X-          #   Calculate counter_variable - `X`
       3        #   Check if this is larger than 3
    ~            #   If either of the two checks above is truhy:
     #           #    Stop the inner infinite loop
   }             #  After the inner infinite loop:
    I¾Q          #  If the input and counter_variable are equal:
       #         #   Stop the outer infinite loop
                 # (and output the result-string at the top of the stack implicitly)
Kevin Cruijssen
fuente
1
@Veskah He hecho una solución directa por ahora. Tengo la sensación de que xnor puede hacer una solución más corta, por lo que probablemente portaré su solución para guardar algunos bytes más adelante. :)
Kevin Cruijssen
1
Puedes arreglarlo como lo hice cambiando X/3a X>2.
xnor
@xnor Gracias, nuevamente a 44 bytes. Sabía que encontrarías algo más corto. ; p
Kevin Cruijssen
3

R , 148 bytes

function(n){`~`=paste0
`*`=sample
o=""
while(nchar(o)<n-1){a=c("B"[T<4],"F","S"[F<2])*1
F=F+(a>"E")
T=T+(a<"F")
o=o~a}
o~c("B"[T>3],"H","S"[F>1])*1}

Pruébalo en línea!

Genera la cadena, utilizando la inclusión condicional en los conjuntos de datos de muestreo para garantizar que el resultado sea una posible secuencia de tono.

Posiblemente hacer un muestreo de rechazo (como lo hace la respuesta de Python de xnor ) es más corto.

function(n){`~`=paste0		# alias
`*`=sample			# alias
o=""				# empty string for output
while(nchar(o)<n-1){		# do n-1 times:
a=c("B"[T<4],"F","S"[F<2])*1	# sample 1 from the string "BFS", conditionally including B or S if the ball/strike count is 3/2	
F=F+(a>"E")			# increment F (strike count) if sampled character is F or S
T=T+(a<"F")			# increment T (ball count) if sampled character is B
o=o~a}				# append a to output

o~c("B"[T>3],"H","S"[F>1])*1}	# append the sampled "BHS", conditionally including B or S if the ball/strike count is 3/2.

Referencia aleatoria "F y S" que seguía jugando en mi cabeza cada vez que escribía una de esas letras ...

Giuseppe
fuente
2

Pyth, 53 bytes

u+GO?H+W<K/G\B3+W<Jl@"SF"G2\F\S\B+WqK3+WgJ2\H\S\B_UQ[

Pruébelo en línea aquí .

Esto se siente demasiado tiempo, creo que se puede requerir otro enfoque.

u+GO?H+W<K/G\B3+W<Jl@"SF"G2\F\S\B+WqK3+WgJ2\H\S\B_UQ[   Implicit: Q=eval(input())
                                                 _UQ    Reversed range from Q-1 to 0
u                                                   [   Reduce the above, with initial value G=[], next value as H:
                    @"SF"G                                Keep elements of G which are in "SF"
                   l                                      Length of the above
                  J                                       Store in J - this is the number of strikes and fouls so far
          /G\B                                            Count number of "B"s in G
         K                                                Store in K - this is the number of balls so far
    ?H                                                    If H is not 0 (i.e. not final pitch):
                           \F                               Start with "F" (foul is always available in non-final pitch)
                W<J       2                                 If J<2...
               +             \S                             ... append "S"
       W<K    3                                             If K<3...
      +                        \B                           ... append "B"
                                                          Else:
                                           \H               Start with "H" (hit is always available in final pitch)
                                       WgJ2                 If J >= 2...
                                      +      \S             ... append "S"
                                  WqK3                      If K == 3...
                                 +             \B           ... append "B"
   O                                                      Choose one element at random from the available options
 +G                                                       Append the above to G
                                                        Implicit print the result of the reduce operation
Sok
fuente
2

JavaScript (ES6),  107 106  99 bytes

f=(n,k=p=s=0,o='')=>p&&p>2|k-s>3|s>2&p<2?k-n?f(n):o:f(n,k+1,o+'FSBH'[p=Math.random()*4|0,s+=p<2,p])

Pruébalo en línea!

Comentado

f = (                       // f = recursive function taking:
  n,                        //   n = requested length
  k =                       //   k = pitch counter, initialized to 0
  p =                       //   p = last pitch
  s = 0,                    //   s = sum of strikes and fouls
  o = ''                    //   o = output string
) =>                        //
  p &&                      // if the last pitch was not a foul
  p > 2 |                   // AND the last pitch was a hit
  k - s > 3 |               //     OR we have 4 balls (or 3 balls + 1 hit)
  s > 2 & p < 2 ?           //     OR more than 2 strikes or fouls, ending with a strike:
    k - n ?                 //   if k is not equal to n:
      f(n)                  //     valid series but bad timing: try again from scratch
    :                       //   else:
      o                     //     success: return o
  :                         // else:
    f(                      //   do a recursive call:
      n,                    //     n is unchanged
      k + 1,                //     increment k
      o + 'FSBH'            //     append the pitch letter to o
        [ p = Math.random() //     pick a new random pitch
              * 4 | 0,      //     in [0..3]
          s += p < 2,       //     increment s if the pitch is a foul or a strike
          p ]               //     actual index in 'FSBH'
    )                       //   end of recursive call
Arnauld
fuente
2

Tinta , 120 119 116 117 bytes

=f(n)
->g(n,3,2)
=g(n,b,s)
~n--
{n:{~{b:b->g(n,b-1,s)}|{s:s->g(n,b,s-1)}|}f->g(n,b,s-(s>0))|{~{b:h|b}|{s:h|s}|h}}->->

Pruébalo en línea!

Probablemente todavía golfable.

Sin golf (ligeramente reformateado)

=f(length) // Define a stitch f, with one parameter which specifies the length of the created string. This is the intended entry point.
->g(length,3,2) // Instantly divert to g, defined below, with some extra parameters

=g(length,balls_left,strikes_left) // Define a stitch g, with three parameters.
~ length--                         // Decrement remaining length
{
    - length: // If this is not to be the last character in the string
              // randomly do one of the following:
              // 1. If balls_left is nonzero, print a b and recurse
              // 2. If strikes_left is nonzero, print an s and recurse
              // 3. Do nothing
              // If we did not divert earlier, print an f and recurse.
        {~{balls_left:b->g(length,balls_left-1,strikes_left)}|{strikes_left:s->g(length,balls_left,strikes_left-1)}|}f->g(length,balls_left,strikes_left-(strikes_left>0)) 
    - else: // Randomly do one of the following
            // 1. If a ball would result in a walk, print a b, otherwise an h.
            // 2. If a strike would result in a strikeout, print an s, otherwise an h.
            // 3. Just print an h.
            // And finally, halt.
        {~{balls_left:h|b}|{strikes_left:h|s}|h}}->->

Ediciones

  1. Guardado un byte al terminar con en ->->lugar de ->END.
  2. Ahorró tres bytes disminuyendo nantes.
  3. Se corrigió un error que causaba ponches en lugares incorrectos, gracias a @veskah por detectarlo (+1 byte)
Sara J
fuente
1
Basado en la escritura y las salidas, parece que no tiene en cuenta las faltas que incrementan el conteo de
golpes
1
@veskah Bien visto, debería arreglarse ahora, gracias
Sara J
1

Carbón , 57 bytes

≔⁰η≔⁰ζF⊖N«≔‽⁺²‹ζ³ι¿›ι¹≦⊕ζ≦⊕η§SFB∨ι›η²»⊞υHF›η¹⊞υSF›ζ²⊞υB‽υ

Pruébalo en línea! El enlace es a la versión detallada del código. Explicación:

≔⁰η≔⁰ζ

Comienza con 0 bolas y 0 golpes.

F⊖N«

Recorra todas las entregas excepto la última.

≔‽⁺²‹ζ³ι

Si han sido menos de tres bolas, entonces genere un número aleatorio de 0 a 2, de lo contrario solo haga un coinflip entre 0 y 1.

¿›ι¹≦⊕ζ≦⊕η

Un valor aleatorio de 2 es una bola; de lo contrario, aumenta el recuento de golpes.

§SFB∨ι›η²»

Los valores 0 a 2 se asignan al golpe, falta y bola, excepto que si hubiera tres golpes, se imprime la falta. (Cuatro bolas están excluidas arriba).

⊞υHF›η¹⊞υSF›ζ²⊞υB‽υ

Determine si un golpe o una bola sacarían al bateador y elija entre ellos o un golpe, según corresponda.

Neil
fuente
1

Perl 5 , 122 bytes

map{$B=$S=$H=0;while($B<4&&$S<3&&!$H&&/./g){${$&}++;$S+=$&eq F&&$S<2}y///c>pos||push@a,$_}glob"{B,F,H,S}"x<>;say$a[rand@a]

Pruébalo en línea!

Xcali
fuente
1
@Veskah Me perdí esa parte. Arreglado.
Xcali
1

C (GCC) 164 145 142 bytes

-3 bytes ceilingcat

#define A(a)!i&&!r--?puts(#a),++a,--n:0;
b,s,f,h,i,r;p(n){srand(time(0));for(i=n;i--;){for(n=1;n;){r=rand()&3;b>2^!A(b)s+f>1^!A(s)!A(f)A(h)}}}

Pruébalo en línea

rtpax
fuente
Sugerir en &nlugar detime(0)
ceilingcat