10, 10, 10 ... hoffe ich?

15

Vorwort

Als ich heute 900 Runden im Bogenschießen geschossen habe (10 endeten bei 6 Pfeilen pro Ende und 10 endeten bei 3 Pfeilen pro Ende, was insgesamt 90 Pfeilen und einer maximalen Punktzahl von 900 entspricht), habe ich an diese Herausforderung gedacht.

Beim Bogenschießen (vorausgesetzt, Sie schießen auf eine von FITA bereitgestellte Zielfläche [das Stück Papier, auf das Sie schießen]) können Sie für jeden Pfeil eine maximale Punktzahl von 10 angeben. Die Zielfläche enthält 10 oder 11 Ringe mit abnehmendem Durchmesser. ineinander verschachtelt. Vom inneren Ring nach außen werden diese von 10 Punkten bis zu einem Punkt gezählt (und im Fall von 11 Ringen gibt es einen sekundären innersten Ring, der als 'X' zählt, der mit 10 bewertet wird, in Fällen, in denen das Binden unterbrochen wird, jedoch als der höhere Wert). Beobachten:

FITA-Zielerfassung

Natürlich beziehe ich mich auf die FITA Metric-Wertung, wie in der obigen Abbildung gezeigt. Wenn Sie genau hinsehen, können Sie den innersten Ring beobachten, bei dem es sich um eine verblasste gepunktete Linie handelt, deren Punktzahl nicht markiert ist. Das ist das 'X', auf das ich mich bezog, aber Sie müssen nicht darauf achten, es sei denn, Sie konkurrieren um den Bonus.

Herausforderung

Erstellen Sie eine Funktion (oder ein vollständiges Programm, wenn die Sprache keine Funktionen unterstützt), die ein perfekt quadratisches Bild als Eingabe (oder ggf. einen Bilddateinamen) mit einer bestimmten Anzahl von Grün (HEX # 00FF00, RGB (0, 255, 0)) Punkte von einiger Größe und gibt die Punktzahl zurück. Das Bild enthält möglicherweise andere Daten als die grünen Punkte , aber das Grün hat immer den exakt gleichen Farbton.

Sie können sich vorstellen, dass das quadratische Bild die Zielfläche darstellt, wobei sich der äußerste Ring an 4 Punkten (oben in der Mitte, unten in der Mitte, rechts in der Mitte, links in der Mitte) berührt. Die dargestellte Zielfläche hat immer das gleiche Verhältnis, wobei alle Ringe eine Breite von genau 1/20 der Breite des eingegebenen Zielbilds haben. Bei einem Eingabebild mit den Eingabeabmessungen 400 x 400 Pixel können Sie beispielsweise davon ausgehen, dass jeder Ring eine innere Breite von 20 Pixel hat, wie im Folgenden dargestellt:

Scheiß Beispiel Illustration

Klarstellungen

  • Wenn Sie zwei Ringe berühren, wird der höhere der beiden Ringe gezählt
  • Sie müssen nicht automatisch Misses oder den 'x'-Fall berücksichtigen, es sei denn, Sie versuchen, den Bonus zu erhalten
  • Sie können davon ausgehen, dass sich keine grünen Kreise überlappen
  • Sie können auch davon ausgehen, dass sich keine anderen Pixel dieses Grüntons im Bild befinden
  • Das Bild ist entweder im PNG-, JPEG- oder PPM-Format (nach Wahl).
  • Externe Bildbearbeitungsbibliotheken sind zulässig, wenn sie vor dem Absenden dieser Frage erstellt wurden
  • Sie können davon ausgehen, dass alle grünen Kreise auf einem Ziel den gleichen Durchmesser haben
  • Wenn Sie für den Bonus für überlappende Kreise schießen (hah), können Sie davon ausgehen, dass mindestens ein Kreis im Bild keine weitere Überlappung aufweist
  • Standardlücken sind nicht zulässig

Testfälle

In den folgenden beiden Fällen sollten jeweils 52 Punkte erzielt werden (oder bei Boni 52 mit 1 "x" und 1 "verfehlt"):

Und dieser letzte Testfall sollte 25 Punkte bringen :

Bonus

  • -25 Bytes, wenn Sie auch die Anzahl der Fehler (außerhalb eines der Ringe) zurückgeben
  • -30 Bytes, wenn Sie auch die Menge der Xs zurückgeben (angenommen, dass das innerste x 3 / 100stel der Breite des Bildes und 10 dann 2 / 100stel der Breite des Bildes beträgt. Die Proportionen 1-9 bleiben unverändert)
  • -35% Byteanzahl, wenn Sie überlappende Kreise berücksichtigen

Dies ist Codegolf, also gewinnt das kleinste Byte. Habe Spaß!

schelmisch
quelle
"30 endet an 3 Pfeilen pro Ende, also insgesamt 30 Pfeile"? Sollte das nicht 90 Pfeile sein?
DavidC
@DavidCarraher Ich habe das richtig erkannt, als ich gepostet habe. Korrigiert
heiter
Welche Bildformate können wir verwenden? PNG? PPM? Unser eigenes Format? (Ich würde die ersten beiden aber nicht die dritte annehmen, sondern nur zur Verdeutlichung.)
Türklinke
Sagen wir einfach , JPEG oder PNG für Einfachheit @Doorknob冰
globby
1
Ich denke, der schwerste Bonus ist der mit der geringsten Belohnung.
Justin

Antworten:

4

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

Liest eine Bilddatei ein f durchläuft die Pixel, bis sie grün sind, und füllt dann den Kreis, um den Punkt zu bestimmen, der der Mitte am nächsten liegt. Addiert dann diese Punktzahl zu einer Gesamtsumme. Wenn die Punktzahl negativ ist, wird sie einem Fehlerzähler hinzugefügt.

Das Programm gibt 2 Zahlen aus, wobei die erste die Punktzahl und die zweite die Anzahl der Fehler ist.

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

Sie können erhalten die Verarbeitung hier

bubalou
quelle
4

Perl 5 + GD: 225 - 25 = 200

Bearbeiten: Ermittelte den Grund für das fehlerhafte Lesen von Pixeln in indizierten PNGs und führte eine Problemumgehung durch. Aus irgendeinem Grund werden bei der GD-Bibliothek die grünen Pixelwerte als (4.254,4) gelesen. Ich bin nicht sicher, ob dies spezifisch für die in der Frage enthaltenen PNG-Dateien ist. Zeilenumbrüche können im folgenden Code entfernt werden.

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

Nimmt ein PNG-Bild in die Eingabe auf und druckt 2 Werte: Anzahl der Punkte und Fehler. Beispielsweise:

perl arch.pl <arch52.png
52 1

Last Minute Änderung:

Im Echtfarben-Modus brauchte ich sowieso die von getPixelund verwendeten Farbindizes fillsind einfach ganzzahlig codierte RGB-Werte, so dass es nicht erforderlich ist, diese Indizes zu verwenden rgbund colorAllocatezu diesen zu konvertieren.

Erläuterung:

  • Erzeugt eine Liste aller Pixelkoordinaten (als durch Leerzeichen getrennte Ganzzahlpaare).
  • Nach potenzieller Punktzahl sortieren (verwendet sub vParameter $_anstelle von Standardparametern, da sie kürzer sind).
  • Für jedes Pixel, beginnend mit den Pixeln mit der höchsten Punktzahl, wenn es grün ist, addiere das Ergebnis und fülle seine Stelle mit Schwarz.
nutki
quelle
Es sind nicht die Bilder; @ Bubalous Antwort richtig lesen Sie die Farben als # 00FF00
globby
@globby Ich weiß, dass die Farben im Bild korrekt sind (ich habe sie mit einer Bildbearbeitungssoftware überprüft), aber möglicherweise gibt es auch dieselben Metainformationen, um den Farbraum zu verkleinern.
Nutki
möglicherweise. Das ist allerdings seltsam
schlauer
3

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

Strategie:

  • Erstelle eine Liste mit (d, x, y) Dreifachen für alle Pixel (d ist der Abstand zur Mitte)
  • sortiere die Liste nach Entfernung
  • Beginnend mit der größten Entfernung: Wenn das Pixel das einzige grüne Pixel in einer kleinen Nachbarschaft ist, halten Sie seine Entfernung in einer Liste L, andernfalls schwärzen Sie es
  • Punktzahl aus der Distanzliste L berechnen

Die Ausgabe ist ein Triple (Score, Misses, Xs), z (52,1,1) für das Testbild.

Das Programm schlägt möglicherweise fehl, wenn sich das Pixel eines Kreises, der dem Zentrum am nächsten liegt, innerhalb von 3 Pixeln eines anderen Kreises befindet.

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
nimi
quelle
Ein Tipp: all idist das gleiche wie and.auch jmit Pattern Guards j n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
umsetzbar
@ proudhaskeller: Ja, danke!
nimi
2

Mathematica - 371 386 - 25 = 361

Eine optimalere Lösung. Berechnet die Antwort viel schneller als meine Python-Lösung.

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 mit PIL - Eine triviale und nicht optimale Lösung, 961 Bytes

Dies ist einfach zu versuchen, einen dummen Ansatz bei der Lösung des Problems zu demonstrieren. Es dauert ca. 2 Minuten, um die ersten beiden Testfälle auszuführen, und ca. 20 Minuten, um den dritten Testfall auf meinem System auszuführen, da der Kreisdetektor schnell aufgebaut, schrecklich ressourcenintensiv und abstoßend algorithmisch komplex ist. Trotzdem erfüllt es die Anforderungen, obwohl es sicherlich nicht optimal golfen kann. Je grüner das Bild ist, desto länger dauert die Ausführung.

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

Nimmt ein PIL-Bildobjekt und gibt die Punktzahl zurück.

Schritte, die es braucht:

  1. Grüne Kreise isolieren (ineffizient)
    • Finde alle Nachbarn eines Pixels n . Falls es sich um grüne Pixel handelt, fügen Sie diese dem Kreis hinzu
    • Bestimmen Sie den groben Umriss, indem Sie Pixel mit 8 Nachbarn herausfiltern
  2. Zeichnen Sie eine Zielrepräsentation
    • Erstellen Sie eine leere Leinwand
    • Zeichnen Sie einen einzigartigen farbigen Hintergrund (leicht zu implementierende Fehler)
    • Zeichnen Sie verschachtelte Ellipsen mit einzigartigen Farben
  3. Bestimmen Sie, in welchen Wertungszonen sich jeder Kreis befindet, indem Sie die Farbe (n) des Ziels bestimmen, das sich unter dem Kreis befinden würde
  4. Wählen Sie die höhere der Bewertungszonen (falls mehrere vorhanden) und addieren Sie die Punktzahl zur Gesamtsumme
  5. Geben Sie den Gesamtbetrag zurück
schelmisch
quelle
Ihre Python - Funktion akann geschrieben werdena=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