10, 10, 10… j'espère?

15

Préface

Alors que je tirais un tir à l'arc 900 plus tôt dans la journée (10 bouts à 6 flèches par bout et 10 bouts à 3 flèches par bout, pour un total de 90 flèches et un score maximum de 900), j'ai pensé à ce défi.

En tir à l'arc (en supposant que vous tirez sur une face cible fournie par la FITA [le morceau de papier que vous tirez]), pour chaque flèche, vous pouvez réclamer un score maximum de 10. La face cible contient 10 ou 11 anneaux de diamètre décroissant, imbriqués les uns dans les autres. De l'anneau intérieur vers l'extérieur, ceux-ci sont comptés de 10 points à un point (et dans le cas de 11 anneaux, il y a un anneau le plus intérieur secondaire qui compte comme `` X '', qui marque 10, mais qui est utilisé dans les cas de départage comme la valeur la plus élevée). Observer:

Scores cibles de la FITA

Bien sûr, je me réfère au score métrique FITA, comme le montre l'illustration ci-dessus. Si vous regardez de plus près, vous pouvez observer l'anneau le plus intérieur, qui est une ligne pointillée décolorée, dont le score n'est pas marqué. C'est le «X» auquel je faisais référence, mais vous n'aurez pas à en tenir compte à moins de concourir pour le bonus.

Défi

Créez une fonction (ou un programme complet, si la langue ne prend pas en charge les fonctions), qui reçoit une image parfaitement carrée en entrée (ou un nom de fichier d'image, le cas échéant), contenant un certain nombre de verts (HEX # 00FF00, RGB (0, 255, 0)) points d'une certaine taille, et renvoie le score. L'image peut contenir des données autres que les points verts , mais le vert sera toujours exactement la même nuance.

Vous pouvez imaginer que l'image carrée représente le visage cible, avec l'anneau le plus extérieur touchant en 4 points (centre supérieur, centre inférieur, centre droit, centre gauche). La face cible représentée sera toujours de la même proportion, tous les anneaux ayant une largeur d'exactement 1 / 20e de la largeur de l'image cible en entrée. À titre d'exemple, étant donné une image d'entrée de dimensions d'entrée 400px par 400px, vous pouvez supposer que chaque anneau a une largeur intérieure de 20px, comme illustré ci-dessous:

Illustration d'exemple de merde

Clarifications

  • Si vous touchez deux anneaux séparés, le plus élevé des deux anneaux est compté
  • Vous n'avez pas à prendre automatiquement en compte les échecs ou le cas 'x', à moins d'essayer le bonus
  • Vous pouvez supposer qu'aucun cercle vert ne se chevauche
  • Vous pouvez également supposer qu'aucun autre pixel de cette nuance de vert n'est dans l'image
  • L'image sera au format PNG, JPEG ou PPM (au choix)
  • Les bibliothèques de traitement d'images externes sont autorisées, si elles sont créées avant la publication de cette question
  • Vous pouvez supposer que tous les cercles verts sur une cible auront le même diamètre
  • Si vous photographiez (hah) pour le bonus des cercles qui se chevauchent, vous pouvez supposer qu'au moins un cercle dans l'image n'a pas un autre chevauchement
  • Les failles standard sont interdites

Cas de test

Les deux cas suivants devraient chacun marquer 52 (ou dans le cas des bonus, 52 avec 1 'x' et 1 manque):

Et ce dernier cas de test devrait marquer 25 :

Prime

  • -25 octets si vous renvoyez également le nombre de ratés (en dehors de l'un des anneaux)
  • -30 octets si vous retournez également la quantité de Xs (supposez que le x le plus à l'intérieur soit 3 / 100ème de la largeur de l'image, et 10 est alors 2 / 100ème de la largeur de l'image. Les proportions 1-9 restent inchangées)
  • -35% d'octets si vous tenez compte des cercles qui se chevauchent

C'est le golf de code, donc le moindre octet gagne. S'amuser!

globby
la source
"30 extrémités à 3 flèches par extrémité, pour un total de 30 flèches"? Cela ne devrait-il pas être 90 flèches?
DavidC
@DavidCarraher J'ai réalisé cela dès que j'ai posté. Corrigé
globby
Quels formats d'image pouvons-nous utiliser? PNG? PPM? Notre propre format personnalisé? (Je suppose que les deux premiers mais pas le troisième, mais juste pour des éclaircissements.)
Poignée de porte
Disons simplement JPEG ou PNG pour plus de simplicité @Doorknob 冰
globby
1
Je pense que le bonus le plus difficile est celui qui a le moins de récompense.
Justin

Réponses:

4

Traitement 2, 448-25 = 423 octets

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

Lit un fichier image f parcourt les pixels jusqu'à ce qu'il trouve le vert puis remplit le cercle en déterminant le point le plus proche du centre. Ajoute ensuite ce score à un total. si le score est négatif, il est ajouté à un compteur de ratés.

Le programme affichera 2 nombres, le premier est le score et le second est le nombre de ratés.

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

vous pouvez obtenir le traitement ici

bubalou
la source
4

Perl 5 + GD: 225 - 25 = 200

Modifier: a trouvé la raison de la lecture incorrecte des pixels dans les fichiers PNG indexés et a appliqué une solution de contournement. Pour une raison quelconque avec la bibliothèque GD, les valeurs des pixels verts sont lues comme (4,254,4). Je ne sais pas si cela est spécifique aux fichiers PNG inclus dans la question. Les sauts de ligne peuvent être supprimés dans le code ci-dessous.

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

Prend une image PNG sur l'entrée et imprime 2 valeurs: Nombre de points et de ratés. Par exemple:

perl arch.pl <arch52.png
52 1

Changement de dernière minute:

En mode couleur véritable, j'avais besoin de toute façon des index de couleur utilisés par getPixelet fillsont simplement des valeurs RVB codées en entier, donc pas besoin d'utiliser rgbet colorAllocatede convertir vers et depuis ces index.

Explication:

  • Générez une liste de toutes les coordonnées de pixels (sous forme de paires d'entiers séparés par des espaces).
  • Trier par score potentiel (en utilisant sub vce qui prend le paramètre$_ place des paramètres standard car il est plus court).
  • Pour chaque pixel, en commençant par les plus élevés s'il est vert, ajoutez au résultat et remplissez son emplacement en noir.
nutki
la source
Ce ne sont pas les images; La réponse de @ bubalou a correctement lu les couleurs comme # 00FF00
globby
@globby Je sais que les couleurs sont correctes dans l'image (j'ai vérifié avec un logiciel de retouche d'image), mais il y a peut-être aussi les mêmes méta-informations pour couper l'espace colorimétrique.
nutki
peut-être. C'est étrange cependant
globby
3

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

Stratégie:

  • Faites une liste de (d, x, y) triplets pour tous les pixels (d est la distance au centre)
  • trier la liste par distance
  • en commençant par la plus grande distance: si le pixel est le seul pixel vert dans un petit quartier, gardez sa distance dans une liste L, sinon noircissez-le
  • calculer le score à partir de la liste des distances L

La sortie est un triple (score, échecs, X), par exemple (52,1,1)pour l'image de test.

Le programme peut échouer si le pixel d'un cercle le plus proche du centre se trouve à moins de 3 pixels d'un autre cercle.

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
la source
Un conseil: all idc'est la même chose que and.aussi, vous pouvez l'implémenter javec des protections de motifj n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
fier haskeller
@proudhaskeller: Oui, merci!
nimi
2

Mathematica - 371 386 - 25 = 361

Une solution plus optimale. Calcule la réponse beaucoup plus rapidement que ma solution 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 avec PIL - Une solution triviale et non optimale, 961 octets

Il s'agit simplement d'essayer de démontrer une approche idiote pour résoudre le problème. Il faut environ 2 minutes pour exécuter les deux premiers cas de test et environ 20 minutes pour exécuter le troisième sur mon système en raison du détecteur de cercle rapidement constitué, terriblement gourmand en ressources et répulsivement complexe sur le plan algorithmique. Malgré cela, il répond aux exigences, bien qu'il ne soit certainement pas joué de manière optimale. Plus il y a de vert sur l'image, plus il faut de temps pour courir.

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

Prend un objet image PIL et renvoie le score.

Étapes à suivre:

  1. Isoler les cercles verts (inefficacement)
    • Trouvez tous les voisins d'un pixel n, s'il y a des pixels verts, ajoutez-les au cercle
    • Déterminez le contour approximatif en filtrant les pixels qui ont 8 voisins
  2. Dessinez une représentation cible
    • Créer une toile vierge
    • Dessinez un arrière-plan coloré unique (facile à implémenter des échecs)
    • Dessinez des ellipses imbriquées avec des couleurs uniques
  3. Déterminez dans quelles zones de notation se trouve chaque cercle en déterminant la ou les couleurs de la cible qui se trouveraient sous le cercle
  4. Choisissez la plus élevée des zones de score (si multiple) et ajoutez le score au total
  5. Renvoyer le total
globby
la source
Votre fonction Python apeut être écrite sous la formea=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