10、10、10 ...我希望吗?


15

前言

当我今天早些时候在射箭900圈时(10头结束时每箭6箭,10头结束时每箭3箭,总共90箭,最高得分900),我想到了这一挑战。

在射箭比赛中(假设您使用FITA提供的目标面孔 [射击的纸张]射击),对于每个箭头,您的最高得分为10。目标面孔包含10或11个直径逐渐减小的环,彼此嵌套。从内圈向外,从10点算到一个点(在11个圈的情况下,存在第二个最里面的圈,记为“ X”,得分为10,但在打破平局的情况下使用:较高的值)。观察:

FITA目标评分

当然,我指的是FITA度量标准评分,如上图所示。如果仔细观察,您可能会看到最里面的环,它是一条淡淡的虚线,其分数未标记。那就是我所指的“ X”,但是除非您争夺奖金,否则您不必理会。

挑战

创建一个函数(或完整程序,如果该语言不支持该函数),则接收一个完美的正方形图像作为输入(或图像文件名,如果需要的话),其中包含一定数量的绿色(十六进制#00FF00,RGB(0, 255,0))点的大小,并返回分数。图像中可能包含绿点以外的数据,但绿色始终是完全相同的阴影。

您可能会想像正方形图像代表目标脸,最外面的环在4个点(顶部中心,底部中心,右中心,左中心)接触。所表示的目标面部将始终具有相同的比例,所有环的宽度都恰好是输入目标图像宽度的1/20。例如,给定输入尺寸为400px x 400px的输入图像,您可以假定每个环的内部宽度均为20px,如下所示:

脾气暴躁的例子图

澄清说明

  • 如果触摸两个单独的环,则计算两个环中的较高者
  • 您无需自动解决未命中或“ x”的情况,除非尝试获得奖金
  • 您可以假设没有绿色圆圈重叠
  • 您还可以假设图像中没有其他那种绿色阴影的像素
  • 图片将采用PNG,JPEG或PPM格式(您可以选择)
  • 如果在发布此问题之前进行创作,则允许使用外部图像处理库
  • 您可以假设一个目标上的所有绿色圆圈的直径相同
  • 如果拍摄(哈哈)重叠的圆圈奖励,则可以假设图像中至少一个圆圈没有另一个重叠的圆圈
  • 不允许出现标准漏洞

测试用例

以下两种情况应分别获得52分(或在奖金为52分时有1个“ x”和1个未中):

最后一个测试用例应得分25

奖金

  • 如果还返回未命中数(在任何环之外),则为-25个字节
  • 如果您还返回Xs的量,则为-30个字节(假设最里面的x是图像宽度的3/100,然后10是图像宽度的2/100。1-9的比例保持不变)
  • 如果您考虑重叠的圆圈,则字节计数为-35%

这是代码高尔夫球,因此最少的字节获胜。玩得开心!


“ 30个箭头末端有3个箭头,总共30个箭头”?那不是90箭吗?
DavidC 2014年

@DavidCarraher我在发布时意识到这一点。已更正
globby 2014年

我们可以使用哪些图像格式?PNG?PPM?我们自己的自定义格式?(我假设是前两个,但不是第三个,只是为了澄清。)
门把手

为了简单起见,我们只说JPEG或PNG @Doorknob冰
globby 2014年

1
我认为最难的奖励是奖励最少的奖励。
贾斯汀2014年

Answers:


4

处理2,448-25 = 423字节

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

读取图像文件f循环遍历像素,直到找到绿色,然后泛洪填充圆圈,确定最靠近中心的点。然后将该分数加到总计中。如果分数为负,则将其添加到未命中计数器。

程序将输出2个数字,第一个是分数,第二个是未命中数。

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

你可以在这里得到处理


4

Perl 5 + GD:225-25 = 200

编辑:找到索引的PNG中像素读取错误的原因,并应用了解决方法。 出于某种原因,GD库将绿色像素值读取为(4,254,4)。我不确定这是否特定于问题中包含的PNG文件。换行符可以在下面的代码中删除。

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

在输入上拍摄PNG图像并打印2个值:点数和未命中数。例如:

perl arch.pl <arch52.png
52 1

最后一刻更改:

无论如何,在真彩色模式下,我需要使用getPixelfill所使用的颜色索引,它们只是整数编码的RGB值,因此无需使用rgbcolorAllocate在这些索引之间来回转换。

说明:

  • 生成所有像素坐标的列表(以空格分隔的整数对)。
  • 按潜在得分排序(使用sub v它会$_缩短参数,而不是标准参数)。
  • 对于从最高得分像素开始的每个像素,如果它是绿色,则将其添加到结果中,然后将其位置填充为黑色。

不是图像,而是图像。@ bublou's答案正确将颜色读取为#00FF00
globby 2014年

@globby我知道图像中的颜色是正确的(我使用图像编辑软件检查过),但是也许也有相同的元信息来修剪颜色空间。
nutki 2014年

可能的。不过这很奇怪
globby 2014年

3

Haskell- 579-25 = 554603-25-30 576-25-30 = 521字节

战略:

  • 列出所有像素的(d,x,y)三元组列表(d是到中心的距离)
  • 按距离对列表进行排序
  • 从最大距离开始:如果像素是一个小邻域中唯一的绿色像素,则将其距离保持在列表L中,否则将其变黑
  • 从距离列表L计算分数

输出一个三倍(分数,缺失,Xs),例如(52,1,1)用于测试图像。

如果最接近中心的一个圆的像素在另一个圆的3个像素以内,则程序可能会失败。

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

提示:all id与。技巧相同and,您也可以j使用图案卫士来实现j n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
骄傲的haskeller 2015年

@proudhaskeller:是的,谢谢!
nimi 2015年

2

Mathematica- 371386-25 = 361

更好的解决方案。计算答案的速度比我的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}&

带有PIL的Python-琐碎且非最佳的解决方案,961字节

这仅仅是为了试图证明解决问题的愚蠢方法。 在我的系统上,运行前两个测试用例需要大约2分钟的时间,而运行第三个测试用例则需要20分钟的时间,这是因为它组成迅速,耗费大量资源并且在算法上令人反感地复杂。尽管如此,它确实可以满足要求,尽管当然不能最佳地打高尔夫球。图像上的绿色越多,运行时间就越长。

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

拍摄一个PIL图像对象,并返回分数。

所需步骤:

  1. 隔离绿色圆圈(效率低下)
    • 查找某个像素的所有邻居n,如果有的是绿色像素,则将其添加到圆圈中
    • 通过滤除具有8个相邻像素的像素来确定粗略轮廓
  2. 绘制目标表示
    • 创建一个空白画布
    • 绘制独特的彩色背景(易于实现的遗漏)
    • 用独特的颜色绘制嵌套的椭圆
  3. 通过确定将在圆下方的目标颜色,确定每个圆所在的计分区域
  4. 选择得分较高的区域(如果有多个),并将分数添加到总分中
  5. 返回总数

您的Python函数a可以写为a=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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.