読者です 読者をやめる 読者になる 読者になる

新卒初心者エンジニアの私が6時間+1時間でエンジニア用語タイピングデスクトップアプリをElectronで作って配布までした話

初めまして!16新卒入社、プログラミング歴半年の山﨑です!
入社当時はHTMLもまともに書けませんでしたが、先輩に迷惑をかけながらエンジニアとして働いています。
今回はブログを書くということで、Electronを使ってデスクトップアプリケーションを作りました!
jsをほとんど書いたことのない私でも全部で6時間!とおまけで1時間!計7時間ほどで完成まで行きました!(必死でやりました笑 )

f:id:AdwaysEngineerBlog:20161118111620p:plain

今回は、エンジニア用語を問題とするタイピングソフトを作りたいと思います。

0分 ~ 0.5時間 : 準備

今回はwindowsで開発をしました。 まずは環境を用意します。

1, Node.jsをインストール

これはインストーラーを使って行いました。

2, Electronのインストール

Electronをインストールします。

Npm install -g electron

これでElecrtronがインストールされました。
※今回はver. 1.4.6を使用しました。

3, ファイルの用意

そして、以下のようなファイル構成を作ります。

your-app/
├── package.json
├── main.js
└── index.html

package.jsonはnpm initで作成しました。

package.jsonは、 main:index.js の値をmain.jsに書き換えます。これでnode.jsであるmain.jsが、Electronの設定として動きます。

main.jsとindex.htmlは、以下のElectronの公式サイトをまるこぴしてきました!

electron.atom.io

これでOK!

your-appディレクトリで

electron .

を実行し、アプリが立ち上がれば成功です。

準備は完了!

意外とサクッと終わりました!良かった~

開発

今回は、タイピングソフトなので、以下の順番で開発を進めていきます。

  • キーボードで打った文字がどれかを表示
  • 打ったら正解・不正解かを判断
  • 単語が最後まで正解したか
  • 正解だったら次の単語を表示
  • 問題を外部のファイルから読み込んで10問出す。

0.5時間 ~ 1時間: キーボードで打たれた文字を判別

まずはtyping.jsというjsを作り、htmlから読み込み、そこに処理を書いていきます。

document.onkeydownにコールバックを作成することで出来るようです。 まずは出力してみます。

document.onkeydown = function (e){
    if(!e) e = window.event; 
    // 出力テスト
    console.log(e.key);
}

ちゃんと打った文字が出てきました!

これでキーボードから何が打たれたかはわかりました!!

ここまでは簡単でした。。。

1時間 ~ 1時間30分: 打ったら正解・不正解を判断 & 単語が最後まで正解したか

どの文字が打たれたかは判断できたのですが、さて、どのようにして正解かを判断しよう・・・
正解と、打たれた文字が同じだったら正解とすれば良いと考えました。

 var str = 'function'; //お題の単語   
 var length = str.length; //単語の長さ
 
 document.onkeydown = function (e) {
   if(!e) e = window.event;
   console.log(e.key);
   var correctCharNum = 0; //正解文字数
   var chr = str.charAt(correctCharNum); //現在何番目の文字かを正解した文字数から出す

   if (e.key == chr){
     console.log('ok');
     correctCharNum++;
     if (length == correctCharNum){
       console.log('end')     
     }   
   }
 };
ここまでで1.5時間!

単語はまだ1つですが、単語を打ち込む機能は完成しました。

ではでは次は単語が正解したら次の単語を表示という処理をかきます。

1.5時間 ~ 3時間: 正解だったら次の単語を表示

今回は問題を10個出題したいと思います!
10個だすと聞くと10回処理を回すのかなしか考えられなかったのですが、難しい・・・
ということで配列から10個単語を取り出すという方法に変更しました! そしてここからコンソールへの出力だけでなく、htmlに表示していきますので、htmlも変更します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <p id='word'></p>
    <br>
    <p id='keyword'></p>
  </body>
  <script src="./typing.js"></script>
</html>
  var strArray = ['aaa', 'abc', 'efg']; //テストデータ(とりあえず3問)
  var str = strArray[0];
  var length = str.length;
  var arrayNum = strArray.length;
  var correctCharNum   = 0;
  var correctAnswerNum = 0;
  var word = document.getElementById('word');
  var keyword = document.getElementById('keyword');
  var hKeyword = '';
  
  word.innerHTML = str;

  document.onkeydown = function (e) {
    var chr = str.charAt(correctCharNum);
    if (e.key == chr) {
        correctCharNum++;
        hKeyword += e.key;
        keyword.innerHTML = hKeyword
        if (length == correctCharNum) {
          correctAnswerNum++;
          
          // 最後の問題が正解した時の処理を追加
          if (arrayNum == correctAnswerNum ) {
            document.onkeydown = null;
            keyword.innerHTML = '';
            word.innerHTML =  'congraturation!!';
           }
           // 次の問題を出す時の処理を追加 
           else {
             str = strArray[correctAnswerNum];
             length = str.length;
             correctCharNum = 0;
             word.innerHTML = str;
             keyword.innerHTML = ''
             hKeyword = '';
          }
        }
      }
   }
 }

correctAnswerNumには正解数が入っているので、単語の配列から正解数番目の単語を取り出せば良い感じにできました。

ここまでで、3時間!!

あとは出題単語の配列ですね。エンジニア用語がたくさんつまったjsonファイルは先輩から頂きました。。。笑
いつか先輩のようにさっとスクレイピングできるようになりたいです。。。

3時間 ~ 6時間: 問題を外部のファイルから読み込んで10問出す。

ここは結構苦労しました。。。

頂いたjsonファイルからランダムに10個単語を取り出し、配列に入れます。
しかし、同じ単語が2回出てくるのはまずい・・・
ということで
jsonファイルを読み込み -> 問題データの配列をランダムする→その中から先頭10個だけ取得し、配列に入れ問題とする
という流れで処理を行いたいとを思います。

jsonは以下のような形式になっています。

{'datas':
    [
       ['2036年問題', 'year 2036 problem'],
       ...
    ]
}

配列をランダムにする処理は、この記事を参考にさせていただきました!

qiita.com

 var xhr = new XMLHttpRequest;
 xhr.open('GET', 'question.json', true);  // # jsonファイルの読み込み
 xhr.onload = function() {
 var datas = JSON.parse(xhr.responseText).datas;
 // 配列をランダムにする。
 for(var i = datas.length - 1; i > 0; i--){
   var r = Math.floor(Math.random() * (i + 1));
   var tmp = datas[i];
   datas[i] = datas[r];
   datas[r] = tmp;
 }

xhr.send();

配列の要素数の最大値をとってランダムな配列を作ります。 ここは最初は以下のような書き方をしていたのですが、

datas.sort(function() { Math.random() - .5; });

ランダムになってくれず、上のような処理にしました。。。
(※ sortに渡した関数の中でreturnしていないからでした。。。)

そしてランダムなオブジェクトから10個単語を取り出し配列にpushし、問題となる配列を作成します。

  var strArray = [];  
  for (var i = 0; i < 10; i++){
    strArray.push(datas[i][1].toLowerCase()); // 扱いやすいように、全部小文字に
  }

あとはHTMLに表示する処理とかを書いて完成です!!!

// innerHTMLと書くのが面倒なので、関数化
function insert(e, w) {
  e.innerHTML = w;
}

var xhr = new XMLHttpRequest;
xhr.open('GET', 'question.json', true);
xhr.onload = function() {
  var datas = JSON.parse(xhr.responseText).datas;
  // 配列をランダムにする。
  for(var i = datas.length - 1; i > 0; i--){
    var r = Math.floor(Math.random() * (i + 1));
    var tmp = datas[i];
    datas[i] = datas[r];
    datas[r] = tmp;
  }
  
  var strArray = [];  
  for (var i = 0; i < 10; i++){
    strArray.push(datas[i][1].toLowerCase());
  }

  var str = strArray[0];
  var length = str.length;
  var arrayNum = strArray.length;
  var correctCharNum   = 0;
  var correctAnswerNum = 0;
  var word = document.getElementById('word');
  var keyword = document.getElementById('keyword');
  var hKeyword = '';
  
  insert(word, str);
  document.onkeydown = function (e) {
    var chr = str.charAt(correctCharNum);
    if (e.key == chr) {
        correctCharNum++;
        hKeyword += e.key;
        insert(keyword, hKeyword);
        if (length == correctCharNum) {
            correctAnswerNum++;
            if (arrayNum == correctAnswerNum ) {
                document.onkeydown = null;
                insert(keyword, '');
                insert(word, 'congraturation!!');                
            } else {
                str = strArray[correctAnswerNum];
                length = str.length;
                correctCharNum = 0;
                insert(word, str);
                insert(keyword, '');
                hKeyword = '';
            };
        };
     }
  };
}
xhr.send(null);

これでしっかりと動きました!!
問題を答えるごとに、次の問題が出てきます。

f:id:AdwaysEngineerBlog:20161118111556g:plain

あー動くものができて良かったです。。。

おまけの1時間

これでタイピングアプリケーションは完成しました。
せっかくデスクトップアプリケーションを作ったので配布できるところまでもって行きたく、このコマンドを実行!

$ npm install electron-packager -g
$ electron-packager . typing --platform=all --arch=all --version=1.4.6 --overwrite

なぜ1時間もかかったというと、
* バージョンを古いのを指定してしまって、パッケージ化して起動するとonkeydownが使えない。
* なぜかMac用のapp作られない(結局、WindowsからはMac用のアプリは作れませんでした泣)

これを調べながらやったら結構かかっちゃいました。。。

反省とかプレッシャーとか

最初は正規表現のことを書こうと思ってたんですが、全然面白いこと書けなくてぼつりました!笑泣

今月は新卒が記事を書いていく月だったのですが前の二週間がレベル高い記事すぎて、びびりました!笑泣

そして私のミスの数々。。。

  • 文字列クォートで囲むの忘れる
  • ローカルで宣言していて変数が使えない
  • グローバル変数で宣言して毎回1つ目の単語しか表示されない
  • 回すしか思いつかない

等初心者まるだしのミスをやり続けてました笑

しかし、1からなにか作るのは楽しかったです!
今回はここまでしか作れませんでしたが、今後スコアだしたり、単語の意味を表示したりしたいと思います!

今回は以上です!