Spock!

Descripción del contenido de la página

Versión plurilingüe del juego Piedra, papel, tijera, lagarto, Spock escrito en Forth, para un jugador.

Etiquetas:

Este programa es una recreación del juego Piedra, papel, tijera, lagarto, Spock (que a su vez es una ampliación del clásico Piedra, papel, tijeras).

Tanto la interfaz como los textos del juego están escritos en varias lenguas (castellano, esperanto, inglés usamericano e inglés británico) y se puede cambiar la lengua durante el juego. De momento los dos dialectos de inglés comparten aún los mismos textos... salvo una sola palabra.

Objetivo

El primer objetivo de este proyecto fue probar el lenguage de programación 4tH, un pariente muy cercano de Forth que sin embargo internamente es muy diferente de Forth. Sin embargo escribir el programa al mismo tiempo que me familiarizaba con 4tH no resultó práctico. Decidí escribir el juego para Gforth y hacer posteriormente una adaptación a 4tH: Spock IV.

Futuras mejoras

Hay tres características interesantes que se han quedado en el tintero:

Quizá sean implementadas en una futura versión del programa.

Código fuente

\ spock.fs

\ "Spock!"
\ Version B-00-20120615
\ (http://programandala.net/en.program.spock)

\ A multilingual implementation of
\ "Rock, paper, scissors, lizard, Spock"
\ in the Forth programming language
\ with Gforth (http://www.jwdt.com/~paysan/gforth.html).

\ Based on the Spanish version of
\ "Rock, paper, scissors"
\ by the same author:
\ http://programandala.net/es.programa.piedra_papel_tijeras

\ Copyright (C) 2012 Marcos Cruz (programandala.net)

\ Spock! is free software; you can redistribute it and/or
\ modify it under the terms of the GNU General Public
\ License as published by the Free Software Foundation; either
\ version 2 of the License, or (at your option) any later version.

\ Spock! is distributed in the hope that it will be useful,
\ but WITHOUT ANY WARRANTY; without even the implied warranty of
\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
\ General Public License for more details.

\ You should have received a copy of the GNU General Public License
\ along with this program; if not, see http://www.gnu.org/licenses .

\ **************************************************************
\ Development History

(

2012-03-30 Version A-00. Start. Code for 4tH and Gforth.
2012-04-01 Version A-01. Gforth only.
2012-04-02 Version A-02. First working version. Spanish interface only.
2012-04-07 Version A-03. Multilingual interface.
2012-04-08 Version A-04. Language selection.
2012-04-10 Version B-00. General revision of the code.
2012-04-14 Simpler method for showing the winner.
2012-04-15 'init_once' moved to 'main'. A bit simpler game loop. 'about' completed with GPL.
2012-04-16 Changed the name format of all multilingual strings. Pauses modified in 'about'.
2012-06-15 Some little internal changes.

More detailed history [in Spanish]:
http://es.programa.spock.historial

)

\ **************************************************************
\ To-do

(

* Random, more elaborated and longer texts,
  instead of fixed compiled strings.
* Different explanation for every tie combination.
* Text interface [no menus], like text adventures.
* Add "also" or "too" to the shown computer option,
  after a tie result.

)

\ **************************************************************
\ Stack notation

(

a      = memory address
a u    = start and length of a memory region, usually a string
c      = character
f      = 0: false; other: true
ff     = 0: false; -1: true
max    = signed 32-bit number
min    = signed 32-bit number
n      = signed 32-bit number
u      = unsigned 32-bit number
x      = undefined element
..     = range
"name" = space delimited text in the input stream
"text" = text in the input stream

)

\ **************************************************************
\ Requirements and stock words

s" random.fs" required  \ Gforth's 'random' and 'seed'.

: randomize  time&date 2drop 2drop * seed !  ;
: enum  (  n "name" -- n+1 )  dup constant 1+  ;
: th  ( a1 n  -- a2 )  cells +  ;
: at  ( n a1 -- a2 )  swap th  ;
: h"  ( "text<quotes>" -- a )  here ,"  ;  immediate \ "
: ++  ( a -- )  1 swap +!  ;
: ,s  ( x1..xu u -- )  0  do  ,  loop  ;
: s@  ( a1 -- a2 u2 )  @ count  ;
: between  ( n min max -- ff )  1+ within  ;

\ **************************************************************
\ Languages

0
enum spanish  \ First language defined (last one in multilingual tables)
enum esperanto
enum american_english
enum british_english  \ Last language defined (first one in multilingual tables)
constant languages  \ Number of languages.
variable language  \ Current language.

: language+  ( a1 -- a2 )
  \ a1 = Address of an element in a multilingual table.
  \ a2 = Actual address of the element in the current language.
  language @ th
  ;
: language_string  ( a1 -- a2 u2 )
  \ a1 = Address of a table of multilingual strings.
  \ a2 u2 = String in the current language.
  language+ s@
  ;
: languages,  ( x..x' -- )
  \ Compile elements from the stack, one for every language.
  languages ,s
  ;

\ Menu option to change the current language
\ (the strings or any kind of data to be compiled in a language table
\ must be always in reverse order of the languages' definition):
h" Not in American English."
h" Not in British English."
h" Ne en Esperanto."
h" No en castellano."
create (not_in_language$)  languages,
: not_in_language$  ( -- a u )  (not_in_language$) language_string  ;
: .not_in_language  not_in_language$ type  ;

char + constant language_key  \ Key that changes the current language.
: next_language  ( u1 -- u2 )  1+ dup languages < and  ;
: language++  language @ next_language language !  ;

\ **************************************************************
\ Pauses and keyboard

: seconds  ( u -- )  1000 * ms  ;
: wait  key drop  ;
: .prompt  cr cr ." > "  ;

h" Press any key to continue."  \ British English.
dup \ American English.
h" Premu iun klavon por plui."  \ Esperanto.
h" Pulsa cualquier tecla para continuar."  \ Spanish.
create (press_key$)  languages ,s
: press_key$  ( -- a u )  (press_key$)  language_string  ;
: .press_key  press_key$ cr type  ;
: press_key  .press_key .prompt wait  ;

\ **************************************************************
\ About

create (title$) ," Spock!"
: title$  ( -- a u )  (title$) count  ;
: .title  title$ type cr cr  ;

h" Rock, paper, scissors, lizard, Spock!"  \ British English.
dup  \ American English.
h" Ŝtono, papero, tondilo, lacerto, Spock!"  \ Esperanto.
h" ¡Piedra, papel, tijera, lagarto, Spock!"  \ Spanish.
create (long_title$)  languages,
: long_title$  ( -- a u )  (long_title$) language_string  ;
: .long_title  long_title$ type cr cr  ;

: copyright
  ." Copyright (C) 2012 Marcos Cruz (programandala.net)" cr cr
  ;
: the_license
  ." Spock! is free software; you can redistribute it and/or" cr
  ." modify it under the terms of the GNU General Public" cr
  ." License as published by the Free Software Foundation; either" cr
  ." version 2 of the License, or (at your option) any later version." cr
  ;
: about  copyright 1 seconds the_license 3 seconds  ;
: splash  page .title about press_key  ;

\ **************************************************************
\ Commands

0
enum rock  \ First command.
enum paper
enum scissors
enum lizard
enum spock  \ Last command.
constant commands  \ Number of commands.

\ Compile the command names, from the last command to the first one,
\ in every language (from the last language to the first one):
h" Spock" dup dup dup  \ Last command.
h" lizard" dup h" lacerto" h" lagarto"
h" scissors" dup h" tondilo" h" tijera"
h" paper" dup h" papero" h" papel"
h" rock" dup h" ŝtono" h" piedra"  \ First command.
create names  languages commands * ,s
: command_name  ( u1 -- a2 u2 )
  \ u1 = Command number.
  \ a2 u2 = Command name.
  languages * language @ + names at s@
  ;
: .command_name  command_name type  ;

\ **************************************************************
\ Score

10 constant max_score
variable your_score
variable my_score

h" Your score" dup
h" Viaj poentoj"
h" Tu puntuación"
create (your_score$)  languages,
: your_score$  ( -- a u )  (your_score$) language_string  ;

h" My score" dup
h" Miaj poentoj"
h" Mi puntuación"
create (my_score$)  languages,
: my_score$  ( -- a u )  (my_score$) language_string  ;

: .score  ( a u -- )  type s" : " type  ;
: .your_score  your_score$ .score your_score ?  ;
: .my_score  my_score$ .score my_score ?  ;
: .scores  cr cr .your_score cr .my_score cr  ;
: max?  ( a -- ff )  @ max_score =  ;
: you_win_game?  ( -- ff )  your_score max?  ;
: i_win_game?  ( -- ff )  my_score max?  ;

\ **************************************************************
\ Command selection

variable your_command
variable my_command
: choices  ( -- u1 u2 )  my_command @  your_command @  ;
char 0 constant "0"
: digit  ( u -- c )  "0" +  ;
: option  ( c -- u )  "0" -  ;
: command_key?  ( c -- ff )  "0" commands 1- digit between  ;
: language_key?  ( c -- ff )  language_key = dup  if  language++  then  ;
: valid_key?  ( c -- ff )  dup language_key? swap command_key? or  ;
: your_key  ( -- c )  0  begin  drop key dup valid_key?  until  ;
variable accusative  \ Show the Esperanto commands in accusative?
: esperanto?  ( -- ff )  language @ esperanto =  ;
: accusative?  ( -- ff )  esperanto? accusative @ and  ;
: (.accusative)  ( u -- )  spock =  if  ." -on"  else  ." n"  then  ;
: .accusative  ( u -- )  accusative?  if  (.accusative)  else  drop  then  ;
: .choice  ( u -- )  dup .command_name .accusative [char] . emit  ;
: .command_option  ( u -- )  dup cr . ." = " .choice  ;
: .command_options  commands 0  do  i .command_option  loop  ;
: .language_option  cr cr language_key emit ."  = " .not_in_language  ;
: .options  cr accusative off .command_options .language_option  ;

h" Choose:" dup
h" Elektu:"
h" Elige:"
create (choose$)  languages,
: choose$  ( -- a u )  (choose$) language_string  ;
: .choose  choose$ type  ;

: menu  page .long_title .choose .options .prompt  ;
: your_choice  ( -- u)
  0  begin  drop menu your_key
  dup command_key?  until  option
  ;
: my_choice  ( -- u )  commands random  ;

h" You choosed" dup
h" Vi elektis"
h" Has sacado"
create (you_choosed$)  languages,
: you_choosed$  ( -- a u )  (you_choosed$) language_string  ;
: .you_choosed  you_choosed$ type space  ;

h" I choosed" dup
h" Mi elektis"
h" Yo he sacado"
create (i_choosed$)  languages,
: i_choosed$  ( -- a u )  (i_choosed$) language_string  ;
: .i_choosed  i_choosed$ type space  ;

: .your_choice  .you_choosed your_command @ accusative on .choice  ;
: .my_choice  .i_choosed my_command @ .choice  ;
: .choices  .your_choice cr .my_choice  ;

\ **************************************************************
\ Versus

: command_combinations  ( -- u )  commands dup *  ;
create winners  command_combinations allot
winners command_combinations erase
: >winner  ( u1 u2 -- a )
  \ Point to an element of the 'winners' table.
  \ u1 = Computer's command.
  \ u2 = Human's command.
  commands * + winners +
  ;
: winner  ( u1 u2 -- )
  \ Mark a winner combination of commands (the computer wins).
  \ u1 = Computer's command.
  \ u2 = Human's command.
  >winner true swap c!
  ;
: winner?  ( u1 u2 -- f )
  \ u1 = Computer's command.
  \ u2 = Human's command.
  >winner c@
  ;

h" I win." dup
h" Mi venkis."
h" Yo gano."
create (i_win$)  languages,
: i_win$  ( -- a u )  (i_win$) language_string  ;
h" You win." dup
h" Vi venkis."
h" Tú ganas."
create (you_win$)  languages,
: you_win$  ( -- a u )  (you_win$) language_string  ;
: i_win_round  i_win$ type  my_score ++  ;
: you_win_round  you_win$ type  your_score ++  ;
: (versus)  ( u1 u2 | u2 u1 -- u3 )
  \ u1 u2 = Commands.
  \ u3 = Identifier of the commands combination.
  2dup min commands * >r max r> + 1+
  ;
: versus  ( u1 u2 | u2 u1 | u1 u1 -- u3 )
  \ u1 u2 = Commands.
  \ u3 = Identifier of the commands combination.
  2dup = if  2drop 0  else  (versus)  then
  ;
commands 1- dup 1- versus constant max_versus

create explanations  max_versus languages * cells allot
variable >explanations  \ Pointer in the 'explanations' table.
: explanations:  ( u1 u2 -- )
  \ u1 u2 = Commands the following explanations definitions refers to.
  versus >explanations !
  ;
: tie_explanations:  false dup explanations:  ;
: winner_explanations:  ( u1 u2 -- )
  \ u1 u2 = Commands the following explanations definitions refers to.
  2dup winner  explanations:
  ;
: explanation!  ( a1 u2 -- )
  \ a1 = Address of the explanation string.
  \ u2 = Language of the explanation string.
  >explanations @ languages * + explanations at !
  ;
: english_explanations!  ( a -- )
  \ a = Address of the explanation string in both dialects of English.
  dup american_english explanation! british_english explanation!
  ;
: explanation  ( u -- a1 u1 )
  \ u = Identifier of a commands combination.
  \ a1 u1 = Explanation in the current language.
  languages * language @ + explanations at s@
  ;
: .explanation  ( u -- )
  \ u = Identifier of a commands combination.
  explanation type
  ;

tie_explanations:
h" Empate." spanish explanation!
h" Remiso." esperanto explanation!
h" Tie." american_english explanation!
h" Draw." british_english explanation!
rock scissors winner_explanations:
h" La piedra rompe la tijera." spanish explanation!
h" La ŝtono rompas la tondilon." esperanto explanation!
h" The rock crushes the scissors." english_explanations!
paper rock winner_explanations:
h" El papel envuelve la piedra." spanish explanation!
h" La papero envolvas la ŝtonon." esperanto explanation!
h" The paper covers the rock." english_explanations!
scissors paper winner_explanations:
h" La tijera corta el papel." spanish explanation!
h" La tondilo tondas la paperon." esperanto explanation!
h" The scissors cut the paper." english_explanations!
lizard spock winner_explanations:
h" El lagarto envenena a Spock." spanish explanation!
h" La lacerto venenas Spock-on." esperanto explanation!
h" The lizard poisons Spock." english_explanations!
rock lizard winner_explanations:
h" La piedra aplasta el lagarto." spanish explanation!
h" La ŝtono premplatigas la lacerton." esperanto explanation!
h" The rock crushes the lizard." english_explanations!
scissors lizard winner_explanations:
h" La tijera decapita el lagarto." spanish explanation!
h" La tondilo senkapigas la lacerton." esperanto explanation!
h" The scissors decapitate the lizard." english_explanations!
lizard paper winner_explanations:
h" El lagarto come el papel." spanish explanation!
h" La lacerto manĝas la paperon." esperanto explanation!
h" The lizard eats the paper." english_explanations!
spock rock winner_explanations:
h" Spock vaporiza la piedra." spanish explanation!
h" Spock vaporigas la ŝtonon." esperanto explanation!
h" Spock vaporizes the rock." english_explanations!
paper spock winner_explanations:
h" El papel desautoriza a Spock." spanish explanation!
h" La papero senrajtigas Spock-on." esperanto explanation!
h" The paper disproves Spock." english_explanations!
spock scissors winner_explanations:
h" Spock rompe la tijera." spanish explanation!
h" Spock rompas la tondilon." esperanto explanation!
h" Spock smashes the scissors." english_explanations!

: i_win_round?  ( -- f )  choices winner?  ;
: (.round_winner)
  i_win_round?  if  i_win_round  else  you_win_round  then
  ;
: tie?  ( -- ff )  choices =  ;
: .round_winner  tie? 0=  if  (.round_winner)  then  ;
: .result  choices versus .explanation space .round_winner  ;
: .results  page .choices cr cr .result .scores press_key  ;

\ **************************************************************
\ The end

false  [if]  \ Old method.

  \ This method is not suitable for languages that change the verb form
  \ in the needed sentences. In order to make it easier to add new
  \ languages, a different method is used.

  h" You " dup h" Vi " h" Has "
  create (you_$)  languages,
  : you_$  ( -- a u )  (you_$) language_string  ;

  h" I " dup h" Mi " h" He "
  create (i_$)  languages,
  : i_$  ( -- a u )  (i_$) language_string  ;

  h" won the game." dup h" venkis la ludon." h" ganado la partida."
  create (won_what$)  languages,
  : won_what$  ( -- a u )  (won_what$) language_string  ;
  : .won_what  won_what$ type  ;

  : winner_who$  ( -- a u )  you_win_game?  if  you_$  else  i_$  then  ;
  : .winner_who  winner_who$ type  ;
  : .game_winner  .winner_who .won_what  ;

[else]  \ New method, with whole sentences.

  h" I won the game." dup
  h" Mi venkis la ludon."
  h" He ganado la partida."
  create (i_won_game$) languages,
  : i_won_game$  ( -- a u)  (i_won_game$) language_string  ;

  h" You won the game." dup
  h" Vi venkis la ludon."
  h" Has ganado la partida."
  create (you_won_game$) languages,
  : you_won_game$  ( -- a u)  (you_won_game$) language_string  ;

  : game_winner$  ( -- a u )
    you_win_game?  if  you_won_game$  else  i_won_game$  then
    ;
  : .game_winner  game_winner$ type  ;

[then]

: game_over  page .game_winner .scores  ;
: game_over?  ( -- ff )  you_win_game? i_win_game? or  ;

h" Press space to play again; any other key to finish." dup
h" Premu spacon por reludi; alian klavon por fini."
h" Pulsa espacio para jugar de nuevo; otra tecla para terminar."
create (press_space$)  languages,
: press_space$  ( -- a u )  (press_space$) language_string  ;
: .press_space  cr press_space$ type  ;

h" Bye!" dup
h" Adiaŭ!"
h" ¡Adiós!"
create (good_bye$) languages,
: good_bye$  ( -- a u )  (good_bye$) language_string  ;
: .good_bye  good_bye$ type cr  ;

: enough?  ( -- ff )  .press_space .prompt key bl <>  ;
: final_pause  2 seconds  ;
: farewell  page .good_bye final_pause page bye  ;

\ **************************************************************
\ Init

: init_game  your_score off  my_score off  ;
: init_once  randomize  american_english language !  ;

\ **************************************************************
\ Game

: i_play  my_choice my_command !  ;
: you_play  your_choice your_command !  ;
: turn  i_play you_play .results  ;
: game  init_game  begin  turn game_over?  until  game_over  ;
: main  init_once splash  begin  game enough?  until  farewell  ;

main


\ **************************************************************
\ Debugging tools

false [if]

: (.)  ( n -- )  dup ." (" 0 .r ." )"  ;
: check_explanations
  page
  languages 0 do  i language !
    commands 0 do
      commands 0 do
        i dup .command_name (.)
        ."  vs "
        j dup .command_name (.) ."  = "
        i j versus dup . ." -> "
        .explanation cr
      loop  cr press_key page
    loop
  loop
  ;

[then]

Descargas

Instrucciones

En primer lugar instala Gforth en el sistema. Después abre una terminal y, desde el directorio en que esté el fichero del juego, arranca Gforth así: gforth spock.fs.

Otra opción es arrancar Gforth y dar cualquiera de los siguientes comandos en Forth (hacen exactamente lo mismo):

s" spock.fs" included

O bien:

include spock.fs

Páginas relacionadas

Historial de desarrollo de Spock!
Historial de desarrollo de Spock!, versión plurilingüe del juego Piedra, papel, tijera, lagarto, Spock escrito en Forth, para un jugador.
Piedra, papel, tijeras
Juego "Piedra, papel, tijeras" escrito en Forth, para jugar contra la máquina.
Spock IV
Versión plurilingüe del juego Piedra, papel, tijera, lagarto, Spock, escrita en 4tH, para un jugador.