10, 10, 10 ... espero?


15

Prefácio

Como eu estava disparando um tiro com arco 900 no início de hoje (10 termina em 6 flechas por fim e 10 termina em 3 flechas por fim, num total de 90 flechas e uma pontuação máxima de 900), pensei nesse desafio.

No arco e flecha (supondo que você esteja atirando em uma face-alvo fornecida pela FITA [o pedaço de papel em que você dispara]), para cada flecha você pode obter uma pontuação máxima de 10. A face-alvo contém 10 ou 11 anéis de diâmetro decrescente, aninhados um dentro do outro. Do anel interno para fora, eles são contados de 10 pontos a um ponto (e no caso de 11 anéis, existe um anel interno secundário que conta como 'X', que tem 10 pontos, mas é usado em casos de desempate como o valor mais alto). Observar:

Pontuação FITA Target

Obviamente, estou me referindo à pontuação do FITA Metric, como visto na ilustração acima. Se você olhar atentamente, poderá observar o anel mais interno, que é uma linha pontilhada desbotada, cuja pontuação não está marcada. Esse é o 'X' ao qual eu estava me referindo, mas você não terá que prestar atenção a menos que esteja competindo pelo bônus.

Desafio

Crie uma função (ou programa completo, se o idioma não suportar funções), que receba uma imagem perfeitamente quadrada como entrada (ou nome do arquivo da imagem, se necessário), contendo algum número de verde (HEX # 00FF00, RGB (0, 255, 0)) pontos de algum tamanho e retorna a pontuação. A imagem pode conter dados que não sejam os pontos verdes , mas o verde sempre terá exatamente a mesma tonalidade.

Você pode imaginar que a imagem quadrada representa a face do alvo, com o anel mais externo tocando em 4 pontos (centro superior, centro inferior, centro direito, centro esquerdo). A face do destino representada sempre terá a mesma proporção, com todos os anéis com uma largura de exatamente 1/20 da largura da imagem de destino da entrada. Como exemplo, dada uma imagem de entrada com dimensões de 400px por 400px, você pode supor que cada anel tenha uma largura interna de 20px, conforme ilustrado abaixo:

Ilustração de exemplo de baixa qualidade

Esclarecimentos

  • Se tocar em dois anéis separados, o mais alto dos dois anéis será contado
  • Você não precisa contabilizar automaticamente os erros ou o caso 'x', a menos que tente o bônus
  • Você pode assumir que nenhum círculo verde se sobrepõe
  • Você também pode assumir que nenhum outro pixel dessa tonalidade de verde está na imagem
  • A imagem estará no formato PNG, JPEG ou PPM (sua escolha)
  • Bibliotecas de processamento de imagem externas são permitidas, se criadas antes da publicação desta pergunta
  • Você pode assumir que todos os círculos verdes em um alvo terão o mesmo diâmetro
  • Se fotografar (hah) pelo bônus de círculos sobrepostos, você pode assumir que pelo menos um círculo na imagem não possui outro sobreposto
  • As brechas padrão não são permitidas

Casos de teste

Os dois casos a seguir devem pontuar 52 (ou, no caso de bônus, 52 com 1 'x' e 1 falta):

E este último caso de teste deve marcar 25 :

Bônus

  • -25 bytes se você também retornar o número de erros (fora de qualquer um dos toques) também
  • -30 bytes se você também retornar a quantidade de Xs (suponha que o x mais interno seja 3 / 100º da largura da imagem e 10 seja 2 / 100º da largura da imagem. As proporções de 1 a 9 permanecem inalteradas)
  • -35% de contagem de bytes, se você considerar círculos sobrepostos

Isso é código de golfe, então o mínimo de bytes vence. Diverta-se!


"30 termina em 3 flechas por final, para um total de 30 flechas"? Não deveriam ser 90 flechas?
DavidC

@DavidCarraher Percebi isso certo quando publiquei. Corrigido
globby

Quais formatos de imagem podemos usar? PNG? PPM? Nosso próprio formato personalizado? (Eu assumiria os dois primeiros, mas não o terceiro, mas apenas para esclarecimentos.)
Maçaneta da porta

Digamos apenas JPEG ou PNG para simplificar @Doorknob冰
globby

1
Eu acho que o bônus mais difícil é o que tem menos recompensa.
Justin

Respostas:


4

Processando 2, 448-25 = 423 bytes

int x,y,w,b,v,c,m;color g;PImage i;void setup(){i=loadImage("f.png");w=i.width;size(w,w);g=#00ff00;image(i,0,0);b=v=x=y=c=m=0;loadPixels();while(y*w+x<w*w){if(pixels[y*w+x]==g){f(y,x);if(v>=0)c+=v;else m++;}v=-1;x++;if(x==w){x=0;y++;}}println(c+" "+m);}void f(int k,int l){pixels[k*w+l]=color(0);if(pixels[(k+1)*w+l]==g)f(k+1,l);if(pixels[k*w+l+1]==g)f(k,l+1);if(pixels[k*w+l-1]==g)f(k,l-1);k-=w/2;l-=w/2;b=10-(int)(sqrt(k*k+l*l)/(w/20));if(b>v)v=b;}

Lê em um arquivo de imagem f percorre os pixels até que fique verde e depois a inundação preenche o círculo, determinando o ponto mais próximo do centro. Em seguida, adiciona essa pontuação a um total. se a pontuação for negativa, ela é adicionada a um contador de erros.

O programa produzirá 2 números, o primeiro é o placar e o segundo é o número de erros.

  int x,y,w,b,v,c,m;
  color g;
  PImage i;
void setup()
{
  i=loadImage("f.png");
  w=i.width;
  size(w,w);
  g=#00ff00;
  image(i,0,0);
  b=v=x=y=c=m=0;  
  loadPixels();
  while(y*w+x<w*w)
  {
    if(pixels[y*w+x]==g)
    {
      f(y,x);
      if(v>=0)c+=v;
      else m++;
    }
    v=-1;
    x++;
    if(x==w){x=0;y++;}
  }
  print(c+" "+m);
}

void f(int k,int l)
{
  pixels[k*w+l]=color(0);
 if(pixels[(k+1)*w+l]==g)f(k+1,l);
 if(pixels[k*w+l+1]==g)f(k,l+1);
 if(pixels[k*w+l-1]==g)f(k,l-1); 
 k-=w/2;
 l-=w/2;
 b=10-(int)(sqrt(k*k+l*l)/(w/20));
 if(b>v)v=b;
}

você pode obter o processamento aqui


4

Perl 5 + GD: 225-25 = 200

Editar: localizou o motivo da leitura incorreta de pixels em PNGs indexados e aplicou uma solução alternativa. Por alguma razão, com a biblioteca GD, os valores de pixel verde são lidos como (4.254,4). Não tenho certeza se isso é específico para os arquivos PNG incluídos na pergunta.Quebras de linha podem ser removidas no código abaixo.

use GD;$k=newFromPng GD::Image'-',1;
sub v{/ /;10-int((($'-@x/2)**2+($`-@x/2)**2)**.5/@x*20)}
map{v>0?($r+=v):$%++,fill$k @c,0if 65280==getPixel$k @c=split
}sort{v($_=$b)- v$_=$a}map{//;map"$_ $'",@x}@x=0..width$k-1;
print"$r $%"

Tira uma imagem PNG na entrada e imprime 2 valores: Número de pontos e erros. Por exemplo:

perl arch.pl <arch52.png
52 1

Alteração de última hora:

No modo de cores verdadeiras que eu precisava, os índices de cores usados getPixele fillsão simplesmente valores RGB codificados por números inteiros, portanto, não é necessáriorgb e colorAllocateconverter e converter para esses índices.

Explicação:

  • Gere uma lista de todas as coordenadas de pixel (como pares de números inteiros separados por espaço).
  • Classifique por pontuação potencial (usando o sub vque leva o parâmetro até$_ vez dos parâmetros padrão, pois é mais curto).
  • Para cada pixel que começa com os de maior pontuação, se estiver verde, adicione ao resultado e pinte de preto sua localização.

Não são as imagens; resposta de @ bubalou ler corretamente as cores como # 00FF00
globby

@globby Eu sei que as cores estão corretas na imagem (verifiquei com o software de edição de imagens), mas talvez haja também as mesmas meta informações para aparar o espaço de cores.
nutki

possivelmente. Isso é estranho embora
globby

3

Haskell - 579-25 = 554 603-25-30 576-25-30 = 521 bytes

Estratégia:

  • Faça uma lista de (d, x, y) triplos para todos os pixels (d é a distância do centro)
  • classifique a lista por distância
  • começando com a maior distância: se o pixel é o único pixel verde em uma vizinhança pequena, mantenha a distância na lista L;
  • calcular pontuação da lista de distâncias L

O resultado é um triplo (pontuação, falha, Xs), por exemplo (52,1,1) para a imagem de teste.

O programa poderá falhar se o pixel de um círculo mais próximo do centro estiver a 3 pixels de outro círculo.

import Data.List
import Codec.Picture
import Codec.Picture.RGBA8
import Codec.Picture.Canvas
z=fromIntegral
f(e,x,y)(v,h)|and$j x y:[not$j a b|a<-[x-3..x+3],b<-[y-3..y+3],not(a==x&&b==y)]=(v,e:h)|1<2=(setColor x y(PixelRGBA8 0 0 0 0)v,h)
 where j n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
d k r(h,i,j)|r>10*k=(h,i+1,j)|r<k*3/5=(h+10,i,j+1)|1<2=(10-(floor$r/k)+h,i,j)
main=do
 i<-readImageRGBA8 "p.png"
 let(Right c)=imageToCanvas i;s=canvasWidth c;q=[3..s-4];(_,g)=foldr f(c,[])$sort[(sqrt$(z x-z s/2)^2+(z y-z s/2)^2,x,y)|x<-q,y<-q]
 print$foldr(d$z s/20)(0,0,0)g

Uma dica: all idé o mesmo que and.also, você pode implementar jcom guardas de padrãoj n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
haskeller orgulhoso

@proudhaskeller: Sim, obrigado!
N

2

Mathematica - 371 386 - 25 = 361

Uma solução mais ideal. Calcula a resposta muito mais rapidamente que minha solução Python.

i=IntegerPart;c=i/@((NestList[#+.01&,.1,10]~Prepend~1)*100);g[m_]:=Last@@c~Position~#-1&/@(i@Round@Last@#&/@(#*100&/@Riffle[RGBColor/@NestList[#+.01&,{.1,.1,.1},10],Table[Disk[{0,0},n],{n,1,.1,-.1}]]~Graphics~{ImageSize->ImageDimensions[m],PlotRangePadding->None}~ImageMultiply~ChanVeseBinarize[m,"TargetColor"->Green]~ComponentMeasurements~"Max"/.Rule[a_,b_]:>b))//{Total@#,#~Count~0}&

Python com PIL - Uma solução trivial e não ideal, 961 bytes

Isso é simplesmente para tentar demonstrar uma abordagem boba para resolver o problema. Demora ~ 2 minutos para executar os dois primeiros casos de teste e ~ 20 minutos para executar o terceiro no meu sistema por causa do detector de círculo rapidamente inventado, com grande demanda de recursos e complexo de algoritmos repulsivamente. Apesar disso, ele atende aos requisitos, embora certamente não seja um golfe ideal. Quanto mais verde houver na imagem, mais tempo levará para ser executado.

from PIL import Image,ImageDraw
a=lambda x,y,w,h:filter(lambda x:0<=x[0]<w and 0<=x[1]<h,[(x-1,y-1),(x,y-1),(x+1,y-    1),(x-1,y),(x,y),(x+1,y),(x-1,y+1),(x,y+1),(x+1,y+1)])
def b(c):
 d=0,255,0;e,f=c.size;g=c.load();h,i=[],[];j=Image.new("RGB",(e,f));k=ImageDraw.Draw(j)
 for l in range(e):
  for m in range(e):
   n=g[l,m][:-1]
   if n==d and(l,m)not in i:
    o=[(l,m)];p=[];q=1
    while q:
     q=0;r=o[:]
     for s in o:
      t=filter(lambda x:g[x[0],x[1]][:-1]==d and(x[0],x[1]) not in r,a(s[0],s[1],e,f))
      if t:
       r+=t
       if len(t)<8:
        p+=[s]
       q=1
     o=r
    h+=[p]
    for u in o:
     i+=[u]
   i+=[(l,m)]
 p=map(lambda x:"#"+str(x)*6,'123456789ab');v=0;k.rectangle((0,0,e,f),fill=p[0])
 for n in p[1:]:
  w=e/20*v;x=e-w;k.ellipse((w,w,x,x),fill=n);v+=1
 y=j.load();z=0
 for l in h:
  v=[]
  for m in l:
   s=y[m[0],m[1]]
   if s not in v:
    v+=[s]
  v=max(v);z+=p.index("#"+''.join(map(lambda x:hex(x)[2:],v)))
 return z

Pega um objeto de imagem PIL e retorna a pontuação.

Passos necessários:

  1. Isolar círculos verdes (ineficientemente)
    • Encontre todos os vizinhos de algum pixel n , se houver pixels verdes, adicione-os ao círculo
    • Determine o contorno aproximado filtrando os pixels que têm 8 vizinhos
  2. Desenhar uma representação de destino
    • Criar uma tela em branco
    • Desenhe um plano de fundo colorido exclusivo (fácil de implementar erros)
    • Desenhar elipses aninhados com cores exclusivas
  3. Determine em quais zonas de pontuação cada círculo se encontra determinando a (s) cor (s) do alvo que estaria embaixo do círculo
  4. Escolha a maior das zonas de pontuação (se múltiplas) e adicione a pontuação ao total
  5. Retorna o total

Sua função Python apode ser escrita comoa=lambda x,y,w,h:[(X,Y)for X in(x-1,x,x+1)for Y in(y-1,y,y+1)if w>X>-1<Y<h]
ovs 15/10
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.