Crie um teste de velocidade de digitação / medição de CPM

11

As regras

É hora de criar um teste de velocidade de digitação no seu idioma preferido!

1 . Você fornece um arquivo com um dicionário de sua escolha (todas as 'palavras' nele devem ser delimitadas por novas linhas). Conecte-o via stdinou forneça seu nome como argumento de linha de comando.

uma
capaz
sobre
acima
ausência
...

2 . Escolha 10 palavras aleatórias do arquivo (nenhuma duplicata deve ser permitida) e imprima-as da seguinte maneira:

-> direto
-> chão
-> próximo
-> cinco
...

3 . Comece a medir o tempo gasto a partir de agora!

4 . Deixe o usuário digitar todas as dez palavras o mais rápido possível (terminado com um retorno de carro). Imprima OKquando houver uma correspondência, imprima WRONGquando houver um erro de digitação (ou a palavra já foi digitada com êxito nesta execução).

5 . Para os relogios! Agora, imprima o CPM (Caracters por minuto) de referência, que é calculado da seguinte forma: (sum of the characters of the chosen words / time spent typing (seconds)) * 60. Arredonde para o número inteiro mais próximo e reproduza a seguinte saída (amostra):

-> Você marcou 344 CPM!

Uma amostra de execução

-> liquidar
-> lado
-> aberto
-> ministro
-> risco
-> cor
-> navio
-> mesmo
-> tamanho
-> espada
resolver
Está bem
lado
Está bem
aberto
Está bem
# ...................... algumas linhas cortadas ......................
palavra
ERRADO
espada
Está bem
-> Você marcou 298 CPM!

O vencedor

Este é o código colf, a entrada mais curta (na contagem de caracteres do código fonte) vence, divirta-se!

ChristopheD
fonte
4
Eu acho que o vencedor deve ser parcialmente marcado pela pessoa com o maior CPM;)
mellamokb
Com que precisão precisamos medir o tempo? A resolução de um segundo está OK?
Ilmari Karonen
@Ilmari Karonen: uma resolução de um segundo seria adequada para este concurso específico.
ChristopheD

Respostas:

5

K, 146

Assume um arquivo de dicionário chamado 'd' no diretório de trabalho atual.

{b:+/#:'a:10?_0:`:d;-1"-> ",/:a;s:.z.t;while[#a;$[(,/0:0)~*a;[a:1_a;-1"OK"];-1"WRONG"]];-1"--> You have scored ",($(60000*b)%"i"$.z.t-s)," CPM!";}
tmartin
fonte
Muito agradável e curto, primeira entrada Keu vi (aqui na codegolf.se) ...
ChristopheD
Graças, todas as minhas respostas aqui estão em Q ou (cada vez mais) em K.
tmartin
Eu não entendo por que isso só recebeu uma única votação positiva (minha)!
ChristopheD
11

Bash - 217 212 199 196 caracteres

Não vai ganhar, mas foi divertido

declare -A W
for w in `shuf -n10`;do C+=$w;echo -\> $w;W[$w]=OK;done
SECONDS=0
for((;${#W[*]};));do read r;echo ${W[$r]-WRONG};unset W[$r];done
echo --\> You have scored $((60*${#C}/SECONDS)) CPM!

Menos de 200 caracteres agora!

Leva o arquivo da lista de palavras como argumento Agora leva a lista de palavras na entrada padrão. Cole-o no terminal e pressione ^ D

Sugestão implementada de manatwork

Geoff Reedy
fonte
1
Não vai ganhar, mas foi divertido - Eu acho que a mesma coisa quando eu postar meu c soluções # :)
Cristian Lupaşcu
1
Você pode usar a $SECONDSvariável shell para simplificar o cálculo do tempo decorrido.
manatwork
Você pode remover mais 2 caracteres: 1) :no parâmetro de valor padrão de expansão; 2) a $frente SECONDSna avaliação aritmética. Na verdade, há outro caractere extra, a nova linha no e do arquivo.
manatwork
4

Ruby (189 178 171 168)

$><<t=['',d=[*$<.lines].sample(10)]*'-> '
s=Time.now
puts d.delete($stdin.gets)?:OK:'WRONG'while d[0]
puts'--> You have scored %i CPM!'%((t.size-40)/(Time.now-s)*60)

Bem básico, tenho certeza de que há melhorias a serem feitas. Leva o nome do arquivo do dicionário como um argumento da linha de comando.

Edição : alguns pequenos ajustes, principalmente em torno de manter as novas linhas do dicionário. Como resultado, o arquivo precisará de uma nova linha à direita para funcionar corretamente.

Paul Prestidge
fonte
4

C, 305309 347 caracteres

char*stdin,w[11][99];long i,t;main(int n,char**v){v=fopen(v[1],"r");
for(srand(time(&t));fgets(w[i++>9?(n=rand()%i)>10?0:n:i],99,v););
for(i=n=0;i<10;n+=printf("-> %s",w[++i])-4);
for(;i;puts(!strcmp(*w,w[11-i])?--i,"OK":"WRONG"))fgets(*w,99,stdin);
printf("--> You have scored %ld CPM!\n",n*60/(time(0)-t));}

Obrigado a @ugoren pelas dicas de melhoria. Usar uma "11ª palavra" para descartar entradas de dicionário recebidas foi uma grande vitória em relação à minha abordagem anterior de strcpy-if-escolhido.

Aqui está a fonte não destruída:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static char words[11][99];
static long i, t;

int main(int argc, char *argv[])
{
    FILE *fp;
    int n;

    fp = fopen(argv[1], "r");
    srand(time(0));
    for (i = 0 ; fgets(words[0], sizeof words[0], fp) ; ++i) {
        n = i < 10 ? i : rand() % i;
        if (n < 10)
            strcpy(words[n + 1], words[0]);
    }
    fclose(fp);

    n = 0;
    for (i = 1 ; i <= 10 ; ++i)
        n += printf("-> %s", words[i]) - 4;
    t = time(0);
    i = 1;
    while (i <= 10 && fgets(words[0], sizeof words[0], stdin)) {
        if (strcmp(words[0], words[i])) {
            puts("WRONG");
        } else {
            puts("OK");
            ++i;
        }
    }
    if (i > 9)
        printf("-> You have scored %ld CPM!\n", n * 60 / (time(0) - t));

    return argc - argc;
}
caixa de pão
fonte
Algumas melhorias: 1. K & declaração R: main(n,v)char**v;{.... 2. stdinpode ser char *. fgets(buf,len,stdin)= gets(buf)(não importa o excesso de buffer). 3. O que há de errado rand()%i? RAND_MAXnão é necessário. 4. Por que long?
Ugoren
1
Também: 1) t=time(0)-> time(&t). 2) n*60/(time(0)-t)tem parênteses que devem ir - *60podem ser movidos para n+=60*printf, então n/=time(0)-t. 3) Substitua bpor um elemento extra w, substitua strcpypor leia diretamente w.
Ugoren
Substituir fgets()por gets()precisa de código extra para lidar com as novas linhas no dicionário; isso acabou sendo mais curto. rand()%inão é suficiente; o cálculo real é (double)i*rand()/RAND_MAX. Mover o *60arquivo para o printf também significa alterar o arquivo -4para, -240assim, acaba perdendo. Seus outros pontos são válidos, no entanto (acredito). Ah, e longé porque o time_t é tradicionalmente longo. Só porque estamos jogando golfe não significa que não podemos ser portáteis.
breadbox
Eu perdi 4-> 240... Portabilidade e golfe não vão bem juntos. Porém, definir i,t;(int implicitamente) é OK até MAX_INTsegundos (se você não usar time(&t)). Com rand(), tudo que você precisa é uma 10/ichance, e rand()%i<10faz.
Ugoren
Sua seleção aleatória é um tanto falha (não que a justiça absoluta seja necessária). A 11ª linha deve ter 10/11 de chance de ser selecionada, mas você faz rand()%10>10, o que lhe dá 100%. rand()%(i+1)>9é melhor (mas em vez se %(i+1)fazer i++>9?. Também se mover *stdinpara ser o primeiro e salvar um espaço.
ugoren
2

C # 401

void T(){
Action<string>C=Console.WriteLine;Func<string>R=Console.ReadLine;
var w=new List<string>();
for(var l=R();l!="";l=R())w.Add(l);
var s=w.OrderBy(_=>Guid.NewGuid()).Take(10).ToList();
s.ForEach(x=>C("=> "+x));
var t=s.Select(x=>x.Length).Sum();
var c=Stopwatch.StartNew();
while(s.Any()){C(s.Remove(R())?"OK":"WRONG");}
c.Stop();
C("--> You have scored "+c.Elapsed.TotalSeconds*60/t+" CPM!");}

Versão em execução aqui: http://ideone.com/Nt6Id

Cristian Lupascu
fonte
2

Python ( 256 235)

import time as t,random as r
def p(x):print x
c=r.sample(input().split("\n"),10)
z=lambda x:p(("WRONG","OK")[raw_input()==x])or len(x)
p("--> "+"\n--> ".join(c))
_=t.time()
p("--> You have scored %d CPM!"%(sum(map(z,c))/(t.time()-_)*60))

Isso está no python 2.x, no 3.x eu posso cortar mais 4 caracteres usando a função de impressão.

Novas linhas incluídas

Joel Cornett
fonte
2
"Pergunta: as novas linhas contam?" Costumamos usar "caracteres necessários". No caso do Python, sim, as novas linhas precisam ser contadas, pois removê-las impedirá o funcionamento do programa.
Joey Adams
1
Eu acho que você pode mudar z=lambda x:para def z(x):.
Joey Adams
@JoeyAdams: Eu poderia se só precisava nenhum retorno, mas eu preciso voltar len(x)e def z(x):returné mais 5 charaters: /
Joel Cornett
Eu acho que você pode ganhar alguns caracteres por tubulação na entrada (permitido na questão) e usando input()em vez desys.argv[1].read()
ChristopheD
@JoelCornett: Opa, você está certo.
Joey Adams
2

PHP 187 bytes

Novas linhas foram adicionadas para maior clareza:

<?$s=file($argv[1]);
for(shuffle($s);$i++<10;$l+=strlen($$i))echo~ÒÁß,$$i=$s[$i];
for($t=time();$j++<10;)echo$$j==fgets(STDIN)?OK:WRONG,~õ?>
--> You have scored <?=0|$l/(time()-$t)*60?> CPM!

Aceita o nome do arquivo do dicionário como um argumento de linha de comando. O arquivo do dicionário deve terminar com uma nova linha.

primo
fonte
2

Scala ( 319 306 304 302)

var s=util.Random.shuffle(io.Source.fromFile(args(0)).getLines.toSet)take 10
def?(a:Any)=println(a)
var l=(0/:s){_+_.size}
s map{"-> "+_}map?
def n=System.nanoTime
val t=n
while(s.size!=0){val m=readLine
if(s contains m)?("OK")else?("WRONG");s-=m}
?("--> You have scored "+l*60000000000L/(n-t)+" CPM!")
Prince John Wesley
fonte