最大公約数を視覚化する


28

バックグラウンド

最大公約数(略してgcd)は便利な数学関数です。多くの有用な特性を持っているからです。そのうちの一つがあるベズーの等式:場合はd = gcd(a, b)、その後、整数が存在するxy、そのようなことをd = x*a + y*b。この課題では、タスクは単純なASCIIアートでこのプロパティを視覚化することです。

入力

入力は、2つの正の整数aとでb、適切な形式で指定されます。単項入力(選択可能な単一の印刷可能なASCII文字の繰り返し)を使用することもできますが、両方の入力に一貫性があり、同じ形式を使用する必要があります。入力の順序は任意で、同じでもかまいません。

出力

出力はs長さの文字列ですlcm(a, b) + 1lcmは最小公倍数を表します)。の文字はsから0までの整数を表しますlcm(a, b)。文字s[i]は、またはの倍数のo場合iは小文字で、それ以外の場合はピリオドです。ゼロはすべての数値の倍数であることに注意してください。現在、Bézoutのアイデンティティにより、距離が正確にである文字のペアが少なくとも1つあります。そのような左端のペアは大文字のsに置き換えられます。これが最終出力です。ab.osgcd(a, b)O

入力a = 4とを考慮してくださいb = 6。その後、我々は持っているgcd(a, b) = 2lcm(a, b) = 12、程度の長さはsになります13aおよびの倍数は、b次のように強調表示されます。

0  1  2  3  4  5  6  7  8  9 10 11 12
o  .  .  .  o  .  o  .  o  .  .  .  o

o距離が2のsのペアが2つありますが、左端のものだけをOsに置き換えるため、最終的な出力は

o...O.O.o...o

ルールとスコアリング

完全なプログラムまたは関数を作成できます。最小のバイトカウントが優先され、標準の抜け穴は許可されません。

テストケース

 1  1 -> OO
 2  2 -> O.O
 1  3 -> OOoo
 4  1 -> OOooo
 2  6 -> O.O.o.o
 2  3 -> o.OOo.o
10  2 -> O.O.o.o.o.o
 4  5 -> o...OO..o.o.o..oo...o
 8  6 -> o.....O.O...o...o.o.....o
12 15 -> o...........O..O........o.....o.....o........o..o...........o
19 15 -> o..............o...o..........o.......o......o...........o..o..............OO.............o....o.........o........o.....o............o.o..............o.o............o.....o........o.........o....o.............oo..............o..o...........o......o.......o..........o...o..............o

1
単項入力を行う場合、任意の文字を選択できますか?(特に、どうですか.oまたはO。)または、そうでなければなり1ませんか?または0
マーティンエンダー

1
@MartinBüttner一貫性があり、両方の入力に同じ形式を使用している限り、任意の文字を使用できます。
ズガルブ

2
テストケースの1つとして3と5を使用しなかったことに驚いています。
ニール

buildinを使用できますか?
-Akangka

@ChristianIrwanはい、すべてのビルトインが許可されています。
ズガルブ

回答:


7

Jolf、52バイト

on*'.wm9jJΡR m*Yhm8jJDN?<*%Sj%SJ1'o'.}"'o%o"n"O%O"n

このコードを2つの部分に分割します。

on*'.wm9jJ
on         set n
  *'.       to a dot repeated
      m9jJ  the gcd of two numeric inputs

ΡR m*Yhm8jJDN?<*%Sj%SJ1'o'.}"'o%o"n"O%O"n
    *Y                                    multiply (repeat) Y (Y = [])
      hm8jJ                                by the lcm of two inputs + 1
  _m       DN              }              and map the array of that length
             ?<*%Sj%SJ1'o'.               "choose o if i%a*(i%b)<1; otherwise choose ."
 R                          "'            join by empty string
Ρ                            'o%o"n        replace once (capital Rho, 2 bytes): "o"+n+"o"
                                   "O%O"n   with "O"+n+"O"
                                          implicit printing

ここで試してみてください!


これまでの他のすべてよりも短い。:P
Rɪᴋᴇʀ

1
@RikerWはい!ジョルフが最終的に勝つことを望んでいます。
コナーオブライエン

10

ジュリア、111の 110 107 103 96バイト

f(a,b)=replace(join([i%a*(i%b)<1?"o":"."for i=0:lcm(a,b)]),"o$(d="."^(gcd(a,b)-1))o","O$(d)O",1)

これは、2つの整数を受け入れ、文字列を返す関数です。

ゴルフをしていない:

function f(a::Int, b::Int)
    # Construct an array of dots and o's
    x = [i % a * (i % b) < 1 ? "o" : "." for i = 0:lcm(a, b)]

    # Join it into a string
    j = join(x)

    # Replace the first pair with distance gcd(a, b) - 1
    replace(j, "o$(d = "."^(gcd(a, b) - 1))o", "O$(d)O", 1) 
end

nimiのおかげで1バイト節約できました!


10

網膜112 109 99 94 91バイト

^
. 
+r`(?<!^\1+). (.+) 
$'$0
.(?=.* (.+) (.+))(?=\1* |\2* )
o
o(\.*)o((\1\.*o)*) .*
O$1O$2

それほど競争的ではないと思いますが、Retinaの数論は常にとても楽しいです。:)

入力を単項数字.として使用し、単項数字として使用します。

オンラインでお試しください。

説明

^
. 

これ.により、入力の前にスペースとスペースが挿入されます。これが最終的に出力になります。

+r`(?<!^\1+). (.+) 
$'$0

これは、のLCM前に付加aしてb文字列にします。既に.そこにあるので、結果はになりますlcm(a,b)+1。これは、この新しいプレフィックスを分割しないb限り、繰り返し先頭にa追加することで実現されます。aグループ1にキャプチャし、そのキャプチャを少なくとも1回照合することで文字列の先頭に到達できるかどうかを確認します。bその後、まれに使用される文字列に挿入され、一致$'すべてが置換に挿入されます。

.(?=.* (.+) (.+))(?=\1* |\2* )
o

これは、aまたはで区切られた位置の文字に一致しbます。結果が対称的であるという事実を利用します。なぜならlcm(a,b)、両方aで除算され、bインスタンスを減算することで左に行くaか、またはそれらを加算するbことで右から行くと同じパターンを生成するから0です。最初の先読みは単にをキャプチャabます。2番目の先読みは、最初のスペースの前に、それぞれaまたはb文字の倍数があることを確認します。

o(\.*)o((\1\.*o)*) .*
O$1O$2

ウィキペディアで述べたように、ベズーの身元に加えて、

最大公約数dは、と記述できる最小の正の整数ですax + by

これは、GCDがo出力の2つの間の最短ギャップに対応することを意味します。そのため、GCDを見つける必要はまったくありません。代わりに、最短ギャップの最初のインスタンスを探します。o(\.*)o候補のギャップに一致し、その幅をグループ1にキャプチャします。次に、グループ1とos(オプションの追加.のs)への後方参照を交互に切り替えて、最初のスペースに到達しようとします。右側に短いギャップがある場合、後方参照でそのギャップを越えることができないため、これは一致しません。これ以上のギャップがすべて現在のギャップと少なくとも同じ幅になると、これは一致します。LCM-stringの終わりをグループ2にキャプチャし、残りの文字列をと一致させます.*。大文字を書き戻しますOs(間にギャップがある)およびLCM文字列の残りの部分。ただし、スペースから始まるすべてを破棄ab、最終結果から削除します。


Retina数論についてはあまり知りませんが、入力文字を保存バイトをエスケープする必要のないものに設定しませんか?すなわち(\.*)=(a*)
コナーオブライエン

@CᴏɴᴏʀO'Bʀɪᴇɴはい。しかし、それを.後で置き換える必要があります。これには4バイトかかります(エスケープを取り除くと3だけ節約されます)。
マーティンエンダー

ああ クール!非常に興味深い答えです。
コナーオブライエン

5

𝔼𝕊𝕄𝕚𝕟、50文字/ 90バイト

⩥Мū⁽îí+1)ⓜ$%î⅋$%í?⍘.:⍘o)⨝ċɼ(`o⦃⍘.ĘМũ⁽îí-1)}o”,↪$ú⬮

Try it here (Firefox only).

これをさらにゴルフする方法があるはずです!

説明

これは基本的な2フェーズアルゴリズムです。実際には非常に簡単です。

フェーズ1

⩥Мū⁽îí+1)ⓜ$%î⅋$%í?⍘.:⍘o)⨝

最初に、0からLCM + 1までの範囲を作成します。次に、それをマッピングし、入力のいずれかが範囲内の現在のアイテムの要素であるかどうかを確認します。その場合、その項目をo;に置き換えます。それ以外の場合は、に置き換え.ます。参加すると、フェーズ2に渡すことができる一連のoとドットが得られます。

フェーズ2

ċɼ(`o⦃⍘.ĘМũ⁽îí-1)}o”,↪$ú⬮

これは、1つの大きな置換関数にすぎません。正規表現はとして作成されo[dots]o、ドットの量はGCD-1によって決定されます。この正規表現はグローバルではないため、最初の出現とのみ一致します。その後、O[dots]OtoUpperCase関数を使用して一致が置き換えられます。


3

MATL、72バイト

このチャレンジよりも前のバージョン6.0.0を使用します。コードはMatlabおよびOctaveで実行されます。

2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 1
> 1
OO

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 2
> 3
o.OOo.o

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 12
> 15
o...........O..O........o.....o.....o........o..o...........o

説明

私はそれがどのように機能するのか分かりません。文字をランダムに入力しました。いくつかの畳み込みが関係していると思います。

編集:オンラインでお試しください!リンクのコードは、言語の変更に合わせて若干変更されています(2016年6月2日現在)。


72バイトのプログラムをランダムに入力することはできません。後で確率を計算します(しばらく寝てからACTした後)
CalculatorFeline

2

Japt、83バイト

'.pD=U*V/(C=(G=@Y?G$($YX%Y :X} $($UV)+1 £Y%U©Y%V?".:o"} $.replace($E=`o{'.pC-1}o`Eu

まだ完全にはゴルフされていません...そして、ゴルフをしたくありません:/


r代わりに使用できません$.replace($か?
-ETHproductions

@Eth私はgフラグなしで置換する方法を理解していないので、いいえ、できません。
ニカエル

2

ジャバスクリプト、170の 164 161 153 145 141 136バイト

(a,b)=>[...Array(a*b/(c=(g=(a,b)=>b?g(b,a%b):a)(a,b))+1)].map((x,i)=>i%a&&i%b?'.':'o').join``.replace(`o${e='.'.repeat(c-1)}o`,`O${e}O`)

それはかなりlonnngggggです。

Demoは、インタープリターがストリクトモードを使用するため、変数を明示的に定義します。


交換i%a<1||i%b<1?'o':'.'してみてくださいi%a&&i%b?'.':'o'
ママファンロール

そうそう、エイリアス結合ができると思います。
ママファンロール

@ןnɟuɐɯɹɐןoɯおかげで、配列も単純な繰り返しに置き換えられました。
ニカエル

ああ、その場合、3回出現しない限り、おそらくエイリアス結合を行うべきではありません。
ママファンロール

[...Array((d=a*b/(c=(g=(a,b)=>b?g(b,a%b):a)(a,b)))+1).keys()].map(i=>i%a&&i%b?'.':'o')2バイト節約できます。(文字列インデックスを使用して「。」と「o」を作成しようとしましたが、実際には2バイトかかります。)
ニール

1

パイソン2、217の 200 191バイト

これは少し鈍いですが、動作します。どれゴルフのヒントは、感謝していますが、その修正方法を知っている場合は特にs[i] = s[v] = "o"それが「O」の上書きする場合は、私が遭遇した問題を手に入れたことを!

g=lambda a,b:b and g(b,a%b)or a
def f(a,b):
 h=g(a,b);x=1+a*b/h;s=["."]*x;v=k=0
 for i in range(x):
    if(i%a)*(i%b)<1:
     if k:s[i]="o"
     else:k=i==h+v;s[i]=s[v]="oO"[k]
     v=i
 return''.join(s)

ゴルフをしていない:

def gcd(a,b):                           # recursive gcd function
    if b:
        return g(b,a%b)
    else:
        return a
def f(a,b):
    h = gcd(a,b)
    x = 1 + a*b/h                       # 1 + lcm(a,b)
    s = ["."] * x
    v = 0
    k = 0
    for i in range(x):
        if i%a == 0 and i % b == 0:
            if k == 0:
                k = (i == h+v)          # correct distance apart?
                if k:                   # if "O" just found
                    s[i] = s[v] = "O"
                else:
                    s[i] = s[v] = "o"
            else:
                s[i] = "o"              # if "O" already found, always "o"
            v = i                       # If we found an "o" or an "O", i is the new v
    return ''.join(s)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.