あなたの挑戦は、1年を与えられて「金曜日13日」の数を出力するプログラムを書くことです。
ルールと詳細:
- を介して
STDIN
、またはプログラムに渡される引数として入力を受け取ることができます。 - 結果をに出力する必要があります
STDOUT
。 - 入力は有効な年であり、グレゴリオ暦より前の日付ではないと想定できます(これらの場合、未定義の動作は許可されます)。
- カレンダー/日付ライブラリが許可されています。
これはcode-golfであるため、最短のコード(バイト単位)が優先されます。
あなたの挑戦は、1年を与えられて「金曜日13日」の数を出力するプログラムを書くことです。
ルールと詳細:
STDIN
、またはプログラムに渡される引数として入力を受け取ることができます。STDOUT
。これはcode-golfであるため、最短のコード(バイト単位)が優先されます。
回答:
+/{13∊⍎,⍉3↑¯5↑⍉2↓cal⍵}¨⎕,¨⍳12
⍳ 12
1から12までの整数
⎕ ,¨
数値を入力して、12個の数字のそれぞれに追加します
{
… }¨
各ペアで、関数を適用します…
cal⍵
その年月のカレンダーを取得する
2 ↓
2行(キャプションと日)をドロップします
⍉
転置(行ではなく列をアドレス指定できるように)
¯5 ↑
最後の5つ(金曜日と土曜日にそれぞれ2桁と1つのスペース)
3 ↑
最初の2つ(金曜日に2桁とスペースを追加)を取る
⍉
転置(読み取り順序を取得)
,
ラヴェル
⍎
APL式として実行(金曜日の日付のリストを提供)
13 ∊
13はそのリストのメンバーですか?
+/
12個のブール値を合計する
@Wrzlprmftのアルゴリズムを使用すると、53バイトのライブラリなしで実行できます。
'21232211321211'⊃⍨14|2 3 ¯1+.×⊢,0≠.=400 100 4∘.|-∘0 1
-∘0 1
0と1を引く
400 100 4 ∘.|
これらの数字で割った(下)2年間の除算剰余表
0 ≠.=
0の内部「製品」、ただし+。×の代わりに≠および=を使用
⊢ ,
変更されていない引数の年を追加する
2 3 ¯1 +.×
これらの数字の内積
14 |
14で除算したときの除算余り
'21232211321211' ⌷⍨
この文字列へのインデックス
純粋な関数として:42文字
DayName@{#,m,6}~Table~{m,12}~Count~Friday&
例
DayName@{#,m,6}~Table~{m,12}~Count~Friday&[2013]
2
名前付き関数として:44文字
f=DayName@{#,m,6}~Table~{m,12}~Count~Friday&
例
f[1776]
f[2012]
f[2013]
f[2014]
2
3
2
1
f=DayName@{#,m,6}~Table~{m,12}~Count~Friday&
f=->m{(1..12).count{|i|Time.gm(m,i,6).friday?}}
編集:Janのおかげで1週間前に戻ってキャラクターを剃り、Time.newからTime.gmに切り替えて別のキャラクターを剃った
編集:それをもう少し難読化することを犠牲にして、私は46で得ることができます
f=->m{(1..12).count{|i|Time.gm(m,i,8).wday<1}}
Time.gm(m,i).wday<1
。また、なぜ関数に名前を付けているのかわかりません。
ヒントについてはIsziに感謝します。
$n=$args;(1..12|?{!+(date $n-$_).DayOfWeek}).Count
月の1日目が日曜日の場合、13日目は金曜日になります。
私も試しました:
(1..12|?{!+(date $args-$_).DayOfWeek}).Count
ただし$args
、スクリプトブロック内では同じではありません。
$n
し$args
、$n=read-host;
完全になしで行うことができます。保存8.上記のように@を削除すると、54になります。
$args
ために$input
このようにパイプラインから一年を送り、およびスクリプトが実行されますが、それは常に3出力
sum(format(as.Date(paste(scan(),1:12,1,sep="-")),"%w")<1)
"%a %d")=="Fri 13"
て"%w%d)=="513")
数としてダウを使用して、スペースを削除することによって。
seq
ここで、月に1回だけ行うことは実際には短くなりますが!sum(format(as.Date(paste(scan(),1:12,13,sep="-")),"%w%d")=="513")
65文字のみです!
<
文字を整数に強制するだろうとは思わなかったでしょう。ナイストリック!
from datetime import*
s=c=0
exec's+=1;c+=date(%d,s,9).weekday()<1;'%input()*12
print c
9日月曜日は、まったく同じリングではないかもしれませんが、同様に機能します。
編集:一年半がそれdate
より短いことに注意してくださいdatetime
:)
from datetime import*
f=lambda y:sum([date(y,m,13).weekday()==4 for m in range(1,13)])
....ただし、インポートと同じサイズのソリューション(86バイト)。
ライブラリまたは組み込みの日付関数を使用しない:
~..({4/.25/.4/--@}2*2*\3*+-
14%' [3/=RI[)a%:*.'\=5%
' [3/=RI[)a%:*.'
かもしれない'feefefgeeffgfe'
本質的に同じアルゴリズム。
l=lambda y:y/4-y/100+y/400
i=input()
print"21232211321211"[(2*i+3*l(i)-l(i-1))%14]
l=lambda y:y/4-y/100+y/400
i=input()
print 94067430>>(4*i+6*l(i)-2*l(i-1))%28&3
これは、暦上、最終日と跳躍しているかどうかで区別できる14年しか存在しないという事実を利用しています。
l
引数までのうるう年の数を計算します(グレゴリオ暦が1年まで遡った場合)。(2*i+3*l(i)-l(i-1))%14
略でl(i)-l(i-1)+(i+l(i))%7*2
、どこl(i)-l(i-1)
の引数はうるう年とあるかどうかを教えてくれるi+l(i)
最終日のシフト(閏年では通常年に1、2)までの合計。
main(int x,char**v){char p[400],*a[]={"abbababbacaacbac","bacabbb","baabbaca","abbb","aabbacaac","abbbbcaac","abbbbaabb"},*b="adcadcadcaebcadcadcafbcadcadcagbcadcadcadc";int c=0,i,y=atoi(v[0]);for(i=0;i<42;i++)strcpy(&p[c],a[b[i]-'a']),c+=strlen(a[b[i]-'a']);printf("%d",p[y%400]-'`');}
最短の答えではありませんが、ライブラリを使用しません。
static char GetNumberOfFriday13s(int year) { const string perpetualCalendar = "1221212213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213112213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122131"; return perpetualCalendar[year % 400];
。マイナスの年は機能しません。
v[0]
必要がありますv[1]
。これを少しゴルフすることもできます。を使用してstrcat
、を直接印刷する文字を保存し、文字a[]
定数の代わりに数値定数を減算することを検討してください。:)
main(int x,char**v){char p[400],*a[]={"1221212213113213","2131222","21122131","1222","112213113","122223113","122221122"},*b="adcadcadcaebcadcadcafbcadcadcagbcadcadcadc";*p=0;for(;*b;b++)strcat(p,a[*b-97]);putchar(p[atoi(v[1])%400]);}
(215文字)
組み込みのカレンダーツールを使用しない他のソリューションが1つしかないことに驚いています。これも(非常に難読化された)数学的なアプローチです。これもCです。
f(x){return(x+(x+3)/4-(x+99)/100+!!x)%7;}main(int x,char**v){int y=atoi(v[1])%400,a=f(y+1);putchar('1'+((f(y)&3)==1)+(a>2&&a-5));}
(上記はGCCでエラーなしでコンパイルされます)
私はむしろ、Williham Totlandのソリューションと彼の圧縮の使用を楽しんだ。2つの小さなバグを修正し、コードを調整して長さを短くしました。
main(int x,char**v){char p[400],*a[]={"1221212213113","213122221122131","12213113","22213113","22221122","2131"},*b="abababafcbababafdbababafebababab";*p=0;for(;*b;b++)strcat(p,a[*b-97]);putchar(p[atoi(v[1])%400]);}
<?for($i=1,$c=0;$i<13;$i++)$c+=(date("N",mktime(0,0,0,$i,1,$argv[1]))==7);echo $c;
に基づく
「日曜日から始まる月には13日金曜日が含まれており、各暦年には少なくとも1日13日金曜日があります。」
seq -f$1-%g-6 12|date -f-|grep -c ^F
seq
デフォルトでstartを使用して10文字を保存してくれた@DigitalTraumaに感謝します1
。
date -f<(printf "%s\n" $1-{1..12}-6)|grep -c ^F
(以前のバージョンecho
ではwhenが空行であるためにバグが発生していました<(echo $1-{1..12}-6$'\n')
。したがって、この関数は今日が金曜日まで正常に機能していました。
set -- 2013
seq -f$1-%g-6 1 12|date -f-|grep -c ^F
2
date -f<(printf "%s\n" $1-{1..12}-13)|grep -c ^F
2
であり、ロケール、それは仕事をしない場合は、する必要があります依存、SI
export LANG=C
または
LANG=C date -f<(printf "%s\n" $1-{1..12}-13)|grep -c ^F
f(){ seq -f$1-%g-6 12|date -f-|grep -c ^F;}
f 2013
2
for i in {2010..2017};do echo $i $(f $i) ;done
2010 1
2011 1
2012 3
2013 2
2014 1
2015 3
2016 1
2017 2
そこから、私の機能が次のようになった場合:
f(){ o=();for t in $(seq -f$1-%g-6 12|date -f- +%a,%b);do [ "${t:0:1}" = "F" ]&&o+=(${t#*,});done;echo ${#o[@]} ${o[@]};}
または
f(){ o=();
for t in $(seq -f$1-%g-6 1 12|date -f- +%a,%b);do
[ "${t:0:1}" = "F" ]&&o+=(${t#*,})
done
echo ${#o[@]} ${o[@]}
}
for i in {2010..2017};do echo $i $(f $i) ;done
2010 1 Aug
2011 1 May
2012 3 Jan Apr Jul
2013 2 Sep Dec
2014 1 Jun
2015 3 Feb Mar Nov
2016 1 May
2017 2 Jan Oct
C
。しかし、バグが...そこにある
%s\\n
seq
:8つの文字ドロップするdate -f<(seq -f$1-%g-6 1 12)|grep -c ^F
seq -f$1-%g-6 12|date -f-|grep -c ^F
f=function(a){b=0;for(c=12;c--;)b+=!new Date(a,c,1).getDay();return b}
,b,c
関数宣言から削除することで、さらに数バイトを節約できます(ゴルフのvarsをリークしても大丈夫です!)。また、:の代わりに、テストの結果b
としてキャストNumber
できます。ただし、7バイトを節約する代わりに、(日曜日に0を返し、13日が金曜日であれば1日が日曜日になるため)これを使用して別のバイトを保存できます!+=
&&b++
b+=/^F/.test(new Date(a,c,6))
!new Date(a,c,1).getDay()
getDay
test
64文字
{+/6={x-7*x div 7}(.:')x,/:(".",'"0"^-2$'$:1+!:12),\:".13"}[0:0]
stdinからの読み取り
int f(int y){int c=0;for(int i=1;i<13;i++)c+=new DateTime(y,i,8).DayOfWeek>0?0:1;return c;}
int g(int y){return Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0);}
linqのJeppe Stig Nielsenと、8日の日曜日のチェックの提案に感謝します。
の>
代わりに提案してくれたDankoDurbićに感謝し==
ます。
c+=(int)new DateTime(y,i,13).DayOfWeek==5?1:0;
、同等のものを使用しc+=new DateTime(y,i,8).DayOfWeek==0?1:0;
ます。秘subtractは減算5
することです。なぜならキャストを取り除くことができint
、また数字8
が数字より1桁少ないから13
です。日曜日8
int g(int y){return Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0);}
。もちろん、ラムダとしてこれはy=>Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0)
です。
.DayOfWeek<1
。
c#
回答に適用できますが、適用方法がわかりませんlinq
。
DayOfWeek
以外の整数と比較することはできません。0
error CS0019: Operator '<' cannot be applied to operands of type 'System.DayOfWeek' and 'int'
for(;++$i<13;)$c+=!date(w,strtotime($argn.-$i));echo$c;
で実行しecho <year> | php -nR '<code>'
ます。
基本的にオレグが試みたものとダミール・カシポヴィッチが試みたものと同じで、ゴルフが良くなっているだけ
です。日曜日から始まる毎月、13日の金曜日があります。
したがって、月をループして、日曜日である最初の日を数えます。
壊す
for(;++$i<13;) // loop $i from 1 to 12
$c+=! // 4. if result is not truthy (weekday==0), increment $c
date(w, // 3. get weekday (0 stands for Sunday)
strtotime( // 2. convert to timestamp (midnight 1st day of the month)
$argn.-$i // 1. concatenate year, "-" and month
)
)
;
echo$c; // output
f: 0 repeat m 12[d: do ajoin["6-"m"-"y]if d/weekday = 5[++ f]]f
Rebolコンソールでの使用例:
>> y: 2012
== 2012
>> f: 0 repeat m 12[d: do ajoin["6-"m"-"y]if d/weekday = 5[++ f]]f
== 3
特定の年のすべての金曜日13日を収集する代替ソリューションは次のとおりです。
>> collect[repeat m 12[d: do ajoin["13-"m"-"y]if d/weekday = 5[keep d]]]
== [13-Jan-2012 13-Apr-2012 13-Jul-2012]
ncal $1|sed '/F/s/13/\
/g'|grep -c ^\ 2
ncal
左下の曜日を指定した年のカレンダーを印刷します。
sed
/g
フラグを使用すると、13行すべてが改行で沈みます
grep -c
「2」で始まる行をカウントします(20は常に13に続きます)
古いバージョンのバグを見つけて解決策を提案してくれた@DigitalTraumaに感謝します!
ncal $1|sed /F/s/13/\\n/g|grep -c ^\ 2
78文字で:
def f(y:Int)=0 to 11 count(new java.util.GregorianCalendar(y,_,6).get(7)==6)
DAY_OF_WEEK = 7
およびに魔法の数字を使用することを除いて、異常なことは何もありませんFRIDAY = 6
。
68文字バージョン:
def f(y:Int)=0 to 11 count(new java.util.Date(y-1900,_,6).getDay==5)
はい、JavaはAPI間の曜日定数の値を変更しました。
new java.util.GregorianCalendar
はとても長くなければならないのは残念だ:(
なぜなら、唯一の前の年のための作品monthdatescalendar
を返す与えられた年のカレンダーまでになりました。最適化の可能性はたくさん残っていると思います:)。
import calendar, sys
c=calendar.Calendar()
f=0
for m in range(1,12):
for w in c.monthdatescalendar(int(sys.argv[1]),m):
for d in w:
if d.weekday() == 4 and d.day == 13:
f=f+1
print(f)
別の解決策は、すべての日付で機能しますが、それより小さくありません:
import datetime,sys
y=int(sys.argv[1])
n=datetime.date
f=n(y,1,1)
l=n(y,12,31)
i=0
for o in range(f.toordinal(), l.toordinal()):
d=f.fromordinal(o)
if d.day == 13 and d.weekday() == 4:
i=i+1
print(i)
探しているではないという考えでは13th
なく、まず、およびなどsunday
で0
、このletが3文字の保存!@ IsziとDankoDurbićに感謝します!
$==$_;$_=grep{!strftime"%w",0,0,0,1,$_,$=-1900}(0..11)
この方法で2010〜2017(サンプル用)を計算できます。
perl -MPOSIX -pE '$==$_;$_=grep{!strftime"%w",0,0,0,1,$_,$=-1900}(0..11)' <(
printf "%s\n" {2010..2017})
11321312
(OK、改行はありませんが、それは尋ねられませんでした;)
$==grep{5==strftime"%w",0,0,0,13,$_,$ARGV[0]-1900}(0..11);say$=
for i in {2010..2017};do
echo $i $(
perl -MPOSIX -E '
$==grep{5==strftime"%w",0,0,0,13,$_,$ARGV[0]-1900}(0..11);say$=
' $i );
done
2010 1
2011 1
2012 3
2013 2
2014 1
2015 3
2016 1
2017 2
日付ライブラリを使用しないソリューションを試しました。
かなりクールな(自分でそう言うことができるなら)ソリューションを見つけました。残念ながら、これよりも短くすることはできません。より良い方法があるべきだと感じているので、これは本当に私を悩ませます。
解決策は、それ自体がわずか44バイトのこのアルゴリズムにかかっています。残念ながら、うまくラップするにはさらに100バイトが必要です...
#include<stdlib.h>
main(int,char**v){int f=0,d,m,y;for(m=1;m<13;++m)d=13,y=atoi(v[1]),(d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7-5||++f;return f;}
リターンコードによる出力(C ++では、別のを使用するcout
か、printf
または別のものを必要とするものを使用#include
すると、ソリューションがさらに爆破されます)。
ドライバー/テストプログラム:
# Make sure we're not running an old version
rm doomsday.exe
gcc doomsday.cpp -o doomsday.exe
./doomsday.exe 1776
echo 1766: $?
./doomsday.exe 2012
echo 2013: $?
./doomsday.exe 2013
echo 2013: $?
./doomsday.exe 2014
echo 2014: $?
echo `wc doomsday.cpp -c` characters
ドライバープログラムの出力:
$ ./test_doomsday
1766: 2
2013: 3
2013: 2
2014: 1
150 doomsday.cpp characters
($m<3?$y--:$y-2)+3
代わりにd=13,
、d+=m<3?y--:y-2,
とd+4
同様に動作し、多くを保存しなければなりません。+5
代わりに、+3
それ-5
も動作し、2バイトを節約します。for(m=0;++m<13;)
1バイト節約します。m=0
機能ヘッドに移動すると、もう1バイト節約されます。()%7||++f
ループヘッドに移動すると、もう1つ保存されます。149バイトから136バイトに減少。
を削除することにより、-20バイトimport
、および私が逃したいくつかの空白。
(import '[java.time LocalDate DayOfWeek])#(loop[d(LocalDate/parse(str %"-01-01"))c 0](if(=(.getYear d)%)(recur(.plusDays d 1)(if(and(=(.getDayOfMonth d)13)(= (.getDayOfWeek d) DayOfWeek/FRIDAY))(inc c)c))c))
指定された年の1月1日から始まり、毎日ループします。日が13日の金曜日の場合、カウントがインクリメントされます。翌年に達するまでループし続けます。
(import '[java.time LocalDate DayOfWeek])
(defn count-friday-13ths [year]
(loop [d (LocalDate/parse (str year "-01-01")) ; Starting date
c 0] ; The count
(if (= (.getYear d) year) ; If we haven't moved onto the next year...
(recur (.plusDays d 1) ; Add a day...
(if (and (= (.getDayOfMonth d) 13) ; And increment the count if it's Friday the 13th
(= (.getDayOfWeek d) DayOfWeek/FRIDAY))
(inc c) c))
c))) ; Return the count once we've started the next year.
echo 0x5da5aa76d7699a>>(($y=$argn%400)+($y>102?$y>198?$y>299?48:32:16:0))%28*2&3;
で実行しecho <year> | php -nR '<code>'
ます。
壊す
平日は400年ごとに繰り返されます。
(たとえば)1600〜1999の結果では、わずか3つのギャップがある28の期間があります。
0:2212122131132131222211221311
28:2212122131132131222211221311
56:2212122131132131222211221311
84:2212122131132131122
103: 131132131222211221311
124:2212122131132131222211221311
152:2212122131132131222211221311
180:2212122131132131222
199: 131132131222211221311
220:2212122131132131222211221311
248:2212122131132131222211221311
276:221212213113213122221122
300: 2131222211221311
316:2212122131132131222211221311
344:2212122131132131222211221311
372:2212122131132131222211221311
これらのギャップの年を調整した後、簡単なハッシュで結果を取得できます。
$y=$argn%400;foreach([300,199,103]as$k)$y<$k?:$y+=16;
echo"2212122131132131222211221311"[$y%28];
短くない(95バイト)が、かなり。そして、私たちはゴルフができます
for(;++$m<13;23*$m/9+($m<3?$y--:$y-2)+5+$y/4-$y/100+$y/400)%7?:$f++)$y=$argn;echo$f;
-x
、10バイトCÆ5¥ÐUXD e
CÆ5¥ÐUXD e :Implicit input of integer U
C :12
Æ : Map each X in the range [0,C) (months are 0-indexed in JavaScript)
5¥ : Check if 5 is equal to
ÐUXD : new Date(U,X,13)
e : 0-based index of day of the week
:Implicitly reduce by addition and output