รหัสกะทัดรัดที่สุดสำหรับการระเบิดจำลอง


13

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

มีคนเขียนโปรแกรมระบบอนุภาคอย่างง่ายที่นี่ในฐานะร่างการประมวลผลและมันค่อนข้างหนักเมื่อเทียบกับสิ่งที่ฉันคิดว่าคนอื่นควรจะประสบความสำเร็จหากพวกเขาพยายาม แต่ฉันจะต้องประทับใจมากขึ้นถ้ามีคนทำเช่นเดียวกันใน c ++ และ sdl หรือแม้แต่ java หรือ c #


2
"Lines of code" เป็นตัวชี้วัดที่เปิดความคลุมเครือจำนวนมากและแน่นอนว่าไม่ใช่ [code-golf] ซึ่งเป็น "จำนวนตัวอักษร" หรือบางครั้ง "จำนวนไบต์" การอภิปรายที่เกี่ยวข้องกับเมตา
dmckee --- ผู้ดูแลอดีตแมว

4
BTW - ปัญหาที่ผมยกขึ้นข้างต้นและสเปคค่อนข้างสมบูรณ์เป็นสิ่งที่จะได้รับการตอกประโยชน์ออกโดยการอภิปรายนี้ล่วงหน้าในการแชทปริศนา LabหรือSandbox ในเมตา แต่ไม่ว่าในกรณีใดยินดีต้อนรับสู่ CodeGolf.SE
dmckee --- ผู้ดูแลอดีตลูกแมว

อัปเดตคำถามแทนที่ LOC ด้วยจำนวนอักขระ
Todd Hopkinson

1
ใช่ถ้าคุณเขียน C / C ++ / Java / อนุพันธ์ C ใด ๆ คุณสามารถเขียนระบบปฏิบัติการทั้งหมดใน 1 บรรทัดของรหัส
Nate Koppenhaver

ที่เกี่ยวข้อง: stackoverflow.com/questions/1947031/…
gnibbler

คำตอบ:


13

Python 245 ตัวอักษร

import random,time
R=lambda:random.randrange(-999,999)/1e3
P=[(40+20j,R()+1j*R())for i in' '*20]
for i in' '*20:
 C=([' ']*80+['\n'])*40
 for p,v in P:C[int(p.real)+81*int(p.imag)]='*'
 print''.join(C);P=[(p+v,v*.95)for p,v in P];time.sleep(.1)

มันไม่ใช่การระเบิดที่เล็มมิ่ง แต่แน่นอนว่า +1 สำหรับความกะทัดรัด!
Todd Hopkinson

10

C #, WPF - 1523

ไม่ร้ายแรงมาก นี่เป็นความพยายามส่วนใหญ่ไม่ว่าจะใช้งานได้จริงหรือไม่

สิ่งที่ฉันทำที่นี่คือการใช้ ItemsControl (เมนูเนื่องจากสั้นกว่า) ใน WPF เพื่อแสดงอนุภาคผ่านการเชื่อมโยงข้อมูลและการสร้างเทมเพลต เทมเพลตข้อมูลควบคุมลักษณะที่ปรากฏของอนุภาค (ในกรณีนี้คือวงกลมที่เรียบง่าย) และการเชื่อมข้อมูลจะควบคุมสีและตำแหน่งของอนุภาค

แต่ละอนุภาคมีตำแหน่งสีและทิศทางที่ได้รับการอัปเดตโดยตัวจับเวลา เริ่มแรกมีการสร้างอนุภาคจำนวนมากที่กึ่งกลางของหน้าต่างโดยมีทิศทางแบบสุ่ม (กระจายแบบปกติ) การรวบรวมนั้นจะเชื่อมโยงข้อมูลกับ ItemsControl ซึ่งจะจัดการแสดงอนุภาคโดยอัตโนมัติทุกครั้งที่มีการอัพเดตคุณสมบัติ อนุภาคถูกลากลงมาเล็กน้อยเนื่องจากแรงโน้มถ่วง

มันมีความยาวเล็กน้อยเป็นที่ยอมรับ แต่อย่างน้อยมันก็ดูดี:

ป้อนคำอธิบายรูปภาพที่นี่

มันสามารถทำให้สั้นลงได้โดยไม่ต้อง:

  • แรงโน้มถ่วงทำให้อนุภาคขยายตัวทุกด้านอย่างสม่ำเสมอ
  • การแจกแจงแบบปกติสำหรับเวกเตอร์เริ่มต้นทำให้อนุภาคขยายตัวในช่องว่าง»กล่อง«;
  • การแปรผันของความสว่างทำให้อนุภาคเป็นสีดำ

ฉันเลือกที่จะไม่ทำเช่นนั้นเพื่อผลประโยชน์ของสุนทรียภาพ วิธีนี้มีความยาวมากกว่าเกือบทุกอย่างโดยไม่คำนึงถึง วิธีการผูกข้อมูลและการสร้างเทมเพลตอาจดูดี แต่ก็ค่อนข้างละเอียดเมื่อเปรียบเทียบกับการอัพเดตบิตแมป (หมายเหตุ: ฉันได้รับมันถึง 1, 1356โดยทิ้งทั้งหมดข้างต้น แต่มันก็ดูน่ากลัวแล้ว)

รหัสมีการแจกจ่ายในสามไฟล์ซึ่งได้รับที่นี่ในรูปแบบที่จัดรูปแบบเพื่อความชัดเจน:

app.xaml

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" StartupUri="W.xaml"/>

W.xaml

<Window x:Class="W" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Menu Name="i">
        <Menu.ItemTemplate>
            <DataTemplate>
                <Ellipse Width="2" Height="2" Fill="#000" Opacity="{Binding O}">
                    <Ellipse.RenderTransform>
                        <TranslateTransform X="{Binding X}" Y="{Binding Y}"/>
                    </Ellipse.RenderTransform>
                </Ellipse>
            </DataTemplate>
        </Menu.ItemTemplate>
        <Menu.Template>
            <ControlTemplate>
                <ItemsPresenter/>
            </ControlTemplate>
        </Menu.Template>
        <Menu.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </Menu.ItemsPanel>
    </Menu>
</Window>

W.xaml.cs

using M = System.Math;
using T = System.Timers.Timer;
using System;
using System.ComponentModel;

partial class W
{
    int a;
    T t = new T(99);

    public W()
    {
        InitializeComponent();
        Height = Width = 500;
        var r = new Random();
        Func<double> n = () => 2 * (M.Sqrt(-2 * M.Log(r.NextDouble())) * M.Sin(6 * r.NextDouble()));
        var l = new System.Collections.Generic.List<P>();
        for (; a++ < 300; )
            l.Add(new P { X = 250, Y = 250, f = n(), g = n() });
        i.ItemsSource = l;
        t.Elapsed += delegate
        {
            foreach (P x in l)
            {
                x.X += x.f;
                x.Y += x.g += .2;
                x.O = M.Max(1 - M.Sqrt(M.Pow(250 - x.X, 2) + M.Pow(250 - x.Y, 2)) / 250, 0);
            }
        };
        t.Start();
    }
}

class P : System.Windows.ContentElement, INotifyPropertyChanged
{
    public double y, f, g;
    public double X { get; set; }
    public double O { get; set; }
    public double Y
    {
        get { return y; }
        set
        {
            y = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(""));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

1
+1 ตัวอย่างที่ดูดี! เหมือนสมัยโบราณที่ระเบิดไปหลายวัน และฉันคิดว่านี่จะเป็นรหัสการประมวลผลในคำถามเริ่มต้น
Todd Hopkinson

@icnivad: ฉันต้องยอมรับว่าร่างการประมวลผล (ฉันดูที่ผลลัพธ์สุดท้ายเท่านั้นไม่ใช่รหัส) เป็นแรงบันดาลใจในการมอง
Joey

Gah! ตอนนี้ฉันหยุดตีกอล์ฟแล้ว ตอนนี้มีเทคนิคที่ดีอยู่แล้ว (เช่น PropertyChanged สำหรับคุณสมบัติทั้งหมดและเฉพาะในรายการสุดท้ายที่ตั้งค่าไว้) เนื่องจากฉันเริ่มต้นจากตัวละคร 2000 ตัวฉันเดาว่าการลด 500-char จะไม่เลวร้ายนัก ตอนนี้มันก็ค่อนข้างช้าด้วย DispatcherTimer ทำงานได้ดีกว่า Timer แต่มีความยาวกว่า ฉันอาจถูกล่อลวงให้ย้ายสิ่งนี้ไปยัง Silverlight และเรียกใช้บนโทรศัพท์ของฉัน
Joey

ฉันคิดว่านี่เป็นสิ่งที่ต้องเอาชนะสำหรับการรวมขนาดรหัสและคุณภาพความสวยงามของการระเบิด
Todd Hopkinson

icnivad: ฉันจะเขียนสิ่งใหม่ทั้งหมดลงบนบิตแมปโดยตรงในภายหลัง ควรสั้นกว่านี้มาก 45% ของรหัสคือ XAML ส่วนใหญ่ของรหัสจะสามารถผูกองค์ประกอบ UI กับคุณสมบัติของอนุภาค เพิ่มไปที่ verbosity ทั่วไปของ C # และเป็นวิธี verbose มากกว่าที่มันจะต้องมี
Joey

7

postscript - 287 244 ตัวอักษร

currentpagedevice/q{exch def}def/PageSize get/z{dup 3 1 roll add exch 4 2 roll}def{2
div}forall/y/r{rand 2 27 exp div 8 sub}def q/x q[99{[x r y r]}repeat]50{dup{aload/t q
3 index 2 index 4 4 rectfill 1 sub z z t astore pop}forall showpage}repeat

ทำงานด้วย gs -dNOPAUSE asplode.ps

คุณสามารถพิมพ์ออกมาและสร้างฟลิปบุ๊คได้


ยอดเยี่ยม! มันสวย!
ผู้ใช้ไม่ทราบ

5

Javascript - 268 ตัวอักษร

นี่คือ 1 มิติ 2 อนุภาคการระเบิด:

javascript:d=document;c=d.createElement('canvas');d.body.appendChild(c);g=c.getContext("2d");function e(x,y,m){g.arc(x,y,m,0,2*Math.PI,false);g.fill()}function s(a,b,v,t){c.width=c.width;e(50+t*v,50,b);e(50+t*b*v/(b-a),50,a-b);setTimeout(function(){s(a,b,v,t+1)},100)};s(9,5,1,0)

หากต้องการเรียกใช้ให้เปิดหน้า about: blank ในเว็บเบราว์เซอร์ที่ดีวางลงในแถบ url แล้วกด Enter s(10,5,1,0)คุณสามารถปรับเปลี่ยนการระเบิดโดยการแก้ไขค่าในตอนท้ายใน ค่าแรกคือขนาดของอนุภาคที่ระเบิด ค่าที่สองคือขนาดของอนุภาคที่ระเบิดออกมา ค่าที่สามคือความเร็วของอนุภาคที่ระเบิดออกมา ปล่อย '0' ไว้ตามเดิม


1
สิ่งนี้ไม่ทำงานใน Safari 5.0.5 (แสดงบางอย่างที่ดูเหมือนเบสบอลค้างคาว) หรือใน Chrome 11.0.696.68 (แสดงลูกบอลสองลูกลูกหนึ่งใหญ่กว่าอีกลูกเล็กน้อยแยกจากกัน)
marinus

1
@marinus สิ่งที่เกิดขึ้นใน Chrome คือสิ่งที่ควรจะเกิดขึ้น
david4dev

ไม่สามารถทำให้มันทำงานบน FF4, IE8 ได้ :(
st0le

ฉันทดสอบบน Firefox 4.0.1 และ Chromium 11.0.696.65 แล้ว ทำให้คุณคัดลอกสคริปต์ทั้งหมด - ฉันพบว่ามันง่ายที่จะพลาดวงเล็บสุดท้ายเมื่อคัดลอก
david4dev

@ st0le IE8 ไม่รองรับแท็กผ้าใบยกเว้นว่าคุณจะเล่นกลสกปรก: stackoverflow.com/questions/1332501/…
Cristian Lupascu

4

APL ( 120 118)

มันมีเอาท์พุทแบบเดียวกับรายการ Python (นั่นคือมันเป็นเพียงแค่แสดงผลสถานะบนกริดอักขระ) เฉพาะกริดคือ 30x15 และกำเนิดของอนุภาคอยู่ที่ 15x7

⍎⊃,⌿(9⍴⊂'(⎕DL.1)⊢{{(A+2↑⍵),0.95×A←2↓⍵}¨⍵⊣⎕←'' ⍟''[1+(⍳15 30)∊2↑¨⌊⍵]}'),⊂',⌿⍉10 4⍴⍎''⍬'',420⍴'',(7 15,.01×99-?2⍴199)'''

2

JavaScript 502 500 496

นี่เป็นการรวมกันของคำตอบของJoeyและdavid4dev (เป็นสำเนาที่ไร้ยางอายของอัลกอริทึมของ Joey ที่ใช้งานโดยใช้ Javascript / canvas ☺):

W=500;H=250;function r(){return 2*m.sqrt(-2*m.log(m.random()))*m.sin(6*m.random())}function n(){z=[];for(i=W;i;i--){s={};s.x=s.y=H;s.f=r();s.g=r();z.push(s)}}function w(){x.clearRect(0,0,W,W);z.forEach(function(a){a.x+=a.f;a.y+=a.g+=.2;x.fillStyle="rgba(0,0,0,"+m.max(1-m.sqrt(m.pow(H-a.x,2)+m.pow(H-a.y,2))/H,0)+")";x.fillRect(a.x,a.y,2,2)})}z=[];m=Math;d=document;c=d.createElement("canvas");c.width=c.height=W;d.body.appendChild(c);x=c.getContext("2d");n();setInterval(n,2e3);setInterval(w,10)

ตัวอย่าง JSFiddle: http://jsfiddle.net/GVqFr/60/ (คุณสามารถกดปุ่ม TidyUp เพื่อจัดรูปแบบโค้ดได้อย่างสวยงาม)


@Qqwy ขอบคุณสำหรับการแก้ไข!
Cristian Lupascu

ฉันไม่ใช่ผู้เชี่ยวชาญจาวาสคริปต์ แต่คุณใช้ค่าคง500ที่มากมาย หากคุณสามารถกำหนดตัวแปรทั่วโลกa=500คุณสามารถบันทึกตัวอักษรไม่กี่โดยการแทนที่ทั้งหมดด้วย500 a
Mr. Llama

@GigaWatt คุณพูดถูก ที่ทำงานให้250เช่นกัน
Cristian Lupascu

1

Bash 380

C="4443311177"
t=".-xxXMXxx-."
alias c='echo -e "\e[2J"'
g(){
echo -e "\e[1;$4\e[$2;$1H$3"
}
f(){
x=$1
y=$2
p=$((2-RANDOM%5))
q=$((2-RANDOM%5))
for i in {-5..5}
do
x=$((x+p))
y=$((y+q))
n=$((5+i))
c=$((5+i))
g $x $y ${t:n:1} 3${C:c:1}m 
w=$(printf "%04i\n" $((5*i*i)))
sleep ${w/0/0.}
g $x $y " " 3${C:c:1}m
done
}
e(){
c
for i in {1..10}
do
f $((COLUMNS/2)) $((LINES/2)) &
done
}

โทรเหมือนระเบิด

ปรับปรุง: colorized

t = text, c = cls, g = gotoxy, f = fly, C = COLOR


1

C กับ SDL, 423 ตัวอักษร

เนื่องจากคำอธิบายปัญหาดั้งเดิมกล่าวถึง SDL อย่างชัดเจนฉันรู้สึกว่าเป็นเวลาที่ผ่านมาที่มีการส่งวิธีแก้ปัญหา SDL น่าเสียดายที่ชื่อของฟังก์ชั่น SDL และโครงสร้างไม่ได้เป็นคำย่อดังนั้นโปรแกรมนี้จึงค่อนข้างยาว #includeในความเป็นจริงผมไม่สามารถแม้แต่จะปล่อยออกมา

#include<math.h>
#include"SDL.h"
SDL_Surface*s;SDL_Event e;SDL_Rect p;int i,n;double q[256];main(){
SDL_Init(SDL_INIT_VIDEO);s=SDL_SetVideoMode(320,320,32,0);
for(srand(time(0));e.type-SDL_QUIT;n=-~n%64){
for(i=256*!n;i;q[--i]=rand()%65536*9.5874e-5);
for(SDL_FillRect(s,0,i=0);++i<256;SDL_FillRect(s,&p,-n*67372036))
p.x=160+cos(q[i])*q[i-1]*n,p.y=160+sin(q[i])*q[i-1]*n,p.w=p.h=1;
SDL_Flip(s);SDL_Delay(50);SDL_PollEvent(&e);}}

(เนื่องจากรหัสมีขนาดใหญ่มากฉันจึงเหลือบิตพิเศษบางอย่างเพื่อให้คอมไพล์โดยไม่มีคำเตือนฉันคิดถึงการรวบรวมโดยไม่มีคำเตือนบางครั้งการลบออกจะประหยัดได้ประมาณ 30 ตัวอักษร)

อนิเมชั่นทำงานในวงวนไม่สิ้นสุด ปิดหน้าต่างเพื่อออกจากโปรแกรม การระเบิดแต่ละครั้งใช้อนุภาคสุ่มชุดใหม่

ฉันต้องการจะชี้ให้เห็นตัวเลข67372036ในรหัส SDL_FillRect()มันจะปรากฏขึ้นในการแสดงออกสำหรับอาร์กิวเมนต์สุดท้ายในสายที่สองไป เมื่อรหัสย่อลงการระเบิดจะแสดงเป็นสีเทาทั้งหมด การเปลี่ยนหมายเลขนี้เล็กน้อยจะเพิ่มเอฟเฟกต์สีที่ละเอียดอ่อน แต่น่าพึงใจสำหรับการระเบิด จำนวน67372032สีจะมีอนุภาคที่จุดเริ่มต้นของการระเบิดในขณะที่จำนวนนั้น67372034จะให้เอฟเฟกต์สีเมื่อมันหายไปในตอนท้าย ตัวเลขอื่น ๆ สามารถสร้างเอฟเฟกต์ขี่จักรยานสีที่ละเอียดน้อยลง ฉันแนะนำให้คุณลองใช้ดู


1

หลังจากได้เห็นตัวอย่างที่ยอดเยี่ยมอื่น ๆ ที่นี่ฉันตัดสินใจที่จะไปและทำฟังก์ชั่นอนุภาคที่เหมาะกับ140byt.es

Javascript, 282 ตัวอักษร

( ฟังก์ชั่นอนุภาค138ตัวและ150ตัวอักษรพื้นฐานสำหรับการวาดภาพผ้าใบ)

p=function(a,t,x,y,n,g,s,i,d){with(Math)for(i=n;i--;d=cos(i*sin(i*s)),a.globalAlpha=n/t/i,a.fillRect(x+t*sin(i)*d, y+t*cos(i)*d+t*g,2,2));};d=document;a=d.body.appendChild(d.createElement('canvas')).getContext('2d');t=setInterval("a.clearRect(0,0,300,150);p(a,t++, 50,50,1e3,.2,1)")

ตัวอย่าง Live JSFiddle ที่นี่

ด้วยการทำให้โค้ดเต็มขั้นตอนฉันไม่ต้องการรหัสหรือการกำหนดออบเจ็กต์อีกต่อไปทำให้ลดขนาดลงได้มาก การสร้างเอฟเฟ็กต์ตามขั้นตอนยังมีผลข้างเคียงอื่น ๆ อีกด้วย

รหัสอาจมีขนาดเล็กลงโดย ommitting Gravity, เมล็ด, จำนวนอนุภาค ฯลฯ แต่ฉันคิดว่าคุณสมบัติเหล่านี้ดีเกินกว่าที่จะลบ;)

คุณสมบัติ

  • กำหนดจุดศูนย์กลาง X, Y ของการระเบิดได้
  • จำนวนอนุภาคที่กำหนดได้
  • แรงโน้มถ่วงในทิศทางแนวตั้ง: ทำให้อนุภาคของคุณหล่นลงมาหรือลอยขึ้นมา!
  • เมล็ดแต่ละเมล็ดมีการระเบิดของตัวเองและจะแสดงให้เห็นว่าการระเบิดแต่ละครั้งผ่านคอมพิวเตอร์
  • Slowmotion, กรอเดินหน้าอย่างเร็วและการเล่นการระเบิดด้านหลังเป็นไปได้ทั้งหมดเนื่องจากวิธีการสร้างเอฟเฟกต์
  • ขนาด: 138 ไบต์

ตรวจสอบด้วย GitHubสำหรับรุ่นที่มีคำอธิบายประกอบ


0

Python กับ PyGame 240 ตัวอักษร

ฉันรู้ว่ามีวิธีแก้ปัญหาใน python อยู่แล้ว แต่เนื่องจากมีเพียงตัวละครที่พิมพ์ออกมาฉันคิดว่ามันจะคุ้มค่าที่จะสร้างเป็นแอนิเมชั่นที่ดี

Ungolfed สิ่งที่ฉันเริ่มต้นด้วย:

import math
import random
import pygame
pygame.init()

screen = pygame.display.set_mode((800, 800))
particles = [(random.gauss(0,.5), random.uniform(0,6.28318)) for i in range(2000)]

for i in range(399):
    screen.fill((255,255,255))
    for speed, angle in particles:
        distance = i * speed
        x = 400 + distance * math.cos(angle)
        y = 400 + distance * math.sin(angle)
        screen.set_at((int(x), int(y)), (0,0,0))
    pygame.display.flip()

หลังจากแฮ็คมาก เต็มหน้าจอเพื่อบันทึกอักขระบางตัว ไม่ใช้เสียงหรือแบบอักษรดังนั้นฉันคิดว่าinit()ไม่จำเป็น (ใช้ได้กับฉัน)

import math as m,random,pygame
d,x,g=pygame.display,range(999),random.gauss
s,e=d.set_mode(),[(g(0,.2),g(0,9))for i in x]
for i in x:
 d.flip(),s.fill([255]*3)
 for v,a in e:
        y=400+i*v*m.cos(a),400+i*v*m.sin(a)
        s.set_at(map(int,y),[0]*3)

0

Python - 327 ตัวอักษร

สิ่งที่น่าสนใจ:

  • ใช้จำนวนเชิงซ้อนเป็นเวกเตอร์ 2D
  • (v * cos(a), v * sin(a)) ดำเนินการเป็น v*e**(1j*a)
  • ดูเหมือนว่าการระเบิด 3 มิติ
  • แรงดึงดูด

.

import pygame as P,random as R,math
R=R.random
D=P.display
D.init()
W=800
S=D.set_mode((W,W))
T=P.time.Clock()
C=lambda v:map(int,(v.real,v.imag))
X=[(8+R())*math.cos(R()*1.57)*2.7**(1j*R()*6.28) for i in range(999)]
for t in range(250):
 D.flip();T.tick(30);S.fill(2**24-1)
 for v in X:S.set_at(C(v*t+.005j*t*t+W/2*(1+1j)),0)

0

dwitter 112

c.width^=0
t?o.push({X:1e3,Y:500,U:S(99*t),V:C(9*t)}):o=[]
o.map(a=>{a.X+=a.U,a.Y+=a.V,x.fillRect(a.X,a.Y,9,9)})

ลองใช้โดยการคัดลอก / วางรหัสไปยัง dwitter.net


เมื่อภาษาโพสต์วันที่ความท้าทายที่คุณควรจะทำเครื่องหมายว่าไม่แข่งขัน
fəˈnɛtɪk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.