みんながいるから続けられる。続けられるから成長できる。プログラミング力を磨く部活動のご紹介
2020年10月7日(水)13時0分 BIGLOBE Style
開発部門(基盤本部)でエンジニア育成を担当している高玉です。
BIGLOBEには登山部、麻雀部、ツーリングクラブなど様々な部活があります。今日はインドア派の部活、プロコン部についてご紹介します。
プロコン部とは
プロコンってご存知ですか?
ここでいうプロコンは、ゲーム機用のProコントローラーでも、良い点(Pros)・悪い点(Cons)を列挙するのでもありません。「競技プログラミングコンテスト」の略です。
プログラミングコンテストとは、プログラミングの技術を競い合うイベントです。参加者にお題が出題されるので、そのお題を解くプログラムを制限時間内に提出します。
プロコン部では、プログラミングコンテストで出題された過去問を各自が解いて持ち寄り、その解法を披露しあうことで、楽しくプログラミング力を高めあっています。
この記事の最後に、部活で書いている実際のコードをご紹介します。JavaScriptで多倍長整数を扱う神コードも飛び出します。どうぞお楽しみください。
ゆるくて多様なプロコン部
プロコン部の最大の特徴は「ゆるさ」と「多様性」にあります。
プログラミングコンテストに挑戦して良い成績を目指すよりは、幅広いアルゴリズムに触れて楽しく実装することが目的のゆるい部活です。
部活は週1回1時間、業務時間内に開催しています。国内最大の競技プログラミングサイトAtCoderで公開されている過去問を1つ取り上げて、各人が業務の合間に自分のペースで挑戦してきます。本番のプログラミングコンテストでは「問題を早く解くスキル」も求められますが、部活ではそのプレッシャーがないのも、ゆるさにつながっています。
約10名のメンバーが使うプログラミング言語は本当に様々です。C++、Python、JavaScript、Java、Scala、Swift、Ruby、Haskell、Rust、Clojure、F#。
みんなが同じ問題を解いてくるのですが、人によってアプローチの仕方が違うことに加え、言語による得意・不得意が分かるのがとても面白いです。問題によって「Haskellだと短く書ける」「Pythonだとシンプル」「C++のライブラリ便利」といった違いがハッキリ分かります。
名著と名高い「達人プログラマー」では「毎年少なくともひとつの言語を学習する」というプラクティスを紹介していますが、この部活が新しいプログラミング言語を学ぶ最適な場になっています。私もC++で問題が解けるようになりました。
みんながいるから続けられる
メンバーにプロコン部の魅力を聞いたところ、
「一人だとなかなか続かないけど毎週集まることでモチベーションが維持できる」
「他の人と一緒にやることで、やる気が刺激される」
「解いてくる人がいるので辞めるに辞められない環境」
といった声が集まりました。
また、
「自分の解答も人に説明するので思考やコードが整理される」
という声もありました。
仲間がいるのは心強いものです。ゆるく取り組んでいるとはいえ幅広く様々なアルゴリズムを学ぶので「苦手なアルゴリズムに取り組むのはとてもしんどい」という正直な声もありました。それでも続けられるのはすごいことです。
その結果「ちゃんと力量アップした実感がある」というメンバーもいます。コンピューターのメモリー量や計算量が、利用するデータ構造やアルゴリズムによって大きく異なることを、業務だけで学ぶことはなかなかできません。「コンピュータや処理系の気持ちになれる」との声もありました。
BIGLOBEが大切にする価値観・信念(BIGLOBEマインド)の一つに「継続的に成長する」があります。みんながいるから続けられる、続けられるから成長できる。私たちプロコン部の活動は「とてもBIGLOBEらしい活動だなぁ」と改めて思います。
みんなのコードをチラ見せ
振り返ってみると、週1回・週1問のゆるいペースとはいえ、とてもたくさんの問題を解いてきました。その中から3つほど、問題と解答コードをご紹介します。
コードゴルフ感ただようPython v.s. Rust
問題文
駅の待合室に座っているjoisinoお姉ちゃんは、切符を眺めています。
切符には 4 つの 0 以上 9 以下の整数A,B,C,D が整理番号としてこの順に書かれています。
A op1 B op2 C op3 D = 7 となるように、op1,op2,op3 に + か - を入れて式を作って下さい。
例えば (A, B, C, D) = (3, 2, 4, 2) が与えられた時、3+2+4-2=7 と出力するプログラムが求められています。Pythonで直積を求めるライブラリー itertools.product を活用して、コンパクトに書かれたコードがこちらです。
importsys, itertools
[a, b, c, d] = sys.stdin.readline().rstrip()
ops = ['+', '-']
forexp in['%s%s%s%s%s%s%s'% (a, op1, b, op2, c, op3, d) forop1, op2, op3 inlist(itertools.product(ops, ops, ops))]:
ifeval(exp) == 7:
print'%s=7'% exp
break
コードの短さを競い合う「コードゴルフ」の雰囲気が漂います。
そういえば、プロコン部で苦手なアルゴリズムに挑戦することが続いたため、その気晴らしにコードゴルフ大会が開催されたという噂があります(笑)。
ちなみに、Rust を書いてきたメンバーのコードはこれでした。コンパイルの通ったRustのコードって簡単に見えるから不思議です!
useproconio::input;
useitertools::*;
fnapply(op: char, x: i32, y: i32) ->i32{
matchop {
'+'=>x +y,
'-'=>x -y,
_ =>unreachable!(),
}
}
fnevaluate(a: &Vec<i32>, ops: &Vec<char>) ->i32{
ops.iter().zip(a.iter().skip(1))
.fold(a[0], |s, (&op, &x)|apply(op, s, x))
}
fnmake_expression(a: &Vec<char>, ops: &Vec<char>) ->String{
a.iter().cloned().interleave(ops.iter().cloned()).chain("=7".chars()).collect()
}
fnoperators(n: usize) ->implIterator<Item =Vec<char>>{
(0..n)
.map(|_|"+-".chars())
.multi_cartesian_product()
}
fnsolve(a: String) ->String{
lets =a.chars().collect::<Vec<_>>();
leta =s.iter().map(|c|c.to_digit(10).unwrap() asi32).collect::<Vec<_>>();
operators(3)
.filter(|ops|evaluate(&a, &ops) ==7)
.map(|ops|make_expression(&s, &ops))
.nth(0)
.unwrap()
}
fnmain() {
input!{
a: String,
}
letr =solve(a);
println!("{}", r);
}
ワンライナー F#
問題文
ファーストフードチェーン「ピザアット」のメニューは「A ピザ」「B ピザ」「AB ピザ」の 3 種類です。A ピザと B ピザは全く異なるピザで、これらをそれぞれ半分に切って組み合わせたものが AB ピザです。A ピザ、B ピザ、AB ピザ 1 枚あたりの値段はそれぞれ
A 円、B 円、C 円です。中橋くんは、今夜のパーティーのために A ピザ X 枚と B ピザ Y 枚を用意する必要があります。これらのピザを入手する方法は、A ピザや B ピザを直接買うか、AB ピザ 2 枚を買って A ピザ 1 枚と B ピザ 1 枚に組み替える以外にはありません。このためには最小で何円が必要でしょうか?なお、ピザの組み替えにより、必要な量を超えたピザが発生しても構いません。
例えば (A, B, C, x, y) = (1500, 2000, 1600, 3, 2) が与えられた時、つまりAピザ 1500円、Bピザ 2000円、ABピザ 1600円で、Aピザが3枚、Bピザが2枚必要な場合、AB ピザを 4 枚買って A ピザと B ピザ 2 枚ずつに組み替え、A ピザを 1 枚買い足すのが最適です。7900円と出力することが求められます。
毎回必ずF#を使って、1行のプログラム(ワンライナー)で提出するメンバーのコードを紹介します。関数型とオブジェクト指向のマルチパラダイムの言語、とのことですが、私は不勉強で理解できないため、いつも雰囲気だけ楽しんでます😇
ループを使った解法では、ABピザ2枚をi枚買って、AピザとBピザに分けつつ、足りないAピザ・Bピザを補充する戦略を取ります。ABピザを買う枚数を変化させながら、最小の金額を総当たりで調べます。
stdin.ReadLine()
|>funx ->x.Split(' ')
|>Array.map int
|>funx ->(x.[0], x.[1], x.[2], x.[3], x.[4])
|>fun(a, b, c, x, y)->
[1..(max x y)]
|>List.fold (
funret i ->
a *(max (x - i)0)+
b *(max (y - i)0)+
c *i *2
|>min ret
)(a *x +b *y)
|>printfn"%d"
場合分けによる解法では、AピザとBピザを別々に買うのと、ABピザを買って分けるのとで、どちらが安くなるかを調べます。
stdin.ReadLine()
|>funx ->x.Split(' ')
|>Array.map int
|>funx ->(x.[0], x.[1], x.[2], x.[3], x.[4])
|>fun(a, b, c, x, y)->
[
a *x +b *y;
(
ifx >y
thena *(x - y)+c *2*y
elseb *(y - x)+c *2*x
);
c *2*(max x y)
]
|>Seq.min
|>printfn"%d"
JavaScriptで多倍長整数を扱う、だと!?
問題文
非負の整数 a, b (a ≤ b) と、正の整数 x が与えられます。
a 以上 b 以下の整数のうち、x で割り切れるものの個数を求めてください。制約
0 ≤ a ≤ b ≤ 1018
1 ≤ x ≤ 1018
例えば (a, b, x) = (4, 8, 2) が与えられた時、つまり 4 以上 8 以下の整数のうち 2 で割り切れるのは、4, 6, 8 の3つなので、3 と出力するプログラムが求められています。
「0 以上 b 以下の整数のうち x で割り切れるもの」から「0 以上 (a - 1) 以下の整数のうち x で割り切れるもの」を引いた値を計算すればOKです(a が 0 の時を考慮する必要があります)。
ただ、この問題の「制約」が10の18乗で大変大きくなっているのがポイントです。C++であれば、64ビット以上の整数を表す long long を使って次のように簡単に解けます。
#include <iostream>
usingnamespacestd;
typedeflonglongll;
ll f(ll n, ll x) {
if(n == -1) return0;
returnn / x + 1;
}
intmain() {
ll a, b, x;
cin >> a >> b >> x;
cout << f(b, x) - f(a - 1, x) << endl;
return0;
}
私は当時 JavaScript で取り組んでいたのですが、JavaScriptで多倍長整数を扱うことができず撃沈していました。そんな時、メンバーの一人が次のコードを提出してきたのです。神か!
長いので折りたたんで表示します。
「部活動」をもっと詳しく
「部活動」のニュース
-
ONE TAP SPORTS、東京都教育委員会が指定する都立高校などの56部活動でコンディションアプリとして採用されました
PR TIMES 4月25日(木)13時46分
-
埼玉県川越市からJリーグを目指す「COEDO KAWAGOE F.C」、JTB川越支店と共に、埼玉県の部活動地域移行等に関する地域クラブ活動実証事業を完了
PR TIMES 4月21日(日)11時16分
-
気象庁職員、妻にDV容疑で逮捕 「子どもの部活動でもめた」
共同通信 4月21日(日)3時14分
-
SUPERDRAGON松村和哉、左足首靭帯損傷で一部活動制限へ【全文】
モデルプレス 4月19日(金)20時58分
-
届け、がんばる部活動生へ!あま〜い差し入れ「あんこでエールを『餡MMu(あんむー)』POPUP」をSAGA MADOで開催!
PR TIMES 4月18日(木)11時16分
-
Z世代が今人気だと思う部活No.1はダンス部!部活を通して養われるものは”忍耐力・体力”から”コミュニケーション能力とリーダーシップ”へ -高校部活動に関する意識調査-
PR TIMES 4月16日(火)11時16分
-
コンディショニングノート『Atleta(アトレータ)』が、部活動の指導・運営を地域に委託する「地域移行」を実施する高校に初採用!
PR TIMES 4月15日(月)16時46分
-
全国の大学部活動生が対象の適正飲酒セミナーを初開催(講演者:サントリーホールディングス(株)ARS部様)
PR TIMES 4月15日(月)16時16分
-
MIXI、渋谷区立中学校の「部活動改革」プロジェクトを今年も年間を通して支援
PR TIMES 4月9日(火)18時16分
-
大学の部活動・サークル活動における、「日々の努力」を可視化。慶應義塾大学公認団体ライフセービングサークルにて「キャリア証明書」を発行
PR TIMES 4月9日(火)16時16分
トピックス
- 能登 給水管は今も「修理待ち」 NEW
- 露がウで化学兵器使用 米指摘 写真
- 大使館元参事官 銭湯で盗撮疑い NEW
- 初の非匿名限定 精子バンク設立 写真
- 外国人向け「二重価格」はアリ? 動画
- Apple IDを乗っ取る攻撃に注意 写真
- 今永 7回無失点で無傷の5勝目 写真
- 元ロッテ谷川 無免許運転で退団 写真
- 草なぎ剛「適当が一番」の境地 NEW
- 朝ドラに水ダウ名物男「鳥肌」 NEW
- 朝ドラに水ダウ名物男「鳥肌」 NEW
- 草なぎ剛「適当が一番」の境地 NEW
- やす子 投稿「プチ炎上」に困惑 写真
- 工藤静香の文章にツッコミ殺到 写真
- 谷原章介 前日の発言を軌道修正 写真
- 太川陽介 蛭子と5年ぶり再会 写真
- 松本人志 約1カ月ぶりに動き 写真
- 人気フリーアナ 髪切って激変 写真
- ガーシー 生配信3分で強制終了 写真
- 上田竜也 懺悔したい先輩明かす 写真
- 秋元康 柏木由紀への手紙が物議 写真
- 吉岡里帆 脇チラ見せ姿を披露 写真
- 平祐奈 雰囲気激変に驚きの声 写真
- 渡辺センス 講談社を提訴 写真
- 森香澄 就活で号泣した過去 写真
- H×H 冨樫義博氏7ヶ月ぶりX更新 写真
- 杉本彩 愛猫の四十九日を報告 写真
- メンディー メンバーが異例応援 写真
- 関口メンディー「ヤメンディー」 写真
- 藤森 婚姻届の保証人は小栗旬 写真
- 元ロッテ谷川 無免許運転で退団 写真
- 今永 7回無失点で無傷の5勝目 写真
- ド軍べンチ総出でクレーム 騒然 写真
- 前田健太 6回1失点で今季初勝利 写真
- 吉田正尚 メジャー初のIL入り 写真
- 大谷翔平 今季初のスタメン落ち 写真
- 巨人 今季初の同一カード3連敗 写真
- 朝倉未来 記者批判の真意を説明 動画
- 尊富士 地元優勝パレードで感謝 写真
- 日本ハム 今季初のサヨナラ負け 写真
- 大使館元参事官 銭湯で盗撮疑い NEW
- 能登 給水管は今も「修理待ち」 NEW
- 改憲論議急ぐ必要ない65% 共同 写真
- 4か国に洪水マップ提供 国交省
- 患者を待ち伏せ 30代技師を停職 写真
- 岸田首相 アタル首相と初会談 写真
- 川勝知事 県民だよりに退任挨拶 写真
- 立民への追い風「微風程度だ」 写真
- フジコ・ヘミングさん死去 92歳 写真
- 自民 旧文通費の使途公開を検討 写真
- 外国人向け「二重価格」はアリ? 動画
- 初の非匿名限定 精子バンク設立 写真
- スクエニの特損221億円に波紋 写真
- NY円が急騰 為替介入の可能性も 写真
- 米FRB 6会合連続で金利据え置き 動画
- オリーブオイル 値上げに悲鳴 動画
- ケーキにカビ発生 5000個回収へ 写真
- 鳥貴族HD 新社名に驚きの声 写真
- 旧築地市場跡地 スタジアム建設 写真
- 「ミャクミャク」記念硬貨発行へ 写真
- Apple IDを乗っ取る攻撃に注意 写真
- 指輪型Visa 誤認に注意喚起 写真
- 空き家の「無償譲渡」サイトとは 動画
- ヤマト運輸の「偽サイト」が話題 写真
- OECD 生成AI対策指針採択へ 写真
- メルカリ 多言語対応を開始発表 写真
- AI依存に「学力格差広がる恐れ」 写真
- Xで障害の報告急増 世界規模か 写真
- MSアカを窃取 巧妙な詐欺に注意 写真
- X日本法人 悪質投稿の対策強化 写真
- 早期退職で失敗する人の特徴 写真
- マック ももシリーズ今年も登場 写真
- 美味しいたけのこの見分け方 写真
- 食べても食べても太らない動物 写真
- 砂糖普及以前の「甘味料」が注目 写真
- 八百屋に並ぶ「ぬい」に大反響 写真
- 外さずできる 網戸掃除時短ワザ 写真
- 2年かけ完成「超リアル」な水面 写真
- アリ「2:6:2の法則」効果的対策 写真
- 子供にゲーム買わない 悪影響? 写真
- Uber置き配でナンパ?投稿波紋 写真
- 褒めてもらえない仕事 投稿話題 写真
- 中でお寿司が浮遊するボールペン 写真
- カーネルおじさんが全国で武者に 写真
- 「透きとおる鳥居」にネット感嘆 写真
- お金持ちが節約している出費とは 写真
- ハードオフ「まさかの商品」販売 写真
- 洗濯機 水栓閉め忘れは危ない? 写真
- 不注意では済まされない落とし物 写真
- 江戸川乱歩賞 減点理由が物議 写真