10, 10, 10 ... Saya harap?

15

Kata pengantar

Ketika saya menembakkan sebuah panahan 900 putaran sebelumnya hari ini (10 berakhir dengan 6 panah per akhir, dan 10 berakhir pada 3 panah per akhir, dengan total 90 panah dan skor maksimum 900), saya memikirkan tantangan ini.

Dalam memanah (dengan asumsi bahwa Anda memotret pada wajah target yang disediakan FITA [selembar kertas yang Anda tembak]), untuk setiap panah Anda dapat mengklaim skor maksimum 10. Wajah target berisi 10 atau 11 cincin dengan diameter menurun, bersarang di dalam satu sama lain. Dari cincin dalam ke luar, ini dihitung dari 10 poin, ke satu titik (dan dalam kasus 11 cincin, ada cincin terdalam sekunder yang dihitung sebagai 'X', yang skornya 10 tetapi digunakan dalam kasus tie breaking sebagai nilai yang lebih tinggi). Mengamati:

Skor Target FITA

Tentu saja, saya mengacu pada penilaian Metrik FITA, seperti yang terlihat pada ilustrasi di atas. Jika Anda melihat lebih dekat, Anda dapat mengamati cincin terdalam, yang merupakan garis putus-putus pudar, yang nilainya tidak ditandai. Itu adalah 'X' yang saya maksudkan, tetapi Anda tidak perlu memperhatikan hal itu kecuali bersaing untuk mendapatkan bonus.

Tantangan

Buat fungsi (atau program lengkap, jika bahasa tidak mendukung fungsi), yang menerima gambar kuadrat sempurna sebagai input (atau nama file gambar, jika perlu), yang mengandung sejumlah warna hijau (HEX # 00FF00, RGB (0, 255, 0)) titik-titik dengan ukuran tertentu, dan mengembalikan skor. Gambar mungkin berisi data selain dari titik hijau , tetapi hijau akan selalu menjadi warna yang sama persis.

Anda dapat membayangkan bahwa gambar persegi mewakili wajah target, dengan cincin terluar menyentuh pada 4 titik (tengah atas, tengah bawah, tengah kanan, tengah kiri). Wajah target yang diwakili akan selalu memiliki proporsi yang sama, dengan semua cincin memiliki lebar tepat 1/20 dari lebar gambar target input. Sebagai contoh, diberikan gambar input dimensi input 400px oleh 400px, Anda dapat mengasumsikan bahwa setiap cincin memiliki lebar bagian dalam 20px, seperti diilustrasikan di bawah ini:

Contoh ilustrasi jelek

Klarifikasi

  • Jika menyentuh dua dering terpisah, semakin tinggi dari kedua dering itu dihitung
  • Anda tidak harus secara otomatis menghitung kesalahan atau kasus 'x', kecuali mencoba bonusnya
  • Anda dapat berasumsi bahwa tidak ada lingkaran hijau yang tumpang tindih
  • Anda juga dapat mengasumsikan bahwa tidak ada piksel lain dari naungan hijau di dalam gambar
  • Gambar akan dalam format PNG, JPEG atau PPM (pilihan Anda)
  • Pustaka pemrosesan gambar eksternal diizinkan, jika ditulis sebelum posting pertanyaan ini
  • Anda dapat mengasumsikan bahwa semua lingkaran hijau pada satu target akan memiliki diameter yang sama
  • Jika memotret (hah) untuk bonus lingkaran yang tumpang tindih, Anda dapat mengasumsikan bahwa setidaknya satu lingkaran pada gambar tidak memiliki tumpang tindih lainnya
  • Celah standar tidak diijinkan

Uji kasus

Dua kasus berikut harus masing-masing skor 52 (atau dalam kasus bonus, 52 dengan 1 'x' dan 1 kehilangan):

Dan test case terakhir ini harus skor 25 :

Bonus

  • -25 byte jika Anda juga mengembalikan jumlah kesalahan (di luar salah satu cincin) juga
  • -30 byte jika Anda juga mengembalikan jumlah Xs (anggap x paling dalam adalah 3/100 dari lebar gambar, dan 10 kemudian 2/100 dari lebar gambar. 1-9 proporsi tetap tidak berubah)
  • -35% jumlah byte jika Anda memperhitungkan lingkaran yang tumpang tindih

Ini adalah kode golf, sehingga byte paling kecil menang. Selamat bersenang-senang!

globby
sumber
"30 berakhir pada 3 panah ujung, dengan total 30 panah"? Bukankah seharusnya 90 panah?
DavidC
@ DavidVarraher Saya menyadari hal itu ketika saya memposting. Dikoreksi
globby
Format gambar apa yang bisa kita gunakan? PNG? PPM? Format khusus kami sendiri? (Saya akan menganggap dua yang pertama tetapi tidak yang ketiga, tetapi hanya untuk klarifikasi.)
Gagang Pintu
Katakanlah hanya JPEG atau PNG untuk kesederhanaan @Doorknob冰
globby
1
Saya pikir bonus yang paling sulit adalah bonus dengan hadiah paling sedikit.
Justin

Jawaban:

4

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

Membaca dalam file gambar untuk loop melalui piksel sampai menemukan hijau kemudian banjir mengisi lingkaran menentukan titik yang paling dekat dengan pusat. Kemudian tambahkan skor itu menjadi total. jika skornya negatif, itu ditambahkan ke miss counter.

Program akan menampilkan 2 angka, yang pertama adalah skor dan yang kedua adalah jumlah yang gagal.

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

Anda dapat memproses di sini

bubalou
sumber
4

Perl 5 + GD: 225 - 25 = 200

Sunting: Ditemukan alasan untuk pembacaan piksel yang salah dalam PNG yang diindeks dan menerapkan solusi. Untuk beberapa alasan dengan perpustakaan GD nilai-nilai piksel hijau dibaca sebagai (4,254,4). Saya tidak yakin apakah ini khusus untuk file PNG yang termasuk dalam pertanyaan. Jeda baris dapat dihapus dalam kode di bawah ini.

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

Mengambil gambar PNG pada input dan mencetak 2 nilai: Jumlah titik dan kesalahan. Sebagai contoh:

perl arch.pl <arch52.png
52 1

Perubahan menit terakhir:

Dalam mode true color yang saya butuhkan pula indeks warna yang digunakan oleh getPixel dan fillhanya integer nilai RGB yang dikodekan, jadi tidak perlu menggunakan rgbdancolorAllocate mengkonversi ke dan dari indeks tersebut.

Penjelasan:

  • Buat daftar semua koordinat piksel (sebagai pasangan bilangan bulat yang dipisahkan ruang).
  • Urutkan berdasarkan skor potensial (menggunakan sub v yang mengambil parameter melalui$_ bukannya parameter standar karena lebih pendek).
  • Untuk setiap piksel mulai dari skor penilaian tertinggi jika berwarna hijau, tambahkan hasilnya dan isi isinya hitam.
nutki
sumber
Bukan gambarnya; @ bubalou jawaban dengan benar membaca warna sebagai # 00FF00
globby
@globby Saya tahu warnanya benar dalam gambar (saya memeriksa dengan perangkat lunak pengeditan gambar), tapi mungkin ada juga informasi meta yang sama untuk memangkas ruang warna.
nutki
mungkin. Itu aneh
globby
3

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

Strategi:

  • Buat daftar tiga kali lipat (d, x, y) untuk semua piksel (d adalah jarak ke pusat)
  • urutkan daftar berdasarkan jarak
  • dimulai dengan jarak terjauh: jika piksel merupakan satu-satunya piksel hijau di lingkungan kecil, pertahankan jaraknya dalam daftar L, yang lain menghitamkannya
  • menghitung skor dari daftar jarak L

Output adalah triple (skor, misses, Xs), mis (52,1,1) untuk gambar uji.

Program mungkin gagal jika piksel lingkaran terdekat dengan pusat berada dalam 3 piksel lingkaran lain.

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
sumber
Kiat: all idsama dengan and.juga, Anda dapat menerapkan jdengan penjaga polaj n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
haskeller bangga
@proudhaskeller: Ya, terima kasih!
nimi
2

Mathematica - 371 386 - 25 = 361

Solusi yang lebih optimal. Menghitung jawabannya jauh lebih cepat daripada solusi Python saya.

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 with PIL - Solusi sepele dan tidak optimal, 961 byte

Ini hanya untuk mencoba menunjukkan pendekatan konyol dalam menyelesaikan masalah. Dibutuhkan ~ 2 menit untuk menjalankan dua uji kasus pertama, dan ~ 20 menit untuk menjalankan yang ketiga pada sistem saya karena cepat membuat, sangat intensif sumber daya, dan detektor lingkaran rumit algoritmik. Meskipun demikian, ia memenuhi persyaratan, meskipun tentu tidak golf secara optimal. Semakin banyak warna hijau pada gambar, semakin lama waktu yang dibutuhkan untuk menjalankannya.

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

Mengambil objek gambar PIL, dan mengembalikan skor.

Langkah-langkah yang dibutuhkan:

  1. Isolasi lingkaran hijau (tidak efisien)
    • Temukan semua tetangga beberapa piksel n , jika ada yang merupakan piksel hijau kemudian tambahkan mereka ke lingkaran
    • Tentukan garis besar kasar dengan memfilter piksel yang memiliki 8 tetangga
  2. Gambar representasi target
    • Buat kanvas kosong
    • Gambarlah latar belakang berwarna yang unik (mudah gagal diterapkan)
    • Gambar elips bersarang dengan warna unik
  3. Tentukan zona skor di mana setiap lingkaran berada dengan menentukan warna target yang akan berada di bawah lingkaran.
  4. Pilih yang lebih tinggi dari zona penilaian (jika banyak) dan tambahkan skor ke total
  5. Kembalikan total
globby
sumber
Fungsi Python Anda adapat ditulis sebagaia=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