10, 10, 10 ... spero?


15

Prefazione

Mentre stavo girando un tiro con l'arco a 900 round oggi (10 finisce a 6 frecce alla fine e 10 finisce a 3 frecce alla fine, per un totale di 90 frecce e un punteggio massimo di 900), ho pensato a questa sfida.

Nel tiro con l'arco (supponendo che stai sparando su una faccia bersaglio fornita dalla FITA [il pezzo di carta che spari a]], per ogni freccia puoi ottenere un punteggio massimo di 10. La faccia bersaglio contiene 10 o 11 anelli di diametro decrescente, annidati l'uno nell'altro. Dall'anello interno verso l'esterno, questi vengono conteggiati da 10 punti, a un punto (e nel caso di 11 anelli, esiste un anello più interno secondario che conta come "X", che segna come 10 ma viene utilizzato nei casi di rottura del pareggio come il valore più alto). Osservare:

Punteggio target FITA

Certo, mi riferisco al punteggio FITA Metric, come mostrato nella figura sopra. Se guardi da vicino, puoi osservare l'anello più interno, che è una linea tratteggiata sbiadita, il cui punteggio non è segnato. Questa è la "X" a cui mi riferivo, ma non dovrai prestare attenzione a questo a meno che non competi per il bonus.

Sfida

Crea una funzione (o un programma completo, se la lingua non supporta le funzioni), che riceve un'immagine perfettamente quadrata come input (o nome file immagine, se necessario), contenente un numero di verde (HEX # 00FF00, RGB (0, 255, 0)) punti di qualche dimensione e restituisce il punteggio. L'immagine può contenere dati diversi dai punti verdi , ma il verde avrà sempre la stessa identica tonalità.

Puoi immaginare che l'immagine quadrata rappresenti la faccia del bersaglio, con l'anello più esterno che tocca in 4 punti (in alto al centro, in basso al centro, al centro a destra, al centro a sinistra). La faccia di destinazione rappresentata sarà sempre della stessa proporzione, con tutti gli anelli che hanno una larghezza esattamente di 1/20 della larghezza dell'immagine di destinazione in ingresso. Ad esempio, data un'immagine di input di dimensioni di input 400px per 400px, puoi supporre che ogni anello abbia una larghezza interna di 20px, come illustrato di seguito:

Illustrazione di esempio scadente

chiarimenti

  • Se si toccano due anelli separati, viene conteggiato il più alto dei due anelli
  • Non è necessario tenere conto automaticamente dei mancati o del caso "x", a meno che non si provi il bonus
  • Puoi presumere che nessun cerchio verde si sovrapponga
  • Puoi anche supporre che nell'immagine non vi siano altri pixel di quella tonalità di verde
  • L'immagine sarà in formato PNG, JPEG o PPM (a tua scelta)
  • Sono consentite librerie esterne di elaborazione delle immagini, se create prima della pubblicazione di questa domanda
  • Puoi presumere che tutti i cerchi verdi su un bersaglio avranno lo stesso diametro
  • Se spari (hah) per il bonus dei cerchi sovrapposti, puoi presumere che almeno un cerchio nell'immagine non abbia un altro sovrapposto
  • Le scappatoie standard non sono ammesse

Casi test

I seguenti due casi dovrebbero segnare 52 (o in caso di bonus, 52 con 1 'x' e 1 mancata):

E quest'ultimo test dovrebbe segnare 25 :

indennità

  • -25 byte se si restituisce anche il numero di mancati (al di fuori di qualsiasi anello)
  • -30 byte se si restituisce anche la quantità di X (supponiamo che la x più interna sia 3 / 100th della larghezza dell'immagine e 10 sia quindi 2 / 100th della larghezza dell'immagine. Le proporzioni 1-9 rimangono invariate)
  • -35% conteggio byte se si tiene conto di cerchi sovrapposti

Questo è il codice golf, quindi vince il minimo byte. Divertiti!


"30 finisce con 3 frecce alla fine, per un totale di 30 frecce"? Non dovrebbero essere 90 frecce?
DavidC

@DavidCarraher L'ho capito bene come ho pubblicato. Corretto
globby il

Quali formati di immagine possiamo usare? PNG? PPM? Il nostro formato personalizzato? (Suppongo che i primi due, ma non il terzo, ma solo per chiarimenti.)
Maniglia della porta

Diciamo solo JPEG o PNG per semplicità @Doorknob 冰
globby

1
Penso che il bonus più difficile sia quello con il minor premio.
Justin,

Risposte:


4

Elaborazione 2, 448-25 = 423 byte

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;}

Legge in un file di immagine f scorre ciclicamente i pixel fino a quando non trova il verde, quindi riempie il cerchio determinando il punto più vicino al centro. Quindi aggiunge quel punteggio a un totale. se il punteggio è negativo, viene aggiunto a un contatore miss.

Il programma produrrà 2 numeri, il primo è il punteggio e il secondo è il numero di mancati.

  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;
}

puoi ottenere l'elaborazione qui


4

Perl 5 + GD: 225-25 = 200

Modifica: trovato il motivo della lettura errata dei pixel nei PNG indicizzati e applicato una soluzione alternativa. Per qualche motivo con la libreria GD i valori di pixel verdi vengono letti come (4.254,4). Non sono sicuro che sia specifico per i file PNG inclusi nella domanda. Le interruzioni di riga possono essere rimosse nel codice seguente.

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 $%"

Cattura un'immagine PNG sull'input e stampa 2 valori: Numero di punti e mancati. Per esempio:

perl arch.pl <arch52.png
52 1

Modifica dell'ultimo minuto:

Nella modalità colore reale di cui avevo bisogno gli indici di colore utilizzati da getPixele fillsono semplicemente valori RGB con codifica intera, quindi non è necessario utilizzare rgbe colorAllocateconvertire da e verso quegli indici.

Spiegazione:

  • Genera un elenco di tutte le coordinate dei pixel (come coppie di numeri interi separati da spazio).
  • Ordina per punteggio potenziale (utilizzando il sub vquale accetta i parametri $_anziché i parametri standard in quanto è più breve).
  • Per ogni pixel a partire da quelli con il punteggio più alto se è verde, aggiungi al risultato e riempi la sua posizione di nero.

Non sono le immagini; La risposta di @ bubalou legge correttamente i colori come # 00FF00
globby

@globby So che i colori sono corretti nell'immagine (ho controllato con il software di modifica delle immagini), ma forse ci sono anche le stesse meta informazioni per tagliare lo spazio colore.
Nutki,

possibilmente. È strano però
lugubre il

3

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

Strategia:

  • Crea un elenco di (d, x, y) triple per tutti i pixel (d è la distanza dal centro)
  • ordina l'elenco per distanza
  • a partire dalla distanza massima: se il pixel è l'unico pixel verde in un piccolo quartiere, mantieni la distanza in un elenco L, altrimenti anneriscilo
  • calcolare il punteggio dall'elenco delle distanze L

L'output è un triplo (punteggio, miss, Xs), ad es. (52,1,1)Per l'immagine di prova.

Il programma potrebbe non funzionare se il pixel di un cerchio più vicino al centro si trova entro 3 pixel da un altro cerchio.

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

Un consiglio: all idè lo stesso di and.anche, è possibile implementare jcon protezioni di patternj n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
haskeller orgoglioso

@proudhaskeller: Sì, grazie!
nimi,

2

Mathematica - 371 386 - 25 = 361

Una soluzione più ottimale. Calcola la risposta molto più velocemente della mia soluzione 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 con PIL - Una soluzione banale e non ottimale, 961 byte

Questo è semplicemente per provare a dimostrare un approccio sciocco nel risolvere il problema. Sono necessari ~ 2 minuti per eseguire i primi due casi di test e ~ 20 minuti per eseguire il terzo sul mio sistema a causa del rilevatore di cerchi rapidamente inventato, terribilmente dispendioso in termini di risorse e complessa dal punto di vista repulsivamente complesso. Ciononostante, soddisfa i requisiti, sebbene non sia certamente ottimizzato. Più verde c'è sull'immagine, più tempo ci vuole per correre.

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

Accetta un oggetto immagine PIL e restituisce il punteggio.

Passaggi necessari:

  1. Isolare i cerchi verdi (in modo inefficiente)
    • Trova tutti i vicini di alcuni pixel n, se presenti pixel verdi, aggiungili al cerchio
    • Determina il contorno approssimativo filtrando i pixel con 8 vicini
  2. Disegna una rappresentazione di destinazione
    • Crea una tela bianca
    • Disegna uno sfondo colorato unico (miss facili da implementare)
    • Disegna ellissi nidificate con colori unici
  3. Determina quali zone segnano ogni cerchio determinando il colore (i) del bersaglio che sarebbe sotto il cerchio
  4. Scegli la più alta delle zone di punteggio (se multiple) e aggiungi il punteggio al totale
  5. Restituisce il totale

La tua funzione Python apuò essere scritta comea=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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.