10, 10, 10 ... ฉันหวังหรือไม่


15

คำนำ

เมื่อก่อนฉันยิงธนู 900 รอบในวันนี้ (10 จบที่ 6 ลูกศรสิ้นสุดและ 10 จบที่ 3 ลูกศรต่อท้ายรวม 90 ลูกศรและคะแนนสูงสุด 900) ฉันคิดว่าความท้าทายนี้

ในการยิงธนู (สมมติว่าคุณกำลังยิงบนหน้าเป้าหมายของ FITA ที่ให้มา[ชิ้นส่วนของกระดาษที่คุณยิง]) สำหรับลูกศรแต่ละลูกคุณสามารถรับคะแนนสูงสุดได้ 10 คะแนนใบหน้าเป้าหมายมี 10 หรือ 11 วงแหวนที่มีเส้นผ่านศูนย์กลางลดลง ซ้อนอยู่ภายในซึ่งกันและกัน จากวงในออกไปด้านนอกสิ่งเหล่านี้นับจาก 10 คะแนนไปจนถึงจุดหนึ่ง (และในกรณีที่มี 11 วงมีวงแหวนชั้นในสุดที่สองซึ่งนับเป็น 'X' ซึ่งทำคะแนนได้เท่ากับ 10 แต่ถูกใช้ในกรณีแตก มูลค่าที่สูงขึ้น) สังเกต:

การให้คะแนนเป้าหมาย FITA

แน่นอนฉันหมายถึงเกณฑ์การให้คะแนน FITA ตามที่เห็นในภาพประกอบด้านบน หากคุณมองอย่างใกล้ชิดคุณอาจสังเกตแหวนวงในสุดซึ่งเป็นเส้นประจางซึ่งไม่มีคะแนน นั่นคือ 'X' ที่ฉันอ้างถึง แต่คุณจะไม่ต้องใส่ใจกับสิ่งนั้นเว้นแต่จะแข่งขันเพื่อรับโบนัส

ท้าทาย

สร้างฟังก์ชั่น (หรือโปรแกรมเต็มรูปแบบหากภาษาไม่รองรับฟังก์ชั่น) ที่ได้รับภาพสี่เหลี่ยมจัตุรัสที่สมบูรณ์แบบเป็นอินพุต (หรือชื่อไฟล์ภาพถ้าจำเป็น) ที่มีสีเขียวจำนวนหนึ่ง (HEX # 00FF00, RGB (0, 255, 0)) จุดที่มีขนาดบางและส่งคืนคะแนน รูปภาพอาจมีข้อมูลอื่นที่ไม่ใช่จุดสีเขียวแต่สีเขียวจะเป็นเฉดสีเดียวกันเสมอ

คุณอาจจินตนาการว่าภาพสี่เหลี่ยมจัตุรัสเป็นตัวแทนของใบหน้าเป้าหมายโดยวงแหวนด้านนอกสุดแตะที่ 4 จุด (กึ่งกลางด้านบนกลางด้านล่างตรงกลางด้านขวากลางซ้าย) ใบหน้าเป้าหมายที่แสดงจะมีสัดส่วนเท่ากันทุกครั้งที่วงแหวนทั้งหมดมีความกว้างเท่ากับ 1/20 ของความกว้างของภาพเป้าหมายที่ป้อนเข้า ตัวอย่างเช่นเมื่อกำหนดภาพอินพุตของขนาดอินพุต 400px คูณ 400px คุณอาจสมมติว่าวงแหวนแต่ละวงมีความกว้างด้านในเท่ากับ 20px ดังแสดงด้านล่าง:

ภาพประกอบตัวอย่างเส็งเคร็ง

ชี้แจง

  • หากสัมผัสแหวนสองวงแยกจะนับส่วนที่สูงกว่าของวงแหวนทั้งสอง
  • คุณไม่จำเป็นต้องอธิบายถึงการคิดถึงหรือกรณี 'x' โดยอัตโนมัติเว้นแต่จะลองรับโบนัส
  • คุณอาจคิดว่าไม่มีวงกลมสีเขียวซ้อนทับกัน
  • คุณอาจสมมติว่าไม่มีพิกเซลอื่นของเฉดสีเขียวนั้นในภาพ
  • รูปภาพจะอยู่ในรูปแบบ PNG, JPEG หรือ PPM (ตัวเลือกของคุณ)
  • อนุญาตให้ใช้ไลบรารีการประมวลผลภาพภายนอกหากเขียนก่อนโพสต์คำถามนี้
  • คุณอาจสมมติว่าวงกลมสีเขียวทั้งหมดในเป้าหมายเดียวจะมีเส้นผ่านศูนย์กลางเท่ากัน
  • หากการถ่ายภาพ (hah) สำหรับโบนัสวงกลมที่ทับซ้อนกันคุณอาจสันนิษฐานว่าอย่างน้อยหนึ่งวงกลมในภาพไม่มีการซ้อนทับอีก
  • ช่องโหว่มาตรฐานไม่ได้รับอนุญาต

กรณีทดสอบ

สองกรณีต่อไปนี้ควรแต่ละคะแนน52 (หรือในกรณีของโบนัส 52 กับ 1 'x' และ 1 พลาด):

และกรณีทดสอบสุดท้ายนี้ควรได้คะแนน25 :

โบนัส

  • -25 ไบต์ถ้าคุณส่งคืนจำนวนคิดถึง (นอกวงแหวนใด ๆ ) เช่นกัน
  • -30 ไบต์หากคุณส่งคืนจำนวน Xs ด้วย (สมมติว่าส่วนท้ายสุดของ x คือ 3 / 100th ของความกว้างของภาพและ 10 คือ 10/2 ของความกว้างของภาพสัดส่วนที่ 1-9 ยังคงไม่เปลี่ยนแปลง)
  • -35% ไบต์จะนับหากคุณนับรวมวงกลมที่ทับซ้อนกัน

นี่คือรหัสกอล์ฟดังนั้นไบต์ที่น้อยที่สุดจึงเป็นผู้ชนะ มีความสุข!


"30 จบที่ 3 ลูกศรสิ้นสุดสำหรับทั้งหมด 30 ลูกศร"? ไม่ควรเป็นลูกศร 90 อัน?
DavidC

@DavidCarraher ฉันรู้ว่าถูกต้องเมื่อฉันโพสต์ แก้ไขแล้ว
globby

รูปแบบภาพใดที่เราสามารถใช้ได้ PNG? PPM? รูปแบบที่กำหนดเองของเรา? (ฉันจะถือว่าสองคนแรก แต่ไม่ใช่คนที่สาม แต่เพื่อความกระจ่าง)
Doorknob

สมมติว่าเป็นเพียง JPEG หรือ PNG เพื่อความเรียบง่าย @Doorknob 冰
globby

1
ฉันคิดว่าโบนัสที่ยากที่สุดคือรางวัลที่น้อยที่สุด
Justin

คำตอบ:


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

อ่านในไฟล์รูปภาพเพื่อวนพิกเซลจนกว่าจะพบสีเขียวจากนั้นน้ำท่วมจะเติมวงกลมเพื่อหาจุดที่ใกล้กับศูนย์กลางมากที่สุด จากนั้นเพิ่มคะแนนนั้นเป็นผลรวม ถ้าคะแนนเป็นลบจะถูกเพิ่มเข้าไปในตัวนับพลาด

โปรแกรมจะแสดงผล 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

การเปลี่ยนแปลงในนาทีสุดท้าย:

ในโหมดสีจริงที่ฉันต้องการอย่างไรก็ตามดัชนีสีที่ใช้โดยgetPixelและfillเป็นเพียงค่า RGB ที่เข้ารหัสจำนวนเต็มดังนั้นไม่จำเป็นต้องใช้rgbและcolorAllocateเพื่อแปลงเป็นและจากดัชนีเหล่านั้น

คำอธิบาย:

  • สร้างรายการพิกัดพิกเซลทั้งหมด (เป็นช่องว่างคั่นคู่ของจำนวนเต็ม)
  • จัดเรียงตามคะแนนที่เป็นไปได้ (การใช้sub vซึ่งรับพารามิเตอร์ผ่าน$_แทนที่จะเป็นพารามิเตอร์มาตรฐานเนื่องจากสั้นกว่า)
  • สำหรับแต่ละพิกเซลเริ่มต้นจากคะแนนที่ให้คะแนนสูงสุดถ้าเป็นสีเขียวให้เพิ่มในผลลัพธ์

มันไม่ใช่ภาพ คำตอบของ @bubalou อ่านสีอย่างถูกต้องเป็น # 00FF00
globby

@ globby ฉันรู้ว่าสีถูกต้องในภาพ (ฉันตรวจสอบด้วยซอฟต์แวร์แก้ไขภาพ) แต่อาจมีข้อมูลเมตาเดียวกันเพื่อตัดพื้นที่สี
nutki

อาจ แม้ว่าจะเป็นเรื่องแปลก
globby

3

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

กลยุทธ์:

  • ทำรายการของ (d, x, y) อเนกประสงค์สำหรับพิกเซลทั้งหมด (d คือระยะทางจากศูนย์กลาง)
  • เรียงรายการตามระยะทาง
  • เริ่มต้นด้วยระยะทางที่ยิ่งใหญ่ที่สุด: ถ้าพิกเซลพิกเซลสีเขียวเพียงตัวเดียวในละแวกเล็ก ๆ ให้รักษาระยะห่างไว้ในรายการ L มิเช่นนั้นจะทำให้เป็นสีดำ
  • คำนวณคะแนนจากรายการระยะทาง L

เอาท์พุท ist สาม (คะแนน, พลาด, 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เหมือนกับ. andalso คุณสามารถนำไปใช้jกับยามรูปแบบได้j n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
ภูมิใจ haskeller

@proudhaskeller: ใช่ขอบคุณ!
nimi

2

Mathematica - 371 386 - 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}&

Python กับ PIL - โซลูชันที่ไม่สำคัญและไม่เหมาะสม 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.