앨리스와 밥은 싸움을


24
  • 앨리스 (A)와 밥 (B)은 전투를하기로 결정했습니다.
  • 각 전투원의 체력은 10입니다.
  • 그들은 6 면체 주사위를 굴려 피해를줍니다.
  • 그 피해는 상대의 건강에서 제거됩니다.
  • 결국 Alice 나 Bob은 적을 정복 할 것입니다.

전투가 어떻게 진행되었는지 보여주세요. 발생한 조치에 대해이 코드를 출력합니다.

공격

B a A    
^ Combatant
  ^ Action (attack)
    ^ Target

B r 4
^ Combatant
  ^ Action (roll)
    ^ Value

건강 변화

A h 6
^ Combatant
  ^ Attribute (health)
    ^ Value   

승리

A w 
^ Combatant
  ^ Action (win)

출력 예 :

A a B
A r 4
B h 6
B a A
B r 6
A h 4
A a B
A r 6
B h 0        
A w

규칙은 다음과 같습니다.

  • 모든 언어로 작성하십시오.
  • 다이의 단일 롤은 1, 2, 3, 4, 5 또는 6 중 하나의 결과를 낳을 확률이 동일해야합니다.
  • 앨리스는 항상 시작합니다 (밥은 구식으로 구식입니다).
  • 각 턴마다 액션을 출력합니다.
  • 당신은 공격, 롤, 손상 및 승리 행동을보고해야합니다.
  • 전투원은 대문자이며 행동은 소문자입니다.
  • 동일한 결과를 일관되게 생성해서는 안됩니다.
  • 출력 전투원, 행동 및 가치 사이에 공백 문자가 하나 이상 있어야합니다.
  • 승리 행동은 상대방의 체력이 0 이하일 때 발생합니다.
  • 작업의 모든 부분은 같은 줄에 있어야합니다.
  • 라인 당 하나의 조치가 있어야합니다.
  • 가장 적은 바이트가 이깁니다.

하세요!


9
Alice (A)와 Bob (B)이라는 이름은 네트워크 보안 클래스에 대한 플래시백을 제공합니다. 배우 앨리스 (A)는 키 등으로 밥 (B)에게 패킷을 보냅니다.
Magic Octopus Urn

21
@MagicOctopusUrn 그게 다야. 그들은 보통 의사 소통을 시도합니다. 의사 소통이 무너질 때 슬프게도 갈등이 종종 발생합니다.
AJFaraday

7
Mallory에서 우리의 비밀을 숨기는 방법을 알아 내려고했던 시절이 그리워요 ...
Bob

4
@Bob Mallory는 정말 산만하다. 조심해야 할 이브입니다.
AJFaraday

3
@ msh210 글쎄, 코드 골프의 중요한 세부 사항은 모두가 같은 도전을 받는다는 것입니다.하지만 여기에 논리가 있습니다. d 효과를 위해 롤한 다음 롤 결과를 구현합니다. 당신이 구르는 것을 아무도 모른다면 롤은 의미가 없습니다.
AJFaraday

답변:


5

05AB1E , 49 바이트

"BaABr0Aha"S3ô»D„AB‡[6LΩ©Tǝ¤H®-©16ǝ=®0‹#s]н…ÿ w?

온라인으로 사용해보십시오!

설명

"BaABr0Aha"                                        # push the initial state of B
           S                                       # split to list of characters
            3ô                                     # divide into 3 parts
              »                                    # join each part on space and all on nl
               D„AB‡                              # make a copy with A and B inverted
                     [                             # start a loop
                      6LΩ©                         # pick a random number in [1 ... 6]
                          Tǝ                       # insert at position 10 of the string
                            ¤H                     # get the last char of the string and
                                                   # convert from hex
                              ®-©                  # subtract the random number
                                 16ǝ=              # insert at position 16 and print
                                     ®0‹#          # if the hp is less than 0, break
                                         s         # swap the other string to the stack top
                                          ]        # end loop
                                           н…ÿ w?  # print the winner

13

파이썬 3 , 131 바이트

x,y="AB"
from random import*
X=Y=10
p=print
while X>0:p(x,"a",y);d=randint(1,6);p(x,"r",d);Y-=d;p(y,"h",Y);x,y,X,Y=y,x,Y,X
p(y,"w")

온라인으로 사용해보십시오!

officialaimm 덕분에 -8 바이트
ChooJeremy 덕분에 -2 바이트


5
미리 정의 p=print하면 약 8 바이트가 절약됩니다.
officialaimm

y는 항상이 시점에서이기므로 (그리고 루프에서 X 공격 만 나중에 Y로 교체 됨) y가 손실되었는지 확인할 필요가 없습니다. - ChooJeremy - 검토에서
NoOneIsHere

@NoOneIs 여기에 메시지를 전달해 주셔서 감사합니다. : D
HyperNeutrino

randint(1,6)id(X+Y)//3%6+1분포가 상당히 균일하지는 않지만 로 대체 될 수 있습니다 .
Vincent

@Vincent 규칙을 더 짧게 만드는 데 도움이되지 않으면 규칙을 구부리는 데 대한 요점을 보지 못합니다.
HyperNeutrino

7

C (gcc) , 146141 바이트

f(A,B,r,t,a,b){for(A=B=10;r=1+clock()%6,A*B>0;t=!t)printf("%c a %c\n%c r %u\n%c h %i\n",a=65+t,b=66-t,a,r,b,t?A-=r:(B-=r));printf("%c w",a);}

온라인으로 사용해보십시오!

골프 골프 :

f(A,B,r,t,a,b){
    for(A=B=10; //Initialize HP
        r=1+clock()%6, // Get the number of processor cycles the program has consumed. This is relatively random, so I call it good enough.
        A*B>0;t=!t) // Flip t for change of turns
        printf("%c a %c\n%c r %u\n%c h %i\n", // Print the turn
            a=65+t,b=65+!t,a,r,b, // 65 is ASCII for 'A', 66 for 'B'
            t?A-=r:(B-=r)); // Deduct the damage.
    printf("%c w",a); // Print the winner
}

2
a=65+t,b=66-t? 를 사용하여 바이트를 저장할 수 있습니까?
moopet

A*B>0몇 바이트를 절약 할 수 있습니다.
Olivier Grégoire

A*B더 많은 비용을 절약 할 수 있지만 서둘러 ATM에 있습니다. 저녁에 업데이트하겠습니다

주사위 seq {6,4,3,1,5}에서 버그를 발견했습니다. b 건강 -4로 승리합니다. 참조 TIO 나는이 버그를 시연하기 위해 주사위 계산기를 변경했습니다.
GPS

@GPS 감사합니다. 지금 패치하겠습니다.

7

파이썬 3 , 127 바이트

이것은 의견에 맞지 않는 @HyperNeutrino 답변 의 개선 사항입니다 . 아래 설명을 참조하십시오.

x,y="AB"
s=id(0)
X=Y=10
p=print
while X>0:p(x,"a",y);s=s**7%~-2**67;d=s%6+1;p(x,"r",d);Y-=d;p(y,"h",Y);x,y,X,Y=y,x,Y,X
p(y,"w")

온라인으로 사용해보십시오!


더 짧은 파이썬 주사위 굴림에 대한 서사적 퀘스트

TL; DR : RSA 암호화를 사용하여 표준 파이썬 주사위 롤에서 4 바이트를 면도 할 수 있습니다.

표준 파이썬 주사위 롤 ( 32 바이트 )이 약간 단축 될 수 있는지 확인하고 싶었습니다 .

from random import*;randint(1,6)

특히 id(x)비 결정적 가치를 프로그램에 도입하는 것이 매우 편리합니다. 내 생각은 어떻게 든 실제 임의성을 만들기 위해이 값을 해시하는 것이 었습니다. 나는 몇 가지 접근 방식을 시도했으며 그 중 하나는 RSA 암호화 입니다.

RSA 암호화는 단순하기 때문에 몇 바이트 만 필요합니다 m**e%n. 그런 다음 이전 값을 암호화하여 다음 임의의 값을 만들 수 있습니다. (e,n)키를 사용할 수 있다고 가정하면 주사위 롤을 22 바이트 로 쓸 수 있습니다 .

s=id(0);s=s**e%n;s%6+1

이는 유효한 RSA 키를 정의 할 약 10 바이트가 있음을 의미합니다. 나는 운이 좋았다. 실험하는 동안 Mersenne 프라임 M67 을 사용하여 나중에 Mersenne이 자신의 목록에 M67 을 포함 하여 실수 를 했다는 사실을 알게되었습니다 . 그것은의 산물로 밝혀 p=193707721q=761838257287. 모듈러스를 찾았습니다.

n=~-2**67

이제 지수와 차 마이클 (Charmichael) 계급공동 초과자가(p-1)*(q-1) 되어야합니다. 운 좋게도 n의 계류를 나누지 않는 첫 번째 소수는 길이가 한 자릿수입니다. 7. 그런 다음 28 바이트를 사용하여 주사위를 쓸 수 있습니다 .

s=id(0);s=s**7%~-2**67;s%6+1

M67의 한 가지 좋은 점 은 생성 된 임의 값에 66 비트가 있으며 이는 일반적인 64 비트 RNG보다 큽니다. 또한 RSA를 사용하면 현재 값을 여러 번 해독하여 시간을 되돌릴 수 있습니다. 암호화 및 해독 키는 다음과 같습니다.

Encryption: (7,                    147573952589676412927)
Decryption: (42163986236469842263, 147573952589676412927)

저는 통계 나 암호화 전문가가 아니므로이 RNG가 "좋은 무작위성"에 대한 기준을 검사하는지 여부를 실제로 알 수 없습니다. 다른 RNG를 사용하여 1-6 주사위 롤 발생의 표준 편차를 비교 하는 작은 벤치 마크 를 작성 했습니다 . 제안 된 솔루션이 다른 솔루션과 똑같이 작동하는 것 같습니다.


3
인상적인 작품! :)
HyperNeutrino


4

자바 (JDK 10) , 180 바이트

v->{var r="";int p=0,H[]={10,10},h=0;for(;H[0]*H[1]>0;)r+=r.format("%3$c a %4$c%n%3$c r %d%n%4$c h %d%n",h+=Math.random()*6-h+1,H[p]-=h,p+65,(p^=1)+65);return r+(char)(66-p)+" w";}

온라인으로 사용해보십시오!

크레딧


1
자바 10은 var? o.Ô 새로운 사양을 곧 조사해야합니다. 어쨌든 char-array를 int-array로 변경하여 4 바이트의 골프를하실 수 있습니다.v->{var r="";int P[]={65,66},p=0,H[]={10,10},h=0;for(;H[0]*H[1]>0;)r+=r.format("%3$c a %4$c%n%3$c r %d%n%4$c h %d%n",h+=Math.random()*6-h+1,H[p]-=h,P[p],P[p^=1]);return r+=P[p^1]+" w";}
Kevin Cruijssen

1
@ KevinCruijssen Yep, Java 10에는 var. 더 읽을 필요는 없습니다. 기본적으로 골퍼들에게 유용한 유일한 변경 사항입니다. 그리고 나는 당신이 제안하는 것을 할 수 없습니다 : 결과의 마지막 줄을 확인하십시오 : 65 w대신 A w. 그래서 나는 int ...진술 에서 그것을 추출한 이유 : 몇 바이트 골프 ;-)
Olivier Grégoire

1
@KevinCruijssen 나는 여기에 몇 가지 예를 썼습니다
Olivier Grégoire



3

루비 , 122120 96 92 91 바이트

f=->x=?A,y=?B,m=10,n=m{p [x,?a,y],[x,?r,r=1+rand(6)],[y,?h,t=n-r]
t<1?p([x,?w]):f[y,x,t,m]}

Asone Tuhid 덕분에 1 바이트를 절약했습니다 .

온라인으로 사용해보십시오!


1
더 이상 루비를
쓰는

"대안의 모든 부분이 같은 줄에 있어야합니다." 탭 문자를 사용하여 동일한 최적화를 수행 할 수 있습니까?
AJFaraday

@AJFaraday 형식으로 라인을 출력하는 것이 가능 ["A", "a", "B"]합니까? 그렇다면 96 바이트 솔루션이 있습니다.
Cristian Lupascu 12

그들이 한 줄에 하나씩 출력되면. 그렇게해야합니다.
AJFaraday

-1 바이트 당신은 대체하는 경우 ?(p [x,?w]):?p([x,?w]):
Asone Tuhid

3

자바 8, 230 바이트

v->{for(int h=104,a=h,x=0,y=1,A=10,B=A,r=0,t=0,T;a<119;)System.out.printf("%c %3$c %c%n",(x=a>h|A*B<1?x^1:x)+65,y=(a<98?t=r+=Math.random()*6-r+1:a>h?(T=x<1?A-=t:(B-=t))<0?0:T:A*B<1?-16:(x^1)+17)+48,a=a<98?114:a>h?104:A*B<1?119:97);}

참고 : Java 답변이 훨씬 짧으므로 그의 투표를 높이십시오 ! 그러나 완전히 다른 접근법을 사용하므로 게시 할 가치가 있다고 생각했습니다.

설명:

온라인으로 사용해보십시오.

v->{                     // Method with empty unused parameter and no return-type
  for(int h=104,         //  Temp integer with unicode for 'h' to save bytes
          a=h,           //  Second part (Action)
          x=0,           //  First part
          y=1,           //  Third part
          A=10,          //  Score player A, starting at 10
          B=A,           //  Score player B, starting at 10
          r=0,           //  Random dice-roll
          t=0,           //  Previous dice-roll
          T;             //  Temp integer
      a<119;)            //  Loop until there is a winner
     System.out.printf(  //   Print
      "%c %3$c %c,%n",   //    The three parts with spaces, and a new-line
      (x=                //    First part:
         a>h             //     If the previous action is 'r',
         |A*B<1?         //     or there is a winner:
           x^1           //      Change A→B or B→A
         :               //     Else:
          x)             //      A/B remains unchanged
       +65,              //     Add 65 to convert 0/1 to 65/66 (unicode values of A/B)
      (y=                //    Third part:
         (a<98?          //     If the previous action was 'a'
           t=r+=Math.random()*6-r+1
                         //      Roll the dice, and save it in `t`
          :a>h?          //     Else-if the previous action was 'r':
           (T=x<1?       //      If the first part changed to player A:
            A-=t         //       Subtract the previous dice-roll from A
           :             //      Else:
            (B-=t))      //       Subtract the previous dice-roll from B
           <0?           //      If this score is below 0:
            0            //       Use 0
           :             //      Else:
            T            //       Use this score
         :               //     Else (the previous action was 'h'):
          A*B<1?         //      Is there a winner:
           -16           //       Change the third part to a space
          :              //      Else:
           (x^1)+17)     //       Change the third part to the other player
       +48,              //     Add 48 to convert it to unicode
       a=                //    Second part:
         a<98?           //     If the previous action was 'a': 
          114            //      Change it to 'r'
         :a>h?           //     Else-if the previous action was 'r':
          h              //      Change it to 'h'
         :               //     Else (the previous action was 'h'):
          A*B<1?         //      If either score is 0:
           119           //       Use 'w'
          :              //      Else:
           97);}         //       Use 'a'


2

배치, 174 바이트

@set/aA=B=10
@set c=A
@set d=B
:g
@set/ar=%random%%%6+1,h=%d%-=r
@echo %c% a %d%
@echo %c% r %r%
@echo %d% h %h%
@if %h% gtr 0 set c=%d%&set d=%c%&goto g
@echo %c% w

설명 : %변수 참조는 구문 분석시 대체됩니다. 여기에는 두 가지 유용한 이점이 있습니다.

  • %d%-=rr의해 명명 된 변수에서 빼기 d(즉, 간접 참조)
  • set c=%d%&set d=%c% 단순히 직선 교환입니다.

2

PHP 7.1 : 159 바이트

<?php $A=$B=10;$t='AB';while($A>0&&$B>0){$a=$t[0];$b=$t[1];$d=rand(1,6);$$b-=$d;echo"$a a $b\n$a r $d\n$b h {$$b}\n";$t=strrev($t);}echo($A>0?'A':'B')." w\n";

여기 브라우저에서 실행하십시오!

PHP 5.6 : 156 바이트

<?php $A=$B=10;$t='AB';while($A>0&&$B>0){list($a,$b)=$t;$d=rand(1,6);$$b-=$d;echo"$a a $b\n$a r $d\n$b h {$$b}\n";$t=strrev($t);}echo($A>0?'A':'B')." w\n";

여기 브라우저에서 실행하십시오!

다음은 PHP 5.6 솔루션의 형식 및 주석 모양입니다.

<?php
// Initialize both HP counters
$A = $B = 10;

// Set the turn order as a string (which 5.6 allows to be unpacked into a list)
$t = 'AB';

// Run this loop as long as both players have HP
while ($A > 0 && $B > 0) {
    // Unpack the turn string into $a and $b variables; on the first run, $a = 'A'
    // and $b = 'B'. This is no longer possible in PHP 7.0, so the PHP 7.0
    // solution needed to use an array instead.
    list($a, $b) = $t;

    // Set damage to a random number between 1 and 6
    $d = rand(1, 6);

    // Subtract the damage from the referenced value $b. On the first turn, this
    // is 'B', so this ends up subtracting $d from $B. Next turn, $b will be 'A',
    // so it'll subtract $d from $A
    $$b -= $d;

    // Echo the string (interpolated values)
    echo "$a a $b\n$a r $d\n$b h {$$b}\n";

    // Reverse the turn order string ('AB' becomes 'BA', which will affect the
    // call to list in the first line of the while-loop)
    $t = strrev($t);
}

// Someone's run out of HP; figure out whom by figuring out who still has HP
echo ($A > 0 ? 'A' : 'B') . " w\n";

1

배쉬, 178 바이트

A=10 B=10 e=echo
a(){ $e $1 a $2;d=$((RANDOM%6+1));$e $1 r $d;eval $2=$((${!2}-$d));$e $2 h ${!2};[ ${!2} -gt 0 ];}
while a A B && a B A;do cd;done;[ $A -gt 0 ]&&$e A w||$e B w

1

F #, 238235 바이트

나는 잘 지내고 있다고 생각했지만, 당신은 모두 나를 능가했다!

let p=printfn
let mutable A=10
let mutable B=A
let x h a d=
 p"%s a %s"a d
 let i=(new System.Random()).Next(1,7)
 let j=h-i
 p"%s r %i"a i
 p"%s h %i"d j
 if j<=0 then p"%s w"a
 j
while A*B>0 do
 B<-x B"A""B"
 if B>0 then A<-x A"B""A"

온라인으로 사용해보십시오!

Ro>에게 A> 0 & B> 0 대신 A * B> 0 (3 바이트 제외)을 사용하라는 훌륭한 조언을 주셔서 감사합니다.

파이썬 답변에서 printf를 미리 정의하는 것에 대한 힌트가 나에게도 몇 바이트를 줄이는 데 도움이 된 officialaimm에게도 감사합니다.


1
@OlivierGregoire에서 얻은 조언 : A*B>0몇 가지를 더 구할 수 있습니다.

그것은 절대적으로 훌륭합니다. 그것을 사랑하십시오. 대단히 감사합니다!
Ciaran_McCarthy

1

하스켈 , 204 바이트

Haskell과의 시도에서 불행히도 더 경쟁력을 얻지 못했습니다.

import System.Random
main=getStdGen>>= \g->putStr$q(randomRs(1,6)g)10(10::Int)"A ""B "
(!)=(++)
l="\n"
q(x:z)a b p o=p!"a "!o!l!p!"r "!show x!l!o!"h "!show n!l!if n<1then p!"w"else q z n a o p where n=b-x

온라인으로 사용해보십시오!

설명 :

import System.Random  --import random module
main=                        --main function, program entry point
 getStdGen                   -- get the global random number generator
   >>= \g->                  --using the random generator g
       putStr $ q            --print the result of function q, passing in ..
          (randomRs (1,6) g) --an infinite list of random numbers, 1 to 6 generated by g
           10 (10::Int)      --the starting health of both players, 
                             --type annotation sadly seems to be required
           "A " "B "         --The names of the players,
                             --with an extra space for formatting
(!)=(++) --define the operator ! for list (String) concatenation, 
         -- we do this a lot so we save a bit by having a one byte operator
l="\n"   -- define l as the newline character

q      --define function q                         
 (x:z) --our list of random numbers, split into the next number (x) and the rest (z)
 a     -- the health of the active player
 b     -- the health of the player getting attacked
 p     -- the name of the active player
 o     -- the name of the player getting attacked
=
  p!"a "!o!l --create the attack action string with a newline
 !p!"r "!show x!l -- append the roll action
 !o!"h "!show n!l -- append the health remaining
 !           -- append the result of the following if
  if n<1     -- if the player being attacked has been defeated
  then p!"w" -- append the win string for the active player
  else q z n a o p  --otherwise append the result of calling q again with 
                    --rest of the random numbers, and the active players swapped
  where n=b-x -- define the attacked player's new health n
              -- their current health b - the random roll x

Haskell의 골프 팁을 살펴볼 수 있습니다 . 예 where m=b-x를 들어 가드에 넣을 수 있습니다 |m<-b-x=.
Laikoni

몇 가지 매개 변수를 다시 정렬하면 람다와 괄호 한 세트를 잃을 수 있습니다 main=putStr=<<q"A "10"B "10.randomRs(1,6::Int)<$>getStdGen. 목록을 사용하여 연결하여 재정의를 제거 할 수도 있습니다 (++). 마지막으로 어디 b-x에서나 사용하는 것이 도움이되지 않는 것 같습니다 .
Angs

1

줄리아 0.6 , 175 바이트

p=println()
f(l="AB",h=[10,10],a=1)=(while min(h...)>0;d=3-a;p(l[a]," a ",l[d]);r=rand(1:6);h[d]-=r;p(l[a]," r ",r);p(l[d]," h ",max(h[d],0));a=d;end;p(l[findmax(h)[2]]," w"))

온라인으로 사용해보십시오!

길지 않은 긴 버전 :

function status(player, health)
    println("$player h $(max(0,health))")
end

function roll(player)
    x = rand(1:6)
    println("$player r $x")
    x
end

function play()
    players = ["A","B"]
    healths = [10, 10]
    attacker = 1

    while min(healths...) > 0
        println("$(players[attacker]) a $(players[3-attacker])")
        healths[3-attacker]-=roll(players[attacker])
        status(players[3-attacker], healths[3-attacker])

        attacker = 3 - attacker
    end

    winner = findmax(healths)[2]
    println("$(players[winner]) w")
end

TIO 링크에 출력이없는 것 같습니다.
AJFaraday

그래, 왜 티오가 싫어하는지 모르겠다. 내 컴퓨터에서 잘 작동합니다. 시간이 있으면 살펴 보겠습니다.
niczky12

1

VBA, 222 185 179 바이트

이 재귀 솔루션에는 3 개의 하위 시스템이 포함됩니다

  1. g는 첫 턴을 시작 하는 게임 시작 입니다
  2. t는 매 마다 호출됩니다 . 재귀를 사용합니다.
  3. (단 4이 솔루션에서) 3 번 이상 사용하는 경우 p는을 Debug.Print보다 짧은 편집 : 이제 내가 배운 것을 그 Debug.?에게 수용 가능한 대안 Debug.Print, Debug.?x인쇄 하위를 호출하는 것보다 짧습니다.
Sub g()
t "A",10,"B",10
End Sub
Sub t(i,j,x,h)
d=Int(Rnd()*6)+1
Debug.?i &" a "&x
Debug.?i &" r "&d
h=h-d
If h<1Then
Debug.?i &" w"
Else
Debug.?x &" h "&h
t x,h,i,j
End If
End Sub

이것은 재미있는 도전이었습니다. VB6 / VBScript / VBA 용 TIO와 같은 온라인 통역사를 알고 있다면 의견을 남겨주십시오. 그런 다음 작동하는 솔루션에 대한 링크를 게시 할 수 있습니다.

이 코드를 테스트하고 Microsoft Excel, Word, Access 또는 Outlook이 설치되어있는 경우 (Windows 만 해당) Alt + F11을 눌러 VBA IDE를 엽니 다. 새 코드 모듈 (Alt + I, M)을 삽입하고 Option Explicit을 지우십시오. 그런 다음 코드를 붙여넣고 F5를 눌러 실행하십시오. 결과는 직접 실행 창에 나타납니다 (표시되지 않으면 Ctrl + G를 누르십시오).

편집 1 : VBA 편집기가 자동으로 다시 추가하는 공백 제거. 37 바이트 감소
편집 2 : 학습 후 6 바이트를 절약하기 위해 Sub p () *가 제거 Debug.?되었습니다 Debug.Print. 처리하기 위해 Sub 를 호출하면 Debug.?6 번 이상의 호출 후에 바이트 만 절약됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.