稲枝の押入れ

いなえが適当なことを書いては、しまっておく場所

VSCodeの簡単な紹介(Markdown)

目次

経緯

今までmarkdownエディタとしてAtomを使ってきていたのだが、とにかく重くなる為に10分毎にソフトを再起動する必要があり、そのストレスが酷かったのでVSCodeに乗り換えてみたら、思っていた以上にいいエディタだった。今更感はあるものの簡単に紹介しようと思う。

また、文中の埋め込み動画について、編集中に撮ったものなので、映っている文章等がこの記事の本文と違う所もあるが気にしないで欲しい。

VSCodeって?

Wikipediaによると

Visual Studio Codeソースコードエディタである。マイクロソフトにより開発され、WindowsLinuxmacOS上で動作する。デバッグ、Gitクライアントの統合、シンタックスハイライト、インテリセンス、スニペットリファクタリングなどの機能を持つ。カスタマイズもでき、利用者はエディタのテーマやキーボードショートカット等を変更できる。

Visual Studio CodeはElectronフレームワークを使用しており、Node.jsを使ったBlinkで描画されるデスクトップアプリケーションである。なお、Electronを使用したテキストエディタとしてAtomが有名であるが、そこからの派生ではなく、Visual Studio Online のエディタ(コードネーム "Monaco")が基になっている。また、Visual Studioとは名称に共通点があり、使われている技術にも共有されている部分があるものの、直接的な派生関係は無い。

Visual Studio CodevscodeGitHub上のリポジトリ名)は完全に同一のものと思われがちだ。しかし、Visual Studio Codeオープンソースvscodeを元に作成されたものでありライセンスを含め違ったものである。

Visual Studio統合開発環境であるのに対して、Visual Studio Codeソースコードエディタ、つまりはテキストエディタであることなどがわかる。

個人的に述べさせてもらうと、Visual Studio Codeは、

といった感じ。なんでさっきからテキストエディタと言っているかというと、僕個人がマークダウンを書くのにしか使っておらず、ソースコードエディタとしての真髄をまだ体験していないと思っているから。

しかし、デバッグ周りの機能がVisual Studioと同じ感じで備わっているのを見ると、こちらもなかなか優秀そうなので、いつか使った時には記事を書くか、追記したい。

VSCodeのインストール

公式サイトのトップページから、Download for ******に自分の使っているOSが自動識別されて表示される様なので、あっていたらそこをクリックする。

f:id:makiofinae:20180322141940p:plain

あっていなければ、その右の矢印の様なマークをクリックしてドロップダウンした選択肢の中から自分の使っているOSを選択する。

f:id:makiofinae:20180322141955p:plain

もしくは、ダウンロードページから自分のOSにあったものをダウンロードする。

f:id:makiofinae:20180322142008p:plain

インストールはインストーラに従って適当にすれば大丈夫。非常に簡潔で、特に変わったことは聞かれなかったと思う。

共通部分はあるとは思うが、ここからはOSはWindows前提で話を進めていく。

VSCodeの強み

以下、VSCodeの強みについて書いていこうと思う。

とにかく軽い

もうこれが強すぎるが、非常に軽い。起動が早ければ動作も早い。何かあったとしても再起動が直ぐなのでストレスがない。

ショートカットキー

参考: - キーバインディング - 【Windows版】VS Code キーボードショートカット一覧 (オススメ付き)

(2018/8/12 追記 : ショートカットが変更されたようで、この記事におけるショートカットキーが必ずしも同様に動作するとは限らないことを確認した。上部のメニューバーから「Help->Keyboard Shotrcuts Reference」から現行のショートカットキーが確認できるのでそちらを確認いただきたい)

VSCodeには豊富な機能が存在しており、それらの殆どはショートカットキーで使用可能だ。Visual Studio(以下、単にVS)を普段遣いしている身としては、同じキーバインドで同じ様な機能が使えるのが非常に嬉しい。しかし勿論完全互換というわけではなく、VSCode独自の機能に対応するためVSと違うキーバインドになっているものもある。

以下コマンド例。

キー 動作 コマンドID
Ctrl+X 行の切り取り (未選択時) editor.action.clipboardCutAction
Ctrl+C 行のコピー (未選択時) editor.action.clipboardCopyAction
Ctrl+Shift+K カーソル行削除 editor.action.deleteLines
Ctrl+Enter 下に行追加 editor.action.insertLineAfter
Ctrl+Shift+Enter 上に行追加 editor.action.insertLineBefore
Alt+Down カーソル行を下に移動 editor.action.moveLinesDownAction
Alt+Up カーソル行を上に移動 editor.action.moveLinesUpAction
Shift+Alt+Down カーソル行を下にコピー editor.action.copyLinesDownAction
Shift+Alt+Up カーソル行を上にコピー editor.action.copyLinesUpAction
Ctrl+D 次のマッチを選択に追加 editor.action.addSelectionToNextFindMatch
Ctrl+K Ctrl+D 次のマッチに移動 editor.action.moveSelectionToNextFindMatch
Ctrl+U カーソル動作のUndo cursorUndo
Ctrl+Shift+L 選択部分の全マッチを選択 editor.action.selectHighlights
Ctrl+F2 選択ワードの全マッチを選択 editor.action.changeAll
Ctrl+Alt+Down カーソルを下に追加 editor.action.insertCursorBelow
Ctrl+Alt+Up カーソルを上に追加 editor.action.insertCursorAbove
Ctrl+Shift+] 対応する括弧に移動 editor.action.jumpToBracket
Ctrl+] 行にインデントを追加 editor.action.indentLines
Ctrl+[ 行のインデントを削除 editor.action.outdentLines
Home 行の先頭に移動 cursorHome
End 行の末尾に移動 cursorEnd
Ctrl+End ファイルの末尾に移動 cursorBottom
Ctrl+Home ファイルの先頭に移動 cursorTop
Ctrl+K Ctrl+C 行コメント記号を追加 editor.action.addCommentLine
Ctrl+K Ctrl+U 行コメント記号を削除 editor.action.removeCommentLine
Ctrl+/ 行コメント記号をトグル editor.action.commentLine
Shift+Alt+A ブロックコメント記号をトグル editor.action.blockComment
Ctrl+F 検索 actions.find
Ctrl+H 置換 editor.action.startFindReplaceAction
F3 次を検索 editor.action.nextMatchFindAction
Shift+F3 前を検索 editor.action.previousMatchFindAction
Ctrl+M タブでフォーカス切り替えモードをトグル editor.action.toggleTabFocusMode

特におすすめのものについては以下でも個別に見ていくのでその時にも示そうと思う。

ディレクトリ単位で開ける

VSCodeは複数のファイルをタブ形式で同時に開くことが出来るのだが、それらのファイルを特定のフォルダに入れておくことで、それを一つの単位として開くことが出来る。こうすると、フォルダ内のファイルがエクスプローラーに表示されるようになる。タブで開いておくと次回開いた際にも同様に開いてくれる。エクスプローラーについては左のメニューのファイルマークみたいなのを選択 or Ctrl+Shift+Eで出せる。以降はCtrl+Bでサイドメニューの表示をトグル出来る。

フォルダとして開くにはまだフォルダを開いていない状態でエクスプローラーのサイドバーを開き、「フォルダーを開く」を選択して、開いたウィンドウで開きたいフォルダを指定する。

f:id:makiofinae:20180322142113g:plain

タブでファイルを開いた際はCtrl+TabもしくはCtrl+Shift+Tabでタブを切り替え出来る。

マルチカーソルが便利

VSCodeでは、マルチカーソルといって、複数箇所に同時入力することが出来る機能がある。簡単なものをリストアップするとこういった感じだ。

機能 使い方
マルチカーソルを追加 Alt+Click
マルチカーソルの拡大 Ctrl+Alt+Up(Down)
マルチカーソルの解除 Esc
選択範囲と同じ文字列を追加選択 Ctrl+D

マルチカーソルの追加 f:id:makiofinae:20180322142202g:plain

マルチカーソルの拡大 f:id:makiofinae:20180322142206g:plain

選択範囲と同じ文字列を追加選択 f:id:makiofinae:20180322142208g:plain

これが結構便利なので是非使いこなして欲しい。

選択が楽

VSCodeではVS同様Ctrl+Left(Right)で文字列単位もしくは英単語単位で移動ができるので、この時Shiftを押しておけば文字列単位もしくは英単語単位で選択ができる。

f:id:makiofinae:20180322142400g:plain

また、Alt+Shiftを押した状態でドラッグアンドドロップすることで矩形選択をすることも出来る(VSではAlt+Shift+矢印キーで矩形選択できたが、VSCodeではAlt+Shift+Up(Down)が「上(下)に現在の行をコピー」になっているので出来ない。またVSと違い矩形選択に対する置換は出来ない模様)。

f:id:makiofinae:20180322142415g:plain

コメントアウトが楽

VSCodeではCtrl+/で行のコメントアウトが出来る。VSと同じくCtrl+K,Ctrl+CコメントアウトCtrl+K,Ctrl+Uコメントアウト解除が出来るが、VSと違いこちらは行コメントアウトのコマンドになる。

f:id:makiofinae:20180322142432g:plain

選択箇所などブロックでのコメントアウトにはShift+Alt+Aを使う。

f:id:makiofinae:20180322142440g:plain

全体の表示

編集場所の右にはコード全体を縮小したものが表示されていて、全体の構成がどの様になっているのか大まかに知ることができる。また、マウスオーバーすることでそのうち画面に映っている場所がどこかも教えてくれる。

f:id:makiofinae:20180322142452g:plain

行ごと移動

Alt+Up(Down)でカーソルがある行を上下に移動させることが出来る。移動する時は移動先と行を交換する形で移動する。

f:id:makiofinae:20180322142805g:plain

インデントの追加(削除)

Ctrl+]([)でインデントの追加(削除)を行える。

f:id:makiofinae:20180322142825g:plain

gitとの連携

git使用時に行番号の右の色のついた部分をクリックすると差分を確認できたりと、gitとの連携も取れていて便利。

変更前と変更後を左右に並べて、全体の変更点について確認も出来る。

拡張機能

VSCodeではユーザーが公開した拡張機能を使うことが出来る。これは所謂他のソフトでアドオンやプラグインと言われる機能だが、これによってデフォルトのままでは痒いところに手が届かずとも、何処かの誰かが作ってくれた便利な拡張機能のおかげで自分の好きな環境を構築することが出来るようになる。

markdownに便利な機能

言語モード

VSCodeでは、言語モードに基づいてその言語にあったシンタックスハイライト等をつけたりする。また、Ctrl+K,M(Ctrl+K,Ctrl+Mではない事に注意)を押すと検索窓が開き使用する言語モードを明示に指定できる。基本的に自動検出されると思うが、シンタックスハイライトがおかしい時等はこれでMarkdownを選択する。

f:id:makiofinae:20180322142552g:plain

プレビュー

markdownのプレビューを見るにはCtrl+Shift+Vで開く。プレビューはリアルタイムに更新されるので、プレビューを表示しながら編集したければ、プレビューを開きそれをCtrl+Alt+Right(右に画面を分割して追加)等で横に移すか、Ctrl+K,Vでプレビューを横に開く。タブで切り替えをしてもその表示されたタブのプレビューを表示してくれるので便利。

f:id:makiofinae:20180322142612g:plain

また、プレビューで何処かを選んでダブルクリックするとエディタ内のその箇所にジャンプすることが出来る。

インジケータ

編集時にプレビュー側に編集箇所を示すインジケータが出るので、そのおかげでプレビューでいうところのどの部分を編集しているのかがわかりやすい。

目次の自動生成

参考:vscodeの AlanWalk/markdown-toc extensionで目次の自動生成すると捗るぞ

markdownの目次を手動で管理するのは流石にアホらしい。自動で生成したいが、デフォルトのままではそういった機能は今の所ない。そこで目次を自動生成する拡張機能を入れる。

右のメニューの一番下の拡張機能マークを押して拡張機能サイドバーを開いたら、その中にある検索窓にmarkdown-tocと入力する。そうしたら恐らく一番上に出てくるAlanWalkさんのMarkdownTOCをインストールする。

インストール出来たら、目次を生成したい所で右クリックしてメニューからMarkdown TOC:Insert/Updateを選択するか、Ctrl+M,Tと押す。するとその位置に目次が生成され、ファイルが保存される度に自動で更新されるようになる。

もしも全ての項目にセクション数を追加したいのであれば(例えばこのセクションは4.8.3になる)、右クリックして出したメニューからMarkdown Sections:Insert/Updateを選択するか、Ctrl+M,Sと押す。

これで目次の自動管理が可能になった。

因みに拡張機能の設定を変更することで目次に表示する項目の深さ(デフォルトだと1から6まで)を変更できるが、これは以下のようにすることでファイルごとにも変更できる。

<!-- TOC depthFrom:2 orderedList:true -->

<!-- /TOC -->

詳しくはこの拡張機能OverView等を参照のこと。

なお、この記事の目次ははてな記法で自動生成しているのでこれは使っていない。

入力補完

VSと同様、入力中にCtrl+Spaceと押すことで入力を自動補完出来る。ただし、IntelliSenseのみならずスニペット等も合わせて表示される。

f:id:makiofinae:20180322142849g:plain

スニペット

スニペットとは、一般的には「切れ端」「断片」という意味の英語である。IT用語としては、プログラミング言語の中で簡単に切り貼りして再利用できる部分のこと 引用元

自動補完で表示が可能なことは先程示したが、VSCodeではこれも自分で定義できる。

自作スニペット

参考:独自のスニペットを作成

自作のスニペットを作るには上のメニューから「ファイル->基本設定->ユーザースニペット」と選択する。そうすると検索窓が出てくると思うので、markdownと入力してmarkdown.jsonを選択する。するとmarkdown.jsonが開くのでここに入力していくことになる。markdownに限らずスニペット(languageId).jsonに保存する。

形式は

 "スニペットの名前":{
        "prefix": "自動補完の際にトリガーとなる文字列",
        "body":["置き換えられる文字列"],
        "description": "説明文",
    }

となっていて、これをデフォルトで書き込まれている{}のブロックの中に追記すればスニペットが追加できる。

bodyの置き換えられる文字列については

"body":[
            "1行目",
            "2行目",
            "3行目"
        ],

のように行にまたがって指定することが出来る。

例えば、横2縦3のテーブルに置き換えるスニペットであれば

 "create table":{
        "prefix": "table",
        "body":[
            "|col1|col2|",
            "|:--|:--|",
            "|ele1|ele2|",
            "|ele1|ele2|"
        ],
        "description": "2x3 table",
    }

と追加して、tableと入力して自動補完からスニペットを選択すると

|col1|col2|
|:--|:--|
|ele1|ele2|
|ele1|ele2|

と入力されるわけだ。スニペットの機能自体はもう少し特殊な構文もあり、色々とやれることはあるのだが、ここでは割愛するので参考ページを参考のこと。

みんなちがってみんないい(本当か?)

すごく簡単なことだけど、人は皆違っている。生まれた時や、過ごしてきた時間や場所、その他とても多くの要素が思考や、もしかすると身体をも形作る。ある人とある人の歴史が違うから、それらの人は違う、という論だとそれはどうだか怪しい気もしてくるが(客観的体験が違うからと言って主観的体験も違うか、またそこから生じる思考も違うかというとそれを論理的に裏付けるのは難しそうだ)、少なくとも全く同じ思考が築かれるよりは皆が違っているほうがよっぽど妥当だと僕は思っている。仮に全員が違わないとしても、違う思考を持つ人がいる、というのはわかるだろう。全員が完全に同じ思考をもっているのだとしたら、通信技術はここまで発展しただろうか。考え始めると色んな矛盾が出始める。よってここでは仮に全員が違わないとしても、少なくとも全員が同じではなく、違う思考を持った人がいる、と考える。

しかし、私たちはそのことを忘れがちである。自分が特定の道を通って体得した何かについて、他者がそれを体得できないことについて疑問を抱いたり、自分が当然に理解できることが他者には理解できない時に戸惑ったりする。さらに奢りが生まれると、自分ができることについては当たり前に「みんな」が出来ることだと思い始めるのである。人に得意不得意があることを忘れたりする。例えば、コミュニケーション能力を要求されるとキレる割に、調べて問題解決する能力がない人やそうやって解決できる事を知らない人に「それくらいやれ」と断じたりする。だから世界に争いはなくならない(すぐにスケールを無駄に大きくした事を言いたがる)。

タイトルに「みんなちがってみんないい」と書いた。「みんなちがって」の部分は以上の通りだ。立証できないので仮説に過ぎないが、僕はこれについては確信している。これを忘れなければ、非常に不合理な押しつけなどはなくなるだろう。

「みんないい」の部分については更に難しい。ここで僕がいいたかったのは違いがあるということはそこが強みになりうるということだ。1次ソースが確認できないので真偽は定かではないが、任天堂の岩田前社長のものとされる言葉に

「自分の長所を見つけるには、自分が楽にできることを探すこと」

というものがある。人は苦労して何かを身に付けると、それにすごい価値があると思い込みたがる。しかし、実は自分は何気なくやってるけど他の人は結構苦労してる物があって、そういうものこそ価値を生む、という事が言いたかったとして紹介されている。

僕はこれに関してその通りだと思う。一生懸命苦労して身につけたものが無駄だと言いたいのではない。人には違いがあって、つまりは得手不得手があって然るべきだ。だから、そのことを忘れず、自分の得意を活かし、他人の不得意を慮る、そういうことが全員がうまく生きられる経済的(ここではいわゆる社会経済の経済というよりは、限られた財を適切に分配すると言ったような経済学等に使われる方の意味の経済)な方法だと思うのだ。

だから僕は題を「みんなちがってみんないい」と書いた。本当か、とつけたのは、みんないい、というわけではないからだ。違いがあることが強みになるとしても、その強みにも程度がある。そしてそれが社会にどの程度評価されるかということもものによって違う。場合によっては社会に評価されないが他人と違う事によってあることについてとても秀でているということがあるかもしれない(寸分違わず狙った場所に輪ゴムを飛ばせる、とか)。それがいいとか悪いとかは正直僕にはわからない(よって本当か?とつけた。みんなよかったら社会に苦しい人はいない)。ただ僕がいいたかったのは、人は違うから、自分にとっての当たり前を他人に押し付けてしまう前に疑おう、みたいなそういう話なのだ。

但しこれを「全員に考えてくれ」、と言うことに関しては問題がある。これは常に思考をして、最善ではなくとも改善をしていこうとする時に常にぶつかるメタな問題だ。それは「以上のことを考えながら生きる」という主張は、思考コストが高い人々への押しつけになり、それこそ人の得意不得意を考えない非合理的な押し付けになってしまうということだ。この主張は、「最善へ向けて改善をすることを目指して常に考え続けたい思考コストの低い人間」のエゴであるとも言えてしまう。コミュニケーション能力の低い人物に無理にコミュニケーションを強いることは許されるだろうか。正当化をしようとすることは出来るかもしれないが、僕はそれは良くないことだと思う。自分が支払うコストが小さいからといって、相手にも同じものを強いるのは安全圏からマウントをとっているようなものになりえないだろうか。そういったことを危惧してしまうのである。 同様に、こういった問題への思考コストが高い、ぶっちゃけていうと面倒くさいと考えている人物に、こういった意見をぶつけてこれからはこういったことを考えながら思考を改めよ、というのは良くないのではないだろうか。

だが、強制しないにしても、こういったことを誰かが言わないと気付けない、という面もあるかもしれないなと思い、思ったものをそのまま書き殴る形になったが、少し吐き出してみた。皆さんはどう思うだろうか。

チャールズ・ケリー氏著の『入門ゲームプログラミング』を読んで

チャールズ・ケリー氏著の『入門ゲームプログラミング』を読了しました。記録として、そして他の方の参考のために感想を書いておこうかと思います。

まず、自分はこの本をDirectXの勉強のために購入しました。しかしDirectXと言っても、DirectX11や12へどういった変遷をしていったのかを知りたい、また、DirectX11や12に直接初心者が入門する為の書籍等は少ないがDirectX9からステップアップする書籍等は幾らかあるといった理由から、現在多く使われている様なDirectX11や12ではなく、DirectX9を勉強したい思いで購入しました。DirectX9を勉強する上で有名なDirectX 9 シェーダプログラミングブックは現在既に絶版になってしまっているらしく、新品が多く流通していない現状のため、取り敢えずDirectX9を使っているらしいことと「入門」と銘打っている事からこの書籍を購入しました。

読んでみた正直な感想としては、

  • どの層をターゲットにしているのかイマイチわからない
  • どこまでがDirectXの話でどこからが本書で使っている自作クラス・関数の話なのかが区別が非常につき辛い
  • 見やすくまとめようと言った配慮はあまりない
  • 本書掲載分だけではなく、サンプルコード全体を見ないと理解しづらい場所がある

と感じました。

まず、どの層をターゲットにしているのかイマイチわからない、ということについてですが、この本はタイトル通り基本的にゲームプログラミングの基礎的なことに触れていくのみで、本当にそれを超えたことはあまりしないのですが、その割には初学者にとっては敷居が高いDirectXをフワッとした説明のみで使い、少し置き去り感があります。どうしたって本書以外で補完しないと、DirectXが「よくわからないもの」にしかならないと思います。おそらく少しDirectXには触ったことがある人間が読んで初めて違和感がないのではないでしょうか。 しかしそれに反して、それなりのゲームを作ったことがある人にとってはあまり新規性のない事ばかりが書かれています。具体的にゲームを作っていく過程を追っていく感じなのですが、ゲーム制作経験のない人にとっては良いものかもしれないですが、経験がある人からするとほぼ全て知っていることなので時間の無駄になると思います。 こうなると、「ゲームは作ったことはないけどDirectXはわかっている人間」が対象になるのですが、こういった人って非常に限られていると思うのでまさかこれをメインターゲットにしているとは思えなく、どの層をターゲットにしているのかイマイチわからないなあ、という風に思いました。

次に、どこまでがDirectXの話でどこからが本書で使っている自作クラス・関数の話なのかが区別が非常につき辛い、ということについてですが、これはそのままで、作者が作ったクラスの説明も本書ではされるのですが、それがDirectXの機能として提供されているものなのか、勝手に作者が作ったものなのかの判別が付きづらく、DirectXを勉強したいだけであって作者の趣味に付き合いたい訳ではない読者にとっては非常に厄介な存在となっています。この点に関しては本当に致命的なのでもっとしっかり明示するようにしていただきたいなと思いました。

次に、見やすくまとめようと言った配慮はあまりないという点についてですが、なんというか、あくまでも説明はプレーンテキスト風から離れないぞという意思の感じられる構成になっていて、読めなくはないもののここはもっとこうした方が読みやすいよなという所が満載で、そこまでは手が回っていないんだろうなというのを全体から感じました。

次に、本書掲載分だけでなく、サンプルコード全体を見ないと理解しづらい場所がある、ということについてですが、本書では本書で順を追って作成していくプログラムについて、公式のサポートから無料ダウンロード出来るようになっています。本書にもソースコードが必要な分引用して記載されていますが、正直必要最低限という感じがある所が幾らかあって、全容をつかむにはやはりそのダウンロードしたソースコードで全体を見る必要があると感じました。おそらくそういった形で学習を進めてほしいというのが本書の意図でしょう。もし書籍のみで取り敢えずの概観を掴みたいという方がいるのであれば、本書はあまりオススメしません。

と、ここまで書いてきてネガティブな話ばかりになってしまったのですが、名前の通りゲームプログラミングをするにあたっての入門的な事は一応ひとしきりしているように感じるので、初心者の人が斜め読みして雰囲気をつかむ分には良いのではないでしょうか。それにしてはボリュームとお値段がなかなかな気はしますが…

それと、数カ所誤訳なのかソースコードでしていることと説明文とが一致していないところがありました。そういった意味でも斜め読み推奨です。

得たものがないかというとあるにはあるのですが、それにしたってもっとコストをかけずに得られたのではないか、と思わせられてしまう一冊でした。

多倍長整数をstd::stringを使ってゴリ押し実装してみた

目次


初めに

前置き

どうも、いなえのまきです。

この記事はCCS Advent Calendar 2017の6日目として書かれた記事です。

前日の記事 by ユーマ

次の人→珈琲王子

どうも今年は裏アドベントカレンダーなるものもあるらしいので気になる方はそちらも是非。

去年はCCS Advent Calenter 2016にも参加しました。記事はこちら


動機

さて、別に何をやるとも決めていなかったので、「コンピュータ上での文字周りのことについて勉強してまとめて、それを記事にしてあげるかなあ」くらいのノリでアドベントカレンダーに参加してしまったのですが、思ったよりもやることがあったのと、少し調べてみると結構な分量と労力になりそうな事がわかったので、文字周りの話は余裕がある時にまた記事をあげることにして断念しました。

そこで、何か楽に書けるふさわしい題材がないかと思った時に、過去に楽しそうと思って書いてみた多倍長整数のコードを思い出した感じです。

多倍長整数自体は結構色々なライブラリで実装されてたり、言語によってはデフォルトでサポートされてたりするそうなので、そもそも自分で作る意味がない(車輪の再発明)なわけなんですが、面白そうなので作ってみたという経緯があります。その為、新規性はないです(1年ぶり2回目)が、個性を出せるように頑張ってみたのでどうぞ。

多倍長整数

多倍長整数って?

Wikipediaを見ると、

任意精度演算とは、数値の精度を必要ならいくらでも伸ばしたりできるような演算システム(実際上は利用可能なメモリ容量に制限されるが)による演算である。

とした上で、

多倍長整数などを内部処理に利用し、必要な桁数の浮動小数点計算を行う

という風に書かれています。

何となくイメージはつかめるかと思いますが、こちらのサイトにあるように

多倍長整数とは、コンピュータに巨大な整数を扱わせるための仕組みである。

こういったものです。

Cなんかでいうint型なんかは扱える数の大きさに定められた制限があります。これはハード側で高速に演算等を行う為らしいのですが、そのせいでその制限以上の大きさの値を扱うことが出来ず困る場面もあります。これを解決する為に用いられるのが多倍長整数といったものです。多倍長整数は、制限なく大きな整数を扱うことを可能にしてくれるのです(実際にはメモリの容量等ハードの制限はありますが)。

よくある方針

ここここここここ当たりを見てる感じ、基本方針としては、整数の配列やリスト等を用意してやって、それらを1つの数として扱うアルゴリズムを実装していく感じが多いみたいですね。

どうやったの?

以前僕が書いたものも内部的にはこれに結構近い感じのものだったのですが、少し特色付けたいなと思って僕が目指したのが、std::stringを使って多倍長整数を実装するという方法です。

何故これにしたかというと、

  • std::stringが勝手に長さを調整してくれるので、メモリの確保や解放の処理を自分で書かなくていいので楽な上メンテナンスしなくていいから
  • いくら大きな値を扱えるようにしてもBigInt a=9999999999999999999999;みたいに書くと定数が大きすぎるとして怒られてしまうが、BigInt a="9999999999999999999999";という風に書けるようにすればこの問題は解決する。その上で内部で数字を文字列で持てば、初期化や代入周りの処理が超楽に書ける
  • str_var[i]とすることでi番目のcharを取り出せるので、n桁目を取得するのが楽*1

みたいな目論見はあったわけですが、正直一桁あたりにchar分の1バイト使ってるのでとてもメモリが無駄になる上に、高速な計算も特に思いついていたわけではなかったので、正直な所演算子オーバーロードを手で書いて覚える練習がしたかったみたいな色合いが強かったです。内心実用には耐えないだろうなあとか思いながらも楽しそうだからというだけで書いてました、ハイ。

ただ、インターフェースを綺麗にするというか、ユーザーが違和感なく使えるようなクラスを考えるのって難しいんだなあとか、あっちを立てるとこっちが立てるでどうにもならんなあというところとかが出てきて、ライブラリ開発者様等の神の凄さを実感して、そこは勉強になりました。

実装

全体の方針

最終目標は、std::string型で保持している整数(以下文字列整数)を持つ自作クラスを、int型と同じ使用感で使えることになります。

そのためにまず、文字列整数をint型と同様に扱えるようにすることを考えます。

そのためにまず文字列整数同士の加算と減算、比較をする関数を用意します。そしてその必要最低限の関数を使って演算子オーバーロードしていきます。

その他雑記

注意すべきは内部処理でint型に変換してしまうと、実質精度がint型と同じなってしまう点に気をつけることです。

演算子オーバーロードでは、他のオーバーロードを出来る限り内部で呼ぶ形にすることでDRY原則に従い、メンテナンスのコストを下げようとしたのですが、加算と減算は場所によってはその場で定義してしまってます(別の演算子呼ぶより早いかな?とか思ったので。もしかしたらコンパイラが最適化してくれるから気にしなくていい系案件かもしれませんが…)。よって少し統一感の無いコードになってます。

あと、char型の数字(文字の内部的な数値ということではなく'1'とかのこと)を単純にint型にするのが地味にどうしようか迷いました。

加えて、実は

BigInt x = BigInt(0) +"2";

みたいな記法を許せるように「BigIntとstd::stringの+演算子」もオーバーロードしてたんですが、intへのキャストを暗黙のキャストも許可して定義した(これはintと同じく自然に使えるようにするため)影響でBigInt(0)が暗黙にint型にキャストされた場合というのも考えないといけなくなってしまい、組み込み演算である「integerとpointer-to-objectとの+演算」とどちらの演算子を使っているのかというのがコンパイラが判断できずエラーを吐くという結果になったので、これについては断念しました。

もう後は見ておくれ

正直そんなに語る所もない内容なのでソースコードだけ貼っつけとくので後はご自由に御覧ください(丸投げ)

多倍長整数bigintbignumといったような名前にする慣習があるらしいのですが、なんかそこまで言うのがおこがましい感じがしたのでちょいデカ目のintくらいのつもりでlonger_intという名前にしました。

何か不足している所や間違っている所があったら教えてください。

以下ソースへのリンク

*1:だと思っていたがそうでもなかった

Fortniteというゲームについて

初めに

最近少しずつ話題になってきているFortniteというゲームについて、あまりに情報が少ないので、少しプレイしただけですが、現時点でわかっている事を書いておこうかと思います。

基本言語が英語なこともあって、初見だと戸惑う所もあるかもしれませんが、これを読んで少しでも楽にプレイできたらと思います。

Fortniteって?

PvP(プレイヤー同士のオンライン対戦)モードに限って話すと、PUBGとマインクラフトを足した感じのゲーム性です。

つまりは多くのプレイヤーで同時に島に降り立ち、そこに置かれた物資(武器・回復道具・素材等)を回収して、戦いつつ、適宜壁や階段を作り、最後の1人になった人が勝ち、という感じです。

簡単にイメージを掴みたい人はこちらの動画を御覧ください。

youtu.be

PUBGでいうところのSQUAD(4人1組でのチームプレイ)も存在します。

PvE(CPUとの対戦)モードはムービーを見た限り、L4D2とマインクラフトを足した感じのゲームなんでしょうか。メタルギアサヴァイヴを思い出しました。

いくらなの?

2017年10月8日現在、アーリーアクセスなのでPvPは無料で遊ぶことが出来ます。2018年中にPvEモードも無料になるそうです(今も課金することでプレイできるみたい?)。

入手方法

  • 公式サイトPLAY FREEをクリックします。
  • Epic Gamesアカウントを持っていたらSIGN IN、持っていなければSIGN UPを押します。
  • インストーラーがダウンロードされるので、指示に従ってインストールします。

起動方法

Epic Games Launcherを起動して、タブがFORTNITEになっていることを確認し、起動をクリックします。

f:id:makiofinae:20171008015026p:plain

プレイ方法

起動後BATTLE ROYALEをクリックします。

f:id:makiofinae:20171008015508p:plain

参加方法

ソロプレイする場合

Match Type:Solo、Squad Fill:No Fillのまま、Playを押します。

チームプレイする場合

友人等とプレイする場合はまずフレンド登録が必要です。まず右上のフレンドのボックスをクリックします。 f:id:makiofinae:20171008020524p:plain

ドロップダウンしてきたリストのタブのうちAdd Friendをクリックし、フレンド登録したい人のIDを入力し、ADDを押した後、相手に承認してもらいます。

プレイヤーのキャラクターの横にある+マークをクリックして招待します。

もし友人と合わせて2人しか身内にはいないが、4人でプレイしたいと言うような時はSquad FillをFillにします。

4人チームのゲームに、2人のみで参加するのでかまわない場合はSquad FillをNo Fillにします。

ルール

1つの島に沢山の人間が着陸して、最後の生き残りになるべく戦います。ソロプレイの場合は体力がなくなると終了です。

チームプレイの場合は、体力がなくなっても即時死亡ではなく、気絶するだけです。チームメンバー全員が気絶するか、気絶させられた後もダメージを受け続けると、死亡扱いとなり終了です。

操作方法

基本操作

操作方法についてはまず列挙しようと思います

  • 移動:WASD
  • 走り:Shift
  • しゃがむ:Crrl
  • ジャンプ:Space
  • 攻撃/設置:左クリック
  • 狙う:右クリック
  • 使用、拾う等のアクション:E
  • マップを開く/閉じる:M(or Tab)
  • インベントリを開く:I(or Alt)

これらは書いてある通りなので特に詳しくは触れません。

ただ一つ言うことがあるとすれば、右クリック長押しで狙うことが出来ますが、このゲームではADS(サイトを覗くこと)は基本的には出来ず、三人称視点の状態で画面の中心に向かって射撃することになります。しかし例外があって、スナイパーライフルの場合は覗き込んで射撃することになります。

飛び降り

メッセージが出てくるので問題ないかと思いますが、PUBGと違い、島に降下するのに押すキーはSpaceです。

また、地表から近いパラシュートを強制される一定よりも低い高度を除いては、パラシュートを開いたり、もう一度閉じて自由落下したりをSpaceで切り替えられます。

建築

さて、このゲームでは通常モードと建築モードとでも言うような2つのモードが有り、それらをQキーで切り替える事ができます。

通常モード

通常モードにおいては、ピッケルや銃・アイテム等が使用できます。建築モードで何かを立てるための資材を集めるためにピッケルで様々なものを壊す時や、敵と交戦する時等、プレイ中の殆どの時間をこのモードで過ごします。

マウスホイールで手に持つものを順に変更でき、数字キーなどを使って指定のものを手に持つ事もできます。

手に持つ事のできるもの、つまりカバンに入っているアイテムは、下のスロットに表示されています。

建築モード

建築モードにおいては、フィールド上に壁・床・階段・屋根・その他オブジェクトを設置できます。コレを使って敵から隠れたり、銃弾を防いだり、高い所に登ったり、どこかに渡ったりします。

同じくマウスホイールで建築するものを変更できます。左クリックで設置しますが、右クリックすることでその建築物の材質(=材料)を木→レンガ→鉄→木→…と変更することが出来ます。

全ての建築物は、その建築物の材質の素材を10消費して建築できます。

その他備考

武器やアイテムの取得

基本的に光ったオブジェクトが家の中などの床の上に浮いているのでそれを拾う感じです。

しかし稀に光る金色の宝箱が落ちているためそれをEで開けることで取得することも出来ます(レアなものが出る確率が高い気がする)。

金の宝箱は音を発しているので、家の中などで不思議な音がしたら屋根裏など音のなる方を探してみましょう。宝箱は叩いて壊した場合武器やアイテムを出さないので注意が必要です。宝箱が設置された床を壊した場合も同様なので注意しましょう。

他にも鉄の箱を開ける音でアイテムを手に入れられたりもします。こちらは光ってもいなければ音も出ていないので見落とさないようにしましょう。

木を切り倒すとそのなかに武器やアイテムがあったりすることもあるらしいです(僕は見たことないです)。

持ち物

基本的にアイテムは5スロット分、つまり最大5種類までしか持てないようです。ただ、武器以外の特定のアイテムは、同種類なら重ねられるようです(Bandageを10個もつ、等の場合でも1スロットのみしか消費しない)。

銃弾については通常の範囲内では制限はないようです、自由に持てます。

木・レンガ・鉄等のフィールド内オブジェクトをピッケルで殴る事で得られる資材についても、制限はないようです。

武器の種類

武器は確認できた範囲だと、

  • ピストル
  • ハンドガ
  • サブマシンガン
  • ポンプアクションショットガン
  • セミオートショットガン
  • セミオートライフル
  • スナイパーライフル
  • ロケットランチャー(自分で手に入れたことはない)
  • グレネード

等があるようです。

アイテムの種類

  • 包帯(一定量を回復。ただし上限は75まで)
  • 応急セット(全回復)
  • シールドポーション(数敵弾を受けても代わりに消費する事でダメージを受けないようなシールドを50付与)
  • 各種弾薬

武器のレアリティ

同じ種類の武器でもレアリティによって性能が違うようです。レアリティは武器に付いている☆の数で表されます。また、レアリティによって武器についているオーラの光の色が変わるのでそれで判別することも出来ます。

PUBGとの違い

ここまでであまり触れていない所をメインに書くと

  • 大分軽いように感じる。ロード等も一瞬だし、通信でカクつくことはあっても処理でカクつくことはない
  • PUBGのように草むらに隠れたり、と言ったプレイは難しそう(出来なくはなさそうではあるけど…)
  • フリールックは存在しないので前しか見れない
  • パラシュート周りが非常に操作感が良く、基本的に思った位置に降りられる
  • パラシュートがよくわからない所に引っかかったりしない
  • ブースト系アイテムがない
  • かわりにシールド?アイテムが有る
  • 銃のカスタムは出来ない?(要確認)
  • ADSが基本できない
  • 設定を変えないとRevive中などキーを押しっぱなしにする必要がある(押してから待つのではない)
  • 操作感がアクションチックで非常によく、意図しない動きをすることが非常に少ない
  • カメラが荒ぶる率が少ない
  • 銃を拾ったらデフォルトでワンマガジン分は弾が入っている
  • 応急キット的なアイテムが全回復
  • 乗り物がない(オブジェクトとしてはあるが乗れない)
  • 島が少し狭い?

というかんじ

最後に

PUBGとはまた違った楽しさがあるよ!!是非皆もやりましょう!!

DXライブラリのパスワード付きアーカイブ機能を楽に使いたかったので適当なソフト作った

前置き

はい、完全にタイトルのとおりです。

※追記:バッチ処理でやる方が楽かもしれないのでそれについてはこちらを参照のこと

そんなに大したこともしてないし、そもそも需要があるのかわからないので自己満足なんですが、一応軽く説明しておきます。

ツール自体は「ツール(EasyDxArchive)について」のところにリンクがあるので、注意書きを読んでお使いください。

DXライブラリ(DxLib)とは?

これをそもそも知らない人は別にこの記事を読んでも何も嬉しいことがないと思います。

という事で、ここでは説明を割愛します。

アーカイブ機能について

アーカイブ機能とは?

DXライブラリは、ゲームを作るのに役立つ機能を提供してくれていますが、実はライブラリそれ自体以外にもツールを提供してくれていたりします。

それらのツールは、DxLib_VCというDXライブラリについての様々なファイルが入っているフォルダ直下のToolというフォルダ内にまとめられています。(C:\DxLib_VC\Toolだったり)

その中の1つがここで言うアーカイブツールです。アーカイブについてはこちらのDXライブラリ置き場でも参考にしてください。

まあ簡単に言うと、ゲームの素材(画像やら音やら)をそのままゲームのexeファイルと一緒に配布してしまうと中身が丸見えになってしまって、ネタバレが起きたり素材を流用されてしまったりとか有り得るよね、みたいな色々な要請から、簡単には中身が見えないようにするのがアーカイブ化と呼ばれるもので、これをするのがアーカイブ機能です。

そして勿論、DXライブラリはアーカイブ化した素材(つまりアーカイブファイル)も読み込むことが出来るようになっています(対応しているものなら)

パスワード付きアーカイブ機能とは?

さて、本来DXライブラリについてくるアーカイブ化ツールは、フォルダをDxaEncode.exeにドラッグ・アンド・ドロップすればアーカイブファイルを作ってくれるという楽に使えるものです。しかし、それだと問題がある部分があります。作ったアーカイブファイルをDxaDecode.exeドラッグアンドドロップすると簡単に元ファイルに戻せる(デコード出来る)のです。これではアーカイブ化しようとしている要請を満たせていないですね。

そこで、DXライブラリのアーカイブ機能は、パスワードによって、DXライブラリからの素材の読み込みやデコードを制限することが出来るようになっています。

例えばパスワードにosageを指定してアーカイブ化すると、デコード時にそのパスワードを入力しないとデコード出来ないし、DXライブラリから読む時も、ある関数でパスワードがosageであると指定してやらないといけなくなるわけです。

パスワード付きアーカイブ機能の面倒な所

パスワード付きアーカイブ機能は便利なのですが、1つ面倒なことがあります。それは、さっき言った「フォルダをDxaEncode.exeにドラッグ・アンド・ドロップ」するという方法が使えないということです。

パスワード付きアーカイブ機能の場合は、コマンドプロンプトからオプションをつけてコマンドとして実行する必要があります。少し面倒ですね。ファイル階層が複雑なところにあったりすると、素材がリリース間近で更新される度にこれをやるのはとても面倒です(経験談)。

今回、これを楽にできないかということで手が空いていたので、よくわからないC#を適当に叩きながら2時間位でこのツールを作ってみました(雑)

拡張子について

アーカイブ機能で製作したアーカイブファイルの拡張子はデフォルトでは.dxaなのですが、これではDXライブラリのアーカイブファイルだと一瞬で分かる人にはわかってしまいます(結局readme等に権利関係を記載する必要がありわかってしまうじゃん、という話はあるのですが)。

そこでDXライブラリにはアーカイブファイルの拡張子を変えても読み込める機能が備わっています。プログラム内で関数から拡張子を指定してやることで.dxaではなくともアーカイブファイルを読み込めるようになります。

しかし、結局アーカイブツールから生成されるアーカイブファイルは*.dxaなので、これを手作業で例えば*.osg等と変えてやる必要があるのです。

…面倒ですよね。これもツールの側で指定して一気に変更できるようにしておきました。

ツール(EasyDxArchive)について

注意書き

C#がよくわかっていない初心者が適当に作ったツールです。

したがって、このツールを使った事による損害等についてはこちらでは責任は取りかねるということをご了承の上お使いください。どうでもいいファイルで一度試してみることを推奨します。

バグの報告などは受け付けておりますのであったら報告がいただけると嬉しいです。

また、使用に関しては自由にして頂いても構いませんが、ソフトそのものの二次配布等についてはご遠慮ください。

置き場所

こちらからダウンロードしてください。

exeファイル1つというとてもシンプルなものですので好きな所に置いて使ってください。

ツールの使い方

起動するとこんな感じのウィンドウが開きます。 f:id:makiofinae:20170910142354p:plain それぞれのテキストボックスは、

  • Program Adress : DxaEncode.exeのアドレスを指定
  • Data Adress : アーカイブ化したいファイル(フォルダ)の置いてあるフォルダを指定
  • Target File Name : アーカイブ化したいファイル(フォルダ)を指定
  • Password : パスワードを指定
  • Extension : 拡張子を指定(.は要らない)

という構成になっているので、自分がしたい設定をし、「Make Archive!」ボタンを押します。すると下に実行結果が出力されます。

アーカイブ化したファイルはData Adress、つまりはアーカイブ化したいファイル(フォルダ)のあるフォルダに生成されます

アーカイブ化したいファイルの有るフォルダと、アーカイブ化したいファイルとをわざわざ分けているのは、例えば同じ階層にimageフォルダとsoundフォルダがあった場合にTarget File Nameを書き換えるだけで楽にアーカイブ化出来るようにと言う配慮なので、特に大きな意味はありません。

おしまい

というわけで締まりもクソもないですがこれで終了です。これで少しでも皆様の制作が楽になれば幸いです。

git初心者によるgit入門

前置き

対象

この記事は、「gitって何?」もしくは「名前だけ聞いたことはあるんだけど何となく手を出さないままでよく知らない」という人を主な対象としています。「コマンド普段から打つわけじゃないから抵抗がある or 面倒だ」という人にも向けています。また、僕自身の備忘録も兼ねています。あしからず。(おそらくこれらのユーザーの殆どはWindowsを使っているだろうという邪推から特に断りなくOSはWindowsを使っているものとして話を進めていきます)

目標

これを読んで、とりあえず最低限の機能については使える、知識としてではなく使えるくらいにはgitをわかってもらえたらなと思います。

注意

gitは一般には(というか原則は)CUI(文字だけの黒画面でコマンド打ち込んだり)で操作をするものなのですが、周りの人を見ていると、gitを使うことに抵抗を覚えている人がメインとしてGUIを使っている人(僕もその1人ですが)が多いので、SourceTreeというGUIフリーソフトを使ってとりあえずgitの便利さを知ってもらい、かつ難しい事をしている訳ではないという事を知ってもらうつもりでいます。コマンドをカタカタ打ってgitを使いたい!という方は沢山ドキュメントが転がっていますので適当なワードで検索することをおすすめします。とはいえ、SourceTreeについての説明部分以外についてはCUIで使う人にとっても有用な部分があるかもしれないので軽く見ていってください。

また、この記事では本当の本当に基本的な事を扱います。あくまでもgitに対するよくわからないという意識を拭うことのみを目的としています。

加えて、筆者も初心者なので、記述が正確であるかはわかりません。他のサイトと記述が矛盾している場合、自らでどちらが正しいか判断してください。そのような場合など、こちらにコメント等頂けると筆者も勉強になるばかりでなく、記述がより正確になるのでありがたいです。

本題

gitとは?

gitとは何か、と聞かれて一言で答えると「分散型バージョン管理システムの一つ」と僕ならば答えるのですが、人によっては何のことやら?という感じだと思います。順をおってみてみましょう。

バージョン管理システムの説明

バージョン管理システム」とは、そのまま「バージョン管理をするシステム」のことだろうというのは推測できるかと思いますが、ではその「バージョン管理」とは何でしょう?ゲームなどで(特にオンラインゲームで見る気がしますが)、「ver.1.2」みたいな表記を見ることが有りますよね。あれがバージョンだということは大体の人は知っていると思います。バージョン管理システムとはまさにあのバージョンを管理するシステムなのです。さて、バージョンはこれでわかったと思いますが、バージョン管理とはなんでしょうか。

それではここで、普段見るゲームのバージョンというものを、遊ぶ側からではなく作る側として考えながらバージョン管理とは何かを見ていきましょう。

例えば、

  • ゲームの基本システムが完成したものをver.1.0
  • 「モンスターA」を追加してモンスターの数を増やしたものをver.1.1
  • 「ボスA」を足したものをver.1.2
  • 「モンスターB」を追加してモンスターの数を増やしたものをver.1.3

としましょう。その上でこれをゲームを作る、開発者目線から見てみます。ver.1.2ではボスを追加しましたが、ボスの動きの実装が難しく、バグが出てしまったとします。バグが取り除ければそれに越したことは無いのですが、バグがなくプレイできる様なバージョンを用意して置かないと、ちょっとプレイして確認したいところがある、などといった時にバグのあるバージョンしかプレイが出来ずデバッグ的な観点からも不都合です。

ではどうすればいいかというと、それぞれのバージョンの状態でプロジェクトを何処かにコピーしてバックアップしておく方法が考えられます。そうすれば仮に最新バージョンでバグが出たとしても、ひとつ前のバージョンのバックアップがあるのでプレイ自体は問題なく行えます。こういったバージョン毎の管理がバージョン管理です。 しかし、多くの方がお気づきでしょうがこのような手動のバージョン管理は無駄が多いです。例えば

  • 新しいバージョンが完成する度に手動コピーをするので特にプロジェクトの規模が大きくなると時間がかかる
  • 同じく、プロジェクトの規模を増すほどに容量を食う
  • コピーした後、「ゲームver.1.0」「ゲームver1.1」とプロジェクトフォルダの名前を手動で書き換えないといけない
  • バージョンはわかってもそのバージョンでどのような変更がなされたか等はフォルダ名に書くわけには行かないので別途テキストを用意して管理しないといけない
  • モンスターAとモンスターBだけを実装したバージョン、つまりバグのあるボスAの実装を全て消したバージョンを作るのに手動でやるしか無い
  • 下のようにリネームの際の表記がブレてしまうこともあり、一貫性がなくなる

f:id:makiofinae:20170818164303p:plain

という感じです。欲を出すともう少しデメリットを出していけるのですが、ここではこれくらいにします。

ではどうすればいいのか、というところでバージョン管理システムの登場です。バージョン管理システムでは、上記のような手動のバージョン管理によるミスを防げる上に、より無駄のない管理が出来るようになっています。 例えばgitではフォルダをコピーしてバックアップしなくても、コミットという動作をすれば、バージョンを作ってくれる上に、その日時や変更内容、コメントなどの情報をまとめたものを作って管理してくれます

バージョン管理システムのイメージ

と、ここまで説明しましたが、イメージがつかめない人がいるかもしれません。その人はゲーム等のセーブをイメージしてくれればいいと思います。バージョン管理システムとは、開発(先程はゲーム開発の例を出しましたがそれ以外のソフトウェア開発についても)等をする際に、その開発内容のセーブやロード等を出来るように管理してくれるシステムなのです。 ゲームでの「あのアイテム取りそこねて先に進めないからあそこのセーブデータに戻ってアイテムを取り直そう」というのと同じように、開発でも「新しく実装したものがバグが有って取るのが難しいから前のバージョンに戻ってもう一度コードを書きなおしてみよう」というのを出来るようにするのがバージョン管理システムです。

gitの大まかなイメージ

「分散型バージョン管理システム」のうち、残りの「分散型」について説明をする前に、gitの簡単なイメージを掴んでおきましょう。 gitでは、ユーザーは「リポジトリ」というバージョン管理の情報等を入れる入れ物の様な物をつくり、そこに新しいバージョンについての情報を追加したり、そこにある過去のバージョンの情報を参照したりすることでバージョン管理をします。つまり、自分のPCの中には実際に開発中である様々なファイル(ソースコードやデータ等)とリポジトリがあり、開発中の様々なファイルの変更をセーブしたい時は、ローカルのリポジトリに対して、バージョンを保存してくれと言ったような命令を出して現状の情報を保存するわけですね。 また、gitではサーバ上などオンラインにリポジトリを作ることも出来、ここに自分のローカルのリポジトリの内容を反映させたり、逆にサーバ上のリポジトリの内容をローカルのリポジトリに反映させたりすることも出来ます。これを用いると、多人数開発等で非常に便利で、これこそがgitの便利な所ではあるのですが、ここについて詳しく書くのはこの記事の趣旨に沿わない上に、僕もそれほど詳しくないのでこの記事では書きません。もし機会があれば別の記事に起こしたいですね。気になる人はGitHub等について調べるといいかもしれません。

「分散型」の意味

ここではそれほど重要なことではないのですが、gitは「分散型バージョン管理システム」だと言ったので分散型の部分も説明しておこうと思います。どうでもいい人はここは読み飛ばしてもらって構いません。 まずそもそも、バージョン管理システムには、分散型でないもの、つまり集中型というものがあります。集中型バージョン管理システムとは、リポジトリはサーバーに1つであり、そこで直接バージョン管理をする、というシステムです。つまり、新しいバージョンが出来た時に、自分のPCにあるローカルなリポジトリにその情報を追加するのではなく、サーバ上のリポジトリに直接追加します。 これに対してgitでは、説明してきたとおりバージョン情報の追加は自分のPCにあるローカルなリポジトリに対して行います。サーバ上のリポジトリには、ローカルなリポジトリの内容を一部若しくは全部反映するという形でバージョン情報を追加したりするので、サーバ上のリポジトリに全てのバージョン情報があるわけではないという状態になります。このような管理の仕方をするものを分散型バージョン管理システムと言います。

gitの基本的な知識

はじめに

GUIで使えるようになろうといっても流石にgitの事がわかっていないのにツールの話ばかりしてもわかるようにはならないので、まずはgitの基本的な事について話そうと思います。ただし、恐らく使いながら慣れたほうが良いと思うので、それなりに細かく書くつもりではいますが、イメージさえ掴めたらここで全てを理解しようとせず次に進んで構いません。 ここではGUIを想定しているので、コマンドという言い方よりも機能という言い方を採用します。

repository(リポジトリ)

先程軽く説明して、ここまでの説明でも使ってきましたが、念の為確認しておきましょう。リポジトリとはバージョン管理情報を入れておく入れ物の事です。もう少し具体的に言うと、ソースやファイルの状態について、保持しておくファイル(群)の事を指します。gitではまず最初にこの入れ物を作ってから、そこにデータを追加していったりする形でバージョン管理を行っていきます。

commit(コミット)

一番よく使うことになるであろう機能がこのコミットです。何をする機能かというと、ゲームで言うとセーブをする機能です。つまりはリポジトリにコードの変更について保存します。

どうやって管理してるの?

gitはセーブをしたり出来るといって、commitについて先程書きましたが、gitはその時のソースコード等の情報を保存しているのではありません。commitによって保存されるのは、commit時の情報ではなく、前回までのcommitから導かれる前回のソースコードと、現在のソースコードとの差分です。 ゲームに例えてみましょう。RPGポーションを初めから3つ持っているとして、その状態でまずセーブがされているとします。そのあと、ポーションの数が4つになったとして、そこでセーブします。ゲーム等であれば大体「ポーションの数が4つである」というのを元のセーブデータに上書き保存する形でセーブすると思います。 しかし、gitでは「ポーションの数が1つ増えた」という情報をコミットすることになります。これによって

という情報から辿っていって現在のポーションの数を4つだ、と認識するわけですね。これをソースコードでもやるわけです。例えば

#include <stdio.h>
int main() {
     printf("Hello World\n");
     return 0;
}

というデータが既にcommit等を済ませた状態であるとして、

#include <stdio.h>
int main() {
     printf("Good Night World\n");
     return 0;
}

と書き換えた場合、commitをすると、リポジトリにはこのコードが保存されるのではなく、 「3行目の『 printf(“Hello World\n”);』が『 printf(“Good Night World\n”);』に書き換えられた」 という情報がリポジトリに保存されるわけです。(厳密に言うと「書き換えられた」と言うのは違う気がしますが、ここでは分かりやすさを優先します)

これを繰り返していってバージョンを管理する訳なので、gitは変更情報(差分)を連ねて保持してくれるシステムとも捉えることが出来ます。

branch(ブランチ)

ブランチというのは、ゲームで例えるとセーブスロットと考えると良いかもしれません。もしくは、世界線と考えると少しわかりやすいかも知れないですね。gitは変更情報を連ねて保持してくれるシステムとさっき言いましたが、このブランチというのはその連なりの分岐を作る機能なのです。ただ、ここで注意しておかなければならないのは、ブランチは分岐を作成・管理するのに使われるものの、ブランチそのものは直接分岐を作成するというよりも、commitの連なりやその分岐の中で現在どこにいるかというのを示す機能でもあるという事です。 ゲームの例で見てみましょう。世にいうギャルゲー、つまり恋愛シミュレーションゲームを考えます。あの手のゲームは所謂攻略対象としてヒロインが設定されているのですが、1周のプレイでは誰か1人を攻略することになると思います(自分はギャルゲーに詳しくはないので、本当にそうなのか!?と詰め寄られると困りますが、ここではそう考えます)。例えば、クリスマスに誰をデートに誘うか、というベタベタの選択肢があったとしてAさんとBさんがその候補にあがったとしましょう。この場合、素直にやるのであれば、まずAさんを誘って攻略を進めた後、また最初からやり直してBさんを攻略します。しかし、このクリスマスイベントまでは同じ手順を辿るのであれば、わざわざ二度も行うのは面倒ですよね。そこで考えられるのが、セーブです。セーブスロット1ではAさんを誘って、セーブスロット2ではBさんを誘う、そして最後には、セーブスロット1ではAさんを、セーブスロット2ではBさんを攻略します。 さて、プログラミングの話に戻りましょう。ソフトウェアの開発では、複数のメンバーが同時に機能の追加や、バグ修正を行ったりすることがあります。また、複数のリリースバージョンが存在し、そのそれぞれを保守しなければならないといったこともあります。こういった場合に役に立つのがブランチです。上記のセーブスロットの例の様に、例えばブランチ「bug_fix」ではバグの修正を、ブランチ「add_enemy」では敵の追加を、と言った風に、依存性の無い機能をそれぞれ平行に管理することが可能になります。この機能のメリットは、次に紹介するmerge(マージ)を含めての部分が多いのですが、そうでなくとも、ブランチについた名前から、そのブランチに属するcommit達が何をする為にされたものなのかを推測する事ができるという利点があります。とある機能についてのコードしか書かない、と決めていたら良いのですが、バグに気付いたら修正したくなるものですよね。かといって敵の実装の一部→バグ修正→敵の実装の一部という風にコミットされているとあとで見直す時に見にくくなってしまいます。しかしブランチを分けて置くことによって、いつでも当該部分についてcommitをすることができるようになるのです。

merge(マージ)

mergeというのは、分岐を再び統合する処理です。gitはその時のコードではなく変更についての情報を保持しているとさっき言いました。そして、その変更情報の連なったものは、分岐してbranch等を通して意味のあるかたまりとして捉えることができました(例えばバグ修正、など)。つまりは、元の情報に変更情報を1つずつ適用していけば、現在の情報が導ける訳です。となると、とある所で分岐したブランチについて、その元は同じであるがゆえに、ある変更情報の連なりに、別の変更情報の連なりを反映する、といったことも可能になります。このようにして、一度分岐した変更のかたまりを、再度統合する処理がmergeです。(以下、便宜上変更情報の連なりをブランチと表現します) しかし、このmergeはいつでもうまくいくとは限りません。あるブランチに別のブランチをマージしようとしたとき、それぞれの変更内容が矛盾してしまった場合、gitはそのどちらを採用すれば良いのかわからないのです。これをconflict(コンフリクト/衝突)と言います。コンフリクトが起きた場合は、その矛盾を解消してやらなければなりません。 具体的にどの様な時にコンフリクトするのでしょう。例えば、

#include <stdio.h>
int main() {
     printf("Hello World\n");
     return 0;
}

というコードに対して、ブランチ「night」では

#include <stdio.h>
int main() {
     printf("Good Night World\n");
     return 0;
}

と、3行目を書き換えてcommitしているのに対して、ブランチ「leave」では

#include <stdio.h>
int main() {
     printf("See You World\n");
     return 0;
}

と3行目を書き換えている事を考えましょう。 この時、3行目について、それぞれのブランチでは「 printf(“Good Night World\n”);」と「 printf(“See You World\n”);」という変更がなされています。この状態でどちらかのブランチにもう一方を統合することを考えてみたらどうでしょう。gitは3行目をどちらにすればいいかわかりませんね。ここでコンフリクトが生じます。 では、「wanna_know_name」というブランチがあって

#include <stdio.h>
int main() {
     printf("Hello World\n");
     printf("What's your name?\n");
     return 0;
}

こういった風になっているとします。元のHello Worldと比較すると、変更分は3行目と4行目の間に「 printf(“What’s your name?\n”);」が追加されたになります。これを「night」ブランチにマージしたらどうなるでしょうか? この場合変更分は、

  • 3行目と4行目の間に「 printf(“What’s your name?\n”);」を追加
  • 「 printf(“Good Night World\n”);」を追加

の2つなので、矛盾することなく、マージ後のコードは

#include <stdio.h>
int main() {
     printf("Good Night World\n");
     printf("What's your name?\n");
     return 0;
}

になります。

checkout(チェックアウト)

コミットは変更の積み重ね、ブランチは変更について分岐したもの、というのは話しましたが、となると今自分がどこに居るのでしょう?「そりゃ最新のコミットでしょ」と思うかもしれませんが、ブランチがいくつもあったら?また、今までゲームで例えた場合のセーブについて話してきましたが、ロードはどうするのでしょう?あのブランチの最新のコミットの状態をロードしたい、となったらどうすれば良いのでしょうか。 それはともかく、gitは差分で情報を保持するといいました。となると、常に現在の最新コミットがどこで、その最新コミットに比べた差分を見るわけです。この最新コミットがどこにあるかというのは何を基準に見て居るのでしょうか。 この二つの問いに対する答えはcheckout(チェックアウト)という機能を見ることで見えてきます。 チェックアウトとは、現在の作業ブランチを変更する機能です。またゲームの喩えをすると、選択しているセーブスロットを変更する機能になります。もっというと、別のセーブスロットをロードする機能、になります。 ブランチAからブランチBに移る場合「ブランチBにチェックアウトする」といいます。「ブランチAからチェックアウトする」といいたくなりますが、こうは言わない様です。

導入

実践

gitを使うメリットと、基本的な機能などについては何となく掴んでもらえたと思うので、そろそろその使う準備をしようかと思います。まず、この記事においては上記の通りGUIでgitを使えるようになる事を目的としているので、そのツールの紹介からしましょう

SourceTree

使うツールはこちら、SourceTreeです。もしかしたらもっと良いツールがあるのかもしれませんが、僕が教えてもらって非常に簡単に使うことが出来るようになったという事や、使い続けてきて充分使えるレベルのソフトウェアだという事を僕がわかっているのでこちらのツールを使っていこうと思います。

インストール

こちらのサイトからSourceTreeをダウンロード、インストールしてください。基本的に無料で使えると思うのでその辺は心配しなくて良いと思います。インストールする際等にアカウントを作ることを求められるかもしれません。もし将来オンラインでソースコードを管理することを考えているのであればGitHubのアカウントを取得してそれを登録しておいても良いかもしれません。(この記事ではSourceTree Version 1.9.13.7を前提として話を進めます)

不親切

色々ともしかすると選択肢等が出てくるかと思いますが、その辺は読めばだいたいわかると思うのでがんばってください…

リポジトリの作成

gitを使うにはリポジトリをまず作る必要がありますのでリポジトリを作ってみましょう。とはいっても難しいことはありません。左上の「新規/クローンを作成する」をクリックします。するとウィンドウ内に小窓が開くので、そのタブの中で「リポジトリを作成」を押し、「保存先のパス」にプロジェクトのパスを指定して「作成」を押します。これでリポジトリが作れました。

コミットしてみる

さて、次はコミットです。本当はgitにはaddという機能があって、gitで管理するファイルをこのコマンドで追加するのですが、Sourcetreeでは、これを自動で認識してくれるので、何も考えずコミットをすれば良いです。 コミットの仕方も簡単で、上の「コミット」ボタンを押して、コミット画面を開きます。変更点があるファイルが下側に表示されるので、コミットしたいものを選んで「Stage selected」を押すか、「Stage All」を押して、変更をステージします。変更をステージする、とは、変更を今回のコミットに含むと言うことを意味します。変更をステージできたら、下のメッセージボックスにコミットに関するコメントを書いて、右下のボタンを押すか、ctrl+Enterを押すだけでコミットは終了です。

ブランチを切る

ブランチを切る、とはブランチを作ることです。ブランチを作る、つまり新しい世界線・セーブスロットを作るのさえ、難しいことではありません。上にある「ブランチ」ボタンを押して、出てきた小窓に新しいブランチの名前を入力し、決定ボタンを押すだけです。

マージする

マージをしたい場合にも、またも上にあるマージボタンを押すのですが、この時に少し注意があります。それは、統合したい先のブランチにチェックアウトした状態でマージを押す必要があるということです。統合元ではないのです。 つまり、ブランチAにブランチBの変更を適用する(統合する=マージする)場合、ブランチAにチェックアウトした上でマージボタンを押す必要があります。 マージボタンを押すと、マージするコミットを選ぶよう言われます。マージしたいブランチの最新コミットを選択して右下の決定を押せば、自動でマージが行われます。 コンフリクトが発生した場合はダイアログが開くので、説明に従いながら衝突を解決してください。

現在のブランチを指定したコミットに移動させる

もう大体話したのですが、たまに便利なのを紹介しておくと、ブランチの現在位置を変更する機能があります。後から「うまくいかない原因を比較検証するためにあの状態からこの機能を実装してみたい」と言った時に過去のコミットに戻れる機能になります。これもいわばゲームでいうロードに近いですね。 やり方は、戻りたい先のコミットを指定して右クリックから「現在のブランチをこのコミットまでリセット」を選択するだけです。選択すると「Mixed」「Hard」など、どの設定で移動するかを聞かれますが、大体Mixedで問題ないでしょう。こいつらがなにかというと、ブランチの現在のコミットに合わせて、コードの方も変更するかという選択肢です。 オンラインリポジトリを使うようになるとこいつのせいで変に整合性が取れなくなることもあるので注意して使いましょう。

gitignore

地味に大事なのがこのgitignoreです。何かというと、変更を検知しないファイルをリスト形式で定義できるものになります。 例えば、コンパイルするたびに生成される.exeファイルや、VisualStudioを使っているのであれば、ソリューションについて更新があるたびに変更される.slnファイル等、定期的に変更が入り、かつ別にそれをコミットしたくはないというオブジェクトがあったりすると思います。これを検知せず、つまりはコミットの対象から外す様に設定できるのがgitignoreです。実際にはこれはgitignore.txt(ここでは名前が違うかもしれませんが気にしないでください)を編集することで行います。どこからそのgitignore.txtを開けるのかというと、まずSourceTreeのウィンドウメニューのツール->オプションを選択してオプションウィンドウを開きます。ここでGitのタブを選択し、「グローバル無視リスト」とある行の一番右の「ファイルの編集」をクリックすることで開けます。これは名前の通り全体に効果のある無視リストになります。ローカル環境でのみ無視するには.git/info/excludeを編集するという手がありますが、これは入門の範囲で扱う必要はないと思うので、必要であれば調べてみてください。
さて、gitignoreの中にどうやって更新を無視するファイルを定義するかですが例えばこのように行います。

#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.obj
*.exe
*.pdb
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk
*.log
*.dll
*.lib
*.sbr

簡単に書くと

  • #で始まる行はコメント
  • *.[拡張子]の場合、その拡張子のファイルすべてが無視される
  • 特定のフォルダ以下を無視したい場合は"folder_name/"

という感じです。

詳しくはこことかここあたりを参考にするか、「gitignore 書き方」とかでググれば出てくると思います。

総括

gitについて

さて、グダグダな説明になってしまいましたが、みなさんgitのイメージは掴めたでしょうか。もし、この有用性にまでイメージを膨らませることが出来たのであれば、あなたは今日からでもgitを使うべきでしょう。 gitにはここで紹介していない機能や、その本領を発揮するオンラインリポジトリについて等、まだまだ強い機能が沢山あります。それらについて皆さんの興味をひくことが出来たなら幸いです。

その他ページ

gitの学習をするにあたって、役に立ちそうなページを紹介しておきます

  • サルでもわかるGit入門
    有名どころ。なんだかんだ忘れた時にみるのはここな気がする。一通り書いてある気がするのでここを見てやるのは普通にアリ。

  • LearnGitBranching
    めっちゃ便利なサイト実戦形式でブラウザ上でコマンドを打ちながらgitについて学べる。CUIも気になる人には特におすすめ

  • こわくないGit
    スライドでGitの原理等から色んな機能に触れてくれる。非常に分かりやすい。スライドなのでとっかかりやすい。

  • チーム開発に必要なGitコマンドを神速で習得しよう! 
    そういえば殆どここにまとまってたななんて今更思い出した。個人使用に慣れてきて、オンラインリポジトリでの多人数開発したいってなったら見るといいかも。

最後に

gitも他の技術同様、実際に使ってみるのがその理解には早いと思います。しかし、バージョン管理という大枠の重要な位置を占める機能であるが故、少しのミスでデータをすべて飛ばす可能性も否定はできません。バージョン管理システムを導入しようとしているのに皮肉な話ではあるのですが、最初の慣れないうちは、プロジェクトのバックアップを手動でとっておくことをおすすめします。ただし、gitはそんなにこわいものではないので、恐れずに使って見てほしいなと思います。 それでは、これを読んだ方がgitの恩恵を受けられることを願っています。