Identificación automática de precios de rollos en Nethack

21

OH DIOSES NO !! ¡No puedes dejarnos aquí con Doorknob! ¡Será nethack en todas partes! - Hace 1 día por Geobits

Bueno, no podría decepcionar ...

Introducción

(puede omitir esta sección si no le importa la exposición y / o si tiene el Síndrome de Explosión de Tabulación )

Una de las mecánicas características de Nethack (y Rogue, y juegos similares en el mismo género roguelike) es su sistema de identificación . Al comienzo del juego, solo los elementos de tu inventario inicial están "formalmente identificados". La gran mayoría de otros objetos comienzan siendo desconocidos; por ejemplo, un "escudo de reflexión" se mostrará inicialmente como un "escudo plateado pulido" antes de ser identificado.

Un "escudo de plata pulido" solo puede ser un escudo de reflexión , pero esto tiene consecuencias interesantes en otros dos casos.

  1. Algunos artículos son diferentes entre sí, pero tienen la misma "apariencia". Por ejemplo, si encuentra una " piedra gris ", podría ser una de cuatro cosas: una piedra de pedernal (inútil), una piedra de toque (puede ser útil), una piedra de carga (que lo gravará gravemente porque pesa una tonelada y usted no se puede soltar), o una suerte (extremadamente útil, casi necesaria para ganar el juego).

  2. Muchos artículos (pergaminos, varitas, anillos, libros de hechizos, algunas armaduras, etc.) tienen una apariencia aleatoria. Lo que esto significa es que hay una lista establecida de posibles apariencias, digamos, que las pociones podrían tener; por ejemplo, [ poción dorada , poción swirly , poción con gas , poción rojo púrpura , etc.]. Estas apariencias se asignan aleatoriamente a lo que realmente son ( poción de curación , poción de parálisis , poción de ver invisible , poción de polimorfo , etc.).

    Lo que significa que un amuleto hexagonal podría salvarte la vida en un juego (amuleto para salvar vidas) y estrangularte hasta el siguiente (amuleto de estrangulamiento) .

Naturalmente, esto hace que la identificación de elementos sea una parte crítica del juego. Los artículos pueden ser "identificados formalmente", lo que significa que se mostrarán inequívocamente como un artículo determinado (por ejemplo, todas las varitas con joyas que encuentres aparecerán como varitas de crear monstruo ); Esto se hace principalmente a través de pergaminos o libros de hechizos de identidad. Sin embargo, normalmente son escasos, lo que nos lleva a ...

Identificación informal Esto significa que está bastante seguro (o seguro) de que cierto elemento no identificado es de cierto tipo (o que solo puede ser uno de varios tipos), pero aún no lo ha identificado "formalmente". Esto se puede hacer a través de varios métodos: prueba de grabado para varitas, prueba de hundimiento para anillos o, el método más común ...

cuadro de ID de precio de desplazamiento

... identificación de precios ! De eso se trata este desafío.

En pocas palabras, hay tiendas ubicadas en Dungeons of Doom (sí, los comerciantes pensaron que sería una buena idea establecer una tienda en una mazmorra subterránea; no preguntes por qué). En estas tiendas, puede comprar y vender los diversos artículos que encuentre durante sus viajes. Al comprar o vender un artículo, el comerciante primero le dirá cuánto le vendería / se lo compraría a usted. Dado que se garantiza que ciertos artículos tienen precios específicos , puede usar esto para identificar informalmente un cierto tipo de artículo.

Algunos elementos, como el pergamino de luz , son los únicos elementos que cuestan una cierta cantidad, lo que le permite identificarlos sin ambigüedades; sin embargo, la mayoría de los artículos comparten un grupo de precios con otros artículos de la misma clase, lo que solo le permite reducir las posibilidades (lo que sigue siendo útil). Sin embargo, los precios de compra / venta de un artículo se ven afectados por una serie de variables (como la estadística de Carisma ). De ahí la tabla de arriba.

¿Puedes decir que me gusta Nethack?

Entrada

La entrada se proporcionará como un juego de Nethack (vainilla, 3.4.3) que se está jugando actualmente:

"For you, most gracious sir; only 177 for this scroll labeled VERR YED HORRE."
--More--

        ------------
        |          .                                        ---------
        |          |                         ----------     |    ^  |
        |          .##       ################.        +#   #.       .#
        |          | #                       |       _|#   #---------#
        |          | ###                   ##.<       |#   ####      #
        |          .#########################----------#      #      #
        ------------   ###     #         ############# #      #      #
           #             #  -----------  #             #      #   ####
         ###             ###|         |###             #      #   #----------
         #                 #.         |#             ### #    #   #|.???????|
        ##                  |         |#             #--------#   #|.??@????|
    ----.----###############.         |#             #|      |#   #-@???????|
    |.......+#              |         |#             #.      |#    ----------
    |.......|               |         .#              |      |#
    |......>|               -----------               |      +#
    ---------                                         --------


Wizard the Evoker         St:12 Dx:14 Co:11 In:16 Wi:12 Ch:10  Chaotic
Dlvl:2  $:0  HP:11(11) Pw:0(8) AC:9  Exp:1 T:11

Esto significa que se garantiza que tiene varias propiedades:

  • Será siempre ser de 24 líneas largas.

  • Cada línea siempre tendrá 80 caracteres o menos de longitud.

  • La segunda a última línea consistirá en los siguientes " tokens ': nombre y el título del jugador (en forma de' foo el bar "), la lista de atributos (separados por un solo espacio), y la alineación del jugador ( Legal, neutral o caótico). Cada ficha estará separada por un número variable de espacios. 1

  • La lista de atributos siempre estará St:* Dx:* Co:* In:* Wi:* Ch:*, donde un *personaje representa un número entero de 3 a 25. 2 (El punto de interés aquí es la última estadística, Carisma, que necesitas para calcular los precios).

  • La primera línea siempre consistirá en un mensaje relacionado con la tienda (específicamente, el mensaje que se muestra cuando compra o vende un artículo). Además, se garantiza que este elemento sea un desplazamiento único, no identificado y sin nombre. Para comprar un artículo, esto es:

    "For you, {TITLE}; only {PRICE} for this scroll labeled {LABEL}."--More--
    

    y para vender es:

    {SHK} offers {PRICE} gold pieces for your scroll labeled {LABEL}.  Sell it? [ynaq] (y)
    

    donde las "variables" enumeradas en {curly braces}son las siguientes:

    • {TITLE}siempre es uno de " bueno ", " honrado ", " muy amable " o " estimado ", concatenado con " dama " o " señor ".

    • {PRICE} Siempre es un número entero.

    • {LABEL}siempre será uno de los siguientes ( fuente ):

      ZELGO MER       JUYED AWK YACC  NR 9             XIXAXA XOXAXA XUXAXA
      PRATYAVAYAH     DAIYEN FOOELS   LEP GEX VEN ZEA  PRIRUTSENIE
      ELBIB YLOH      VERR YED HORRE  VENZAR BORGAVVE  THARR
      YUM YUM         KERNOD WEL      ELAM EBOW        DUAM XNAHT
      ANDOVA BEGARIN  KIRJE           VE FORBRYDERNE   HACKEM MUCHE
      VELOX NEB       FOOBIE BLETCH   TEMOV            GARVEN DEH
      READ ME
      
    • {SHK}siempre será uno de los siguientes ( fuente ):

      Skibbereen      Ballingeary     Inishbofin      Annootok        Abitibi
      Kanturk         Kilgarvan       Kesh            Upernavik       Maganasipi
      Rath Luirc      Cahersiveen     Hebiwerie       Angmagssalik    Akureyri
      Ennistymon      Glenbeigh       Possogroenoe    Aklavik         Kopasker
      Lahinch         Kilmihil        Asidonhopo      Inuvik          Budereyri
      Kinnegad        Kiltamagh       Manlobbi        Tuktoyaktuk     Akranes
      Lugnaquillia    Droichead Atha  Adjama          Chicoutimi      Bordeyri
      Enniscorthy     Inniscrone      Pakka Pakka     Ouiatchouane    Holmavik
      Gweebarra       Clonegal        Kabalebo        Chibougamau     Lucrezia
      Kittamagh       Lisnaskea       Wonotobo        Matagami        Dirk
      Nenagh          Culdaff         Akalapi         Kipawa
      Sneem           Dunfanaghy      Sipaliwini      Kinojevis
      

    Este mensaje puede dividirse en otra línea (pero nunca ocupará más de 2 líneas). 3

  • Aparte de las primeras líneas, todas las apuestas están apagadas en cuanto al aspecto del resto de la pantalla. Nethack usa la mayoría del juego de caracteres ASCII . Lo único que puede asumir con seguridad es que la entrada será puramente ASCII (sin embargo, esto probablemente no importará porque de todos modos puede descartar las líneas 3-22).

Si la entrada se toma como un argumento de función, se dará exactamente como se muestra en el ejemplo anterior (nueva línea separada). Si ingresa a través de STDIN, se dará como 24 líneas consecutivas de entrada (nuevamente, como se muestra arriba). Puede elegir si desea que la entrada tenga una nueva línea final o no. Se garantiza que la entrada no tendrá espacios finales.

Salida

La salida debe proporcionarse como lo que debería ser #nameel desplazamiento que acabo de identificar. El sistema de nombres que uso (y que he visto usar a otros) es:

  • Si el pergamino se identifica inequívocamente como un cierto pergamino (identificar, encender, encantar arma), #namees eso. Este es el caso de los pergaminos de los siguientes precios base (verás cómo calcular el precio base a continuación): 20 -> identificar, 50 -> ligero, 60 -> encantar arma.

  • De lo contrario, tome las primeras tres letras de la apariencia del pergamino, o la primera palabra si tiene menos de 3 caracteres. Por ejemplo, se ZELGO MERconvierte ZEL, se VE FORBRYDERNEconvierte VE, etc. Concatene con esto (un espacio, y luego) el precio base del pergamino. Por ejemplo, ELB 300.

  • Si el precio base puede ser una de dos posibilidades, generalmente trato de comprar o vender el artículo hasta que obtengo un precio ofrecido que lo coloca sin ambigüedad en un cierto rango de precios. Sin embargo, no puede hacer eso en este desafío, así que simplemente separe los dos precios base posibles con una barra inclinada ( /). Por ejemplo, HAC 60/80.

Aquí está la fórmula para convertir el precio base de un artículo en el precio que le ofrecen comprarlo:

  • comenzar con el precio base del artículo

  • posibilidad de un posible "recargo no identificado" del 33%, calculado mediante price += price / 3

  • otra posibilidad de un "margen de beneficio" del 33% (en realidad, no es una posibilidad aleatoria, pero a los efectos de este desafío lo es), calculada de la misma manera

  • un modificador de carisma, que se aplica de la siguiente manera:

    Ch    3-5     6-7       8-10      11-15  16-17     18        19-25
    Mod   +100%   +50%      +33%      +0%    -25%      -33%      -50%
    Code  p *= 2  p += p/2  p += p/3  ---    p -= p/4  p -= p/3  p /= 2
    

Y aquí está la fórmula del precio base -> precio de venta:

  • comenzar con el precio base del artículo

  • divida esto entre 2 o 3 ("normal" o "marcado de succión" respectivamente; nuevamente, no al azar, pero es para los propósitos de este desafío)

  • posibilidad de una reducción adicional del 25% 4 , calculada medianteprice -= price / 4

La división es la división entera, lo que significa que el resultado en cada paso se redondea hacia abajo. (Fuente: wiki , y un poco de excavación de código fuente. Invertir estas fórmulas es su trabajo).

Finalmente, aquí hay un gráfico ASCII práctico que muestra los posibles precios de compra (agrupados por la estadística de Carisma) y los precios de venta de un pergamino con un cierto precio base:

Base  Ch<6          6-7          8-10         11-15        16-17        18           19-25        Sell
20    40/52/68      30/39/51     26/34/45     20/26/34     15/20/26     14/18/23     10/13/17     5/6/8/10
50    100/132/176   75/99/132    66/88/117    50/66/88     38/50/66     34/44/59     25/33/44     12/16/19/25
60    120/160/212   90/120/159   80/106/141   60/80/106    45/60/80     40/54/71     30/40/53     15/20/23/30
80    160/212/282   120/159/211  106/141/188  80/106/141   60/80/106    54/71/94     40/53/70     20/26/30/40
100   200/266/354   150/199/265  133/177/236  100/133/177  75/100/133   67/89/118    50/66/88     25/33/38/50
200   400/532/708   300/399/531  266/354/472  200/266/354  150/200/266  134/178/236  100/133/177  50/66/75/100
300   600/800/1066  450/600/799  400/533/710  300/400/533  225/300/400  200/267/356  150/200/266  75/100/113/150

(Esto es idéntico al gráfico del wiki, excepto que enumera todos los precios de venta posibles, mientras que el gráfico del wiki no incluye dos de los cuatro precios de venta posibles. No, no hice ese gráfico manualmente; generado con este script Ruby .)

Casos de prueba

Entrada:

"For you, honored sir; only 80 for this scroll labeled LEP GEX VEN ZEA."
--More--                   #                                          #
                      ----------------                              -----
                      |              |              ------------####+   |
      -----           |              -##############+          .#   |   |
      |   .###########|           >  |#           # |          |  ##.   |
      |   |          #------------.---#           ##.          |  # -----
      -+---          ##################             ----.-------###    #
       ####                     ###                     #       #      #
          #                     #                       #     ###      ###
          ###                 ###                       #     #          #
            #                 #                         #   ###     -----|--
       -----.---            ###                     ----+---#       |...@..|
       |       |            #                       |      |#       |???+??|
       |  <    .#          ##                     ##+      |        |+?????|
       |       |#    ------.-------                 |      |        |??]?@?|
       ---------###  |            |                 |      |        --------
            #     #  |            |                 --------
                  ###|            |                       #
                    #+            |
                     --------------

Wizard the Evoker         St:11 Dx:15 Co:9 In:20 Wi:9 Ch:11  Chaotic
Dlvl:7  $:0  HP:11(11) Pw:1(8) AC:9  Exp:1

Salida: LEP 60/80


Entrada:

"For you, most gracious sir; only 80 for this scroll labeled DAIYEN FOOELS."
--More--                                                             #
                ------------                         -----      -------
 -----          |          |                         |   |      |     |
 |!)%|          |          |     ---------------     |   |     #-     |
 |*[@|          |          .#####|   <         |#####.   |   ###|     |
 |?(?|          ---------.--    #+             |#    |   |   #  |     |
 |[!(|                  ##       |             |#    |   +#### #.     .#
 |.@.|         ##################.             +#    ---.-     #|     |#
 ---|-                ###        ---------------#       ##     #-------#
    ##                #                    ######        #     #       #
     #              ###                         #        #     #       #
     ##             #                           #        #     #       #
  ------        #####                           #        #     #       #
  |    |       -.----                           #        #     #       #
  |    .#####  |^   |                        ####        #     #       #
  |    |    #  |    |          ----          #-----------.---- #       #------
  |    |    ###|    |          |  |          #.      >       | #       #|    |
  ------      #.    |          |  |           |              .##       #|    |
               |    |          ----           |              |         #.    |
               ------                         ----------------          ------

Wizard the Evoker         St:11 Dx:14 Co:16 In:15 Wi:10 Ch:9  Chaotic
Dlvl:6  $:0  HP:11(11) Pw:9(9) AC:9  Exp:1

Salida: enchant weapon


Entrada:

Aklavik offers 113 gold pieces for your scroll labeled GARVEN DEH.  Sell it?
[ynaq] (y)

     -----      ------                                 ---------      -------
     |   |      |    |                         #     ##.       |      |.?)%/|
     |   |    ##.    |                       -----   # |       |      |.@!=*|
     |<  |    # |    |            #        ##.   .#####+    >  |#    #-.*?@[|
     |   .##### |    |      ------------   # | { |#    |^      |#    #|.=%)+|
     ---.-      |    |      |          .#### |   |#    ---------##   #-------
       ##       -.----     #.          |     |   |#          # ###   #
       #         ########  #|          .##   |   |#            ##    #
     ###                #  #------------ #   -----#          ####    #
     #                  #######          ##########################  #
     #                    #   #                            ###----.--#
     #                    ### #                            # #|     |#
   --.----       ########################################### #.     |#
   |     |       #----------.-#                               |     |#
   |     |       #|          |#                               -------
   |     |       #|          .#
   |     |########|          |
   -------        ------------
                   #    #
Wizard the Evoker         St:9 Dx:14 Co:11 In:19 Wi:10 Ch:12  Chaotic
Dlvl:4  $:0  HP:11(11) Pw:5(9) AC:9  Exp:1 Satiated

Salida: GAR 300


Entrada:

"For you, good lady; only 67 for this scroll labeled VE FORBRYDERNE."--More--

                                                 -------
                                               ##|     |
  ------------                                 # |     |
  |+[!/!?%[?)|                               ### |     |          --------
  |[)(!/+]?!@|               #               #   |     |        ##+      |
  |.......@..|            --------------   ###   | <   | ##       |      |
  --------+---           #|            |   #     |     |  #       |    > |
          #            ###|            .####     --.----  ###    #-      |
          #            ###.            |           #        #  ###|      |
          #          #### ---.----------           #        ######.      |
          #          ####    ##                    #         ###  --------
          #        ####       #                    #         #
          #        ####       ########################     ###
        ###      ####                            ----+---- #
        #   #    ####                            |       .##
    ----.------####                              |  ^    |
    |         +####                              |    >  |
    |         |                                  | ^     |
    -----------                                  ---------

Wizard the Evoker         St:18 Dx:18 Co:16 In:20 Wi:20 Ch:18  Chaotic
Dlvl:4  $:150 HP:11(11) Pw:5(7) AC:9  Exp:1

Salida: VE 100


Entrada:

Droichead Atha offers 5 gold pieces for your scroll labeled XIXAXA XOXAXA
XUXAXA.  Sell it? [ynaq] (y)
                                                ------------
                   -----                        |          .#
                   |   .### -----------        #.       {  |#
       -----       |   |  # |         |      ###|          |#
       |   .#     #.   |  # |         |      #  ---------+--#
       |   |    ###-|---    |         .##  ###          ##  #
       |   |    #   # #     |         | #  #            #   #
       |   -#####   #       |         | #### ############   #
       |>  | ##     #       ---------+-  ## -.----------    # ----------
       |   .####    ###             ## #####|          |    # |.*??/?)*|
       -----   #      #             #  #    |          |    # |@*)%!)]%|
               ###    ###         ######    |          |    # |.=)!%*!!|
                 #      #         #  #      |          |    ##+@*[%)(%?|
                 #####################      |          |      |.]?*?)%%|
                    -----+---.----##########.          |      |.%)%!!!%|
                    |            +##        ------------      ----------
                    |    <       |                  #
                    |            |
                    --------------

Wizard the Digger          St:11 Dx:9 Co:14 In:6 Wi:6 Ch:9  Lawful
Dlvl:3  $:0  HP:15(15) Pw:0(1) AC:9  Exp:1

Salida: identify

(Tuve que compilar manualmente Nethack con todos los demás nombres de comerciantes eliminados porque no pude encontrar un comerciante que tuviera un espacio en su nombre ...)

Reglas


1: esto no siempre es cierto durante un juego de Nethack, pero asumimos esto por simplicidad.

2: de nuevo, no siempre es cierto. La fuerza puede ser del 18/01 al 18 / **, pero no necesita manejar eso.

3: simplificaciones excesivas más brutas. Por ejemplo, es posible que un comerciante lo llame "escoria" o "criatura más famosa y sagrada", pero no tiene que manejar nada de eso.

4: que un jugador inteligente se mueve ofreciendo repetidamente vender el artículo hasta obtener el precio más alto.

Pomo de la puerta
fuente
15
¡Santo muro de texto!
orlp

Respuestas:

10

Javascript (ES6), 1610 724 601 612 419 405 bytes

a=>(b=a.match(/(\d+) (g|f).+d (\w{0,3})[\s\S]+h:(\d+)/m),c=+b[4],d=[20,50,60,80,100,200,300].map(e=>(f=e>>1,g=~~(e/3),[e,b[2]=='g'?[g-(g>>2),g,f-(f>>2),f]:[e,e+g,e+g+~~((e+g)/3)].map(h=>c<6?h*2:c<8?h+h>>1:c<11?h+~~(h/3):c<16?h:c<18?h-(h>>2):c<19?h-~~(h/3):h>>1)])).filter(i=>i[1].includes(+b[1])),j={20:'identify',50:'light',60:'enchant weapon'}[d[0][0]],k=b[3]+' '+d[0][0],d.length==1?j||k:k+'/'+d[1][0])

Gran muro de texto, cumple con gran muro de código.

Sin golf

inp => (
    extraction = inp.match(/(\d+) (g|f).+d (\w{0,3})[\s\S]+h:(\d+)/m),

    charisma = +extraction[4],

    allowed = [20, 50, 60, 80, 100, 200, 300].map(base => (
        tmp1 = base >> 1,
        tmp2 = ~~(base / 3),
        [
            base,
            extraction[2] == 'g' ?
                [tmp2 - (tmp2 >> 2), tmp2, tmp1 - (tmp1 >> 2), tmp1]
            :
                [base, base + tmp2, base + tmp2 + ~~((base + tmp2) / 3)].map(val =>
                    charisma < 6 ?
                        val * 2
                    : charisma < 8 ?
                        val + val >> 1
                    : charisma < 11 ?
                        val + ~~(val / 3)
                    : charisma < 16 ?
                        val
                    : charisma < 18 ?
                        val - (val >> 2)
                    : charisma < 19 ?
                        val - ~~(val / 3)
                    : val >> 1
            )
        ]
    )).filter(key => key[1].includes(+extraction[1])),

    name_ = {
        20: 'identify',
        50: 'light',
        60: 'enchant weapon'
    }[allowed[0][0]],

    tmp3 = extraction[3] + ' ' + allowed[0][0],

    allowed.length == 1 ?
        name_ || tmp3
    :
        tmp3 + '/' + allowed[1][0]
)

Ejemplo

usandfriends
fuente
1
Esa es una gran pila de guiones.
Fatalize
1
Woah, alguien finalmente respondió esto? Niza: D
Pomo de la puerta
@Doorknob He estado queriendo actualizar esto por un tiempo, finalmente lo conseguí.
usandfriends