月別アーカイブ: 2012年11月
アプリづくりの準備
・アプリづくりの初歩の初歩
アプリ開発について、初歩者でも開発環境を整えれば、サンプルコードを基準に動作までこぎつけられることを複数回にわたって公開してきました。今回は、開発環境を整える以前のお話です。園芸や工作はあまり得意ではありません。事を進めるにあたってシステム開発者として長年携わってきたソフトウェア開発に的を絞ります。具体的には、アンドロイドアプリを開発する手順について話を進めます。
1)予備知識を吸収する
風呂の椅子を作る場合、市販品や日曜大工クラブの作品を見たりします。木材、釘、金づちや道具袋の予備知識を吸収します。アンドロイドアプリを開発するにはどのような準備をすればよいか、予算はいくらかかるかに興味が絞られます。ANDROIDアプリはスマホやタブレットPCで動作するので実機があれば良いのだが、スマートフォンの実行をPC上で代行してくれるエミュレータがあり、とりあえずWindowsパソコン(PC)があれば十分です。OSはWindows7か8が望ましいです。WindowsXPでも問題ありませんが、新しいプラグインツールは古いOSになじまなくなっています。スマホのように自らのシステム開発環境を整えることができない場合、他の機器でシステム開発することをクロス開発と言います。セルフ開発の用語はほとんど使われません。
コンピュータミシンの場合も同様でパソコン上でソフトウェアを開発し、右図のようなROMに焼き付けてミシンに実装します。スマホではWindowsパソコンで開発したプログラムコードをUSBケーブルやLANを使って転送して実装します。上でプラグインという用語がすでに使われているようにパソコンをシステム開発ツールの要として利用するので、一般のパソコン利用者よりもパソコンに精通することが大切です。 予備知識としてクロス開発のほか、コンパイル、ビルド、機械語、高級言語、JAVA、プログラム、ライブラリなどの用語について理解されることが望ましいといえます。
・なぜアンドロイドなのか
スマートフォンにはiOS(アップル)とAndroid(Google)の2大OSがあります。アップル社のiOSが先行していましたが最近はAndroidが追い上げています。どちらを採用するかは好みもありますが、伸びしろが見込める後者を選びました。MaccintosshとIBM PCの時に似ているのですが、規格や回路図を公開したIBM PCが世界標準機となったことは広く知られています。iPHONE用ツールは有償ですが、アンドロイド系は開発ツールや規格などを無料で公開しており新規参入障壁は高くありません。OS別にビジネスモデルを比較を参照。
ものを作るには道具を揃えなければなりません。霊長類で道具を使うのは人間だけと言われていましたが、チンパンジーがくぼみのある石にくるみを置いて石で割っている映像を放映していましたので、定説は覆されたのでしょう。アプリを開発するための道具は、テキストエディタ、コンパイラ、ライブラリ、デバッガ、エミュレータなどです。これらは統合開発ソフトなどとひとくくりにして呼ばれることがあります。かなり前はこれらのツールは数十万円する高価なものであり、開発を生業にする技術者しか目にすることができませんでした。現在は、すべてが無料で手に入れることができ、多くの人々がアプリケーション開発に参加できるようになりました。
アンドロイドアプリ開発に要する道具についてはこれまで何度も語っていますので、そちら(Androidアプリ開発環境構築、再び)を参照してください。
3)先人の作品を探求する
赤ん坊は親の真似をして知識を深めていきます。芸術も大御所の作品から多くの基礎を学びます。文化が進むほど学問は体系づけられてきました。昔は著作権を尊重する風土になく、秘密主義で先人のワザは簡単に伝承されませんでした。ごく限られた人に秘伝書が与えられノウハウが伝えられました。
今は、先達者の高度技術に触れることができます。先達の作品を鑑賞、解析、分析することによって自己の血肉にします。では鑑賞力、解析力を養うにはどうするのかということになりますが、まずは優れた技術に触れることから始まります。
4)先人の作品を模倣して作る
インターネットの普及で、有益なサンプル作品を目にすることができます。その多くは無料であり、営利目的に利用しなれば自由に使うことができます。どれが有用であるかの眼力が必要ですが徐々に目は肥えてきます。そして先人の作品そっくりに模倣して作ってみます。絵画においても大家の作品を眺めて模写することから始まります。
5)オリジナル作品を開発する
アプリ開発においても多くの先達者が、書籍やブログを通して優れた作品を発表しており、それらを手にして同様の結果が得られたのちに、まず簡単なオリジナル作品を開発してみましょう。Hello Worldを表示するものでも構いません。簡単なものを数多く手の内に入れ引き出しの中が満杯になるように頑張りましょう。 技量が向上し引き出しにものが溢れ出したら、高度な機能を有するアプリケーション開発に挑戦しましょう。
江戸時代のエコ生活
江戸時代の人口は、複数の研究者の発表からすると2000~3000万人と言われています。職業・身分比率はおおむね下左図のような分布と考えられます。
一部の階層が多くの階層を支配する典型的な封建制度といえます。身分制度は武家政治に行き詰まり始め町人文化が勃興した中期以降は事実上、崩壊したといえるでしょう。
江戸時代は上方を発祥地とする元禄文化を経て大衆文化が本格化した文化文政以降が興味深いです。
江戸時代のエコ生活を探求するには、物の生産-流通-消費-再利用など物の動きやそれに関わった人々の調査が必要になるでしょう。
庶民生活の基本は日の出に始まり日の入りと共に終わり、時計の刻みを季節によって(厳密には毎日)変えるという大胆にもフリキシブルな考え方を取り入れていました。
極端にエネルギーを浪費する現代生活に較べて、自然エネルギーをとことん利用するということでは欧米で採用されている夏時間制度よりももっと理にかなっています。
日の出36分前を明け六つ、日の入り36分後を暮れ六つとして、その間、昼間夜間6等分づつしていっとき(一刻、2時間)とする不定時法でした。
庶民は、寺院の鐘の音で時を知りました。寺の鐘をつく担当者はどのようにして日々、鐘をついたか、寺院ごとに時間差はなかったかなどを解明するのはこれからの研究課題です。
あみだくじ作成法
初歩からスタートするAndroidアプリ開発
目次
(1)あみだくじとは
(2)あみだくじの作り方
(3)画面設計と処理手順
(4)プログラムの設計とデザイン
(5)あみだくじ描画法
(6)音声出力
(7)実行結果
(8)SourceCode
(9)ファイル一覧
(10)プロジェクト全ファイル
(11)感想・概評
(12)関連情報
本文
以前にC言語であみだくじ作成法の一部を発表しましたが、ANDROID用に作り直しました。くじを作るところから始めます。以前にあみだくじ作成法を公開すると述べたことへの回答でもあります。
あみだくじを初めて体験される方のために、少し解説します。少人数(3~12人ほど)の仲間うちでくじをランダムに作って参加者全員、くじを引き当番人や当選者を決めるやりかたです。くじを作る場合、誰もがくじに手を加えることができ不正が起きないように配慮されます。コンピュータ処理では、乱数などを用いて不正への対策に当てます。
紙やホワイトボードであみだくじを作る方法を吟味します。ここでは便宜上、6人の参加者の場合を述べます。
1)参加者ぶん6本の縦線を引きます。
2)縦線と縦線の間(枠内)に、間隔4~9で4本ほどの横線を引きます。
3)それを全枠内で実行します。
4)隣どおしで横線の縦位置が同じになることを避けます。
5)くじを引く人は0~5の任意の番号を一意的に確保し引当てます。
6)引いたくじの番号を決めるには各々、上から下に線をたどります。
7)三叉路に出会ったら右、左、下に進み、終点まで繰り返します。
8)終点に宝物やミッション指示書があれば、当選者になります。
9)上のくじでは当選者は2番者になります。
上記の処理をアルゴリズムに反映させます。
1)上図に示すように6×36のマトリックスを作ります。10人参加なら10x36になります。
2)マトリックス(node[x][y])の要素をすべてゼロクリアします。x:0~5,y:0~35。
3)node[x][y]のうち、左端のx=0を除きx:1~5で、横線用のポイントを決定します。
4)乱数を順に4箇発生させ、その値を縦位置に設定します。
5)間隔は4~9、左隣と同じ値を避けます。
6)縦位置の値が36以上になったら4回発生させる前に終了します。
7)乱数は時間データを種にして再現性と人為的な関与を排除します。
8)node[x][y]=2,node[x-1][y]=1に設定します。1は横線の始まり、2は終点です。
9)上記のあみだくじでは右図のnodeテーブル設定値になります。
画面設計は参加者の入力とくじの表示並びに当選者の決定処理です。参加者名を入力して締切り後、参加者の人数に問題がなければあみだくじを表示する次のアクティビティに歩を進めます。
■プログラムの設計
前回に使ったインテントを今回も使用します。参加者の入力画面からくじ表示と当選者の決定画面を起動するために使います。
■画面設計
関数getResources()とgetConfiguration()を使って、スマートフォンの向きを検出して自動的に縦型、横型用画面が制御されます。
1)縦型画面
■主なプログラムのモジュール構成
・delay.java ディレー関数 ・FirstActivity.java 参加者入力画面 ・SecondActivity.jav あみだくじ表示画面
あみだくじを描画するには、あみだくじの作り方をプログラムに表現すべく、具体的に以下に示します。
1)参加者ぶん、ここではxが0から順に5まで繰り返します。
2)縦方向に0から35まで36行あり、順に描画対象かを確認します。
3)2次元配列のnodeの値は0が多く、他は1か2です。
4)1つのxに対し上から順に検索し、0以外が現れたら横線を引きます。
5)値が1ならば右に、2ならば左に向かって引きます。
6)横線はCanvasオブジェクトのdrawLinesを使用します。
7)次に、検索した値により探索地点を1加算(減算)して右(左)に移動します。
8)yは加算され終端(35)に達するまで繰り返します。
9)一人のくじを引き終り、宝物や地雷があれば、当選者に対する処理をします。
10)xを加算して次の人のくじを描画します。
11)最後の参加者の処理が終えたら終了です。
処理の切れ目やエラー発生、くじが三叉路を通過するときに音声が出力されます。C言語のBeep関数がなく、あらかじめ音声ファイルを読み込んで音データを用意して置かなければなりません。SoundPoolオブジェクトを利用し、サウンドファイルを読み込み音声を再生します。音声における書式付きprint関数のような機能はまだマスターできてないので、当選者をアナウンスするために10人ぶんの10個のファイルをあらかじめ用意しています。
ソースコードを以下に示します。
1.delay
package example.android.kuji; public class delay { public static void time(int millis) { try { Thread.sleep(millis); } catch(InterruptedException e){System.out.println("delay failed");} } }
2.FirstActivity.java
package example.android.kuji; import android.app.Activity; import android.content.Intent; import android.media.AudioManager; import android.media.SoundPool; import android.os.Bundle; import android.text.Editable; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; class gv{ /** global variable **/ public static SoundPool sound; // SoundPool public static int Si0; // ちょうはんコマ… public static int Si1; // 乱数を発生させ… public static int Si2; // pyon public static int Si3; // bororo public static int Idx[]={0,0,0,0,0,0,0,0,0,0}; // no0~no9 } public class FirstActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState){// onCreateメソッド(画面初期表示イベントハンドラ) super.onCreate(savedInstanceState); // スーパークラスのonCreateメソッド呼び出し setContentView(R.layout.firstlayout); // レイアウト設定ファイルの指定 Button button = (Button) findViewById(R.id.button1);// ボタンオブジェクト取得 button.setOnClickListener(new LotteryListener());// ボタンオブジェクトにクリックリスナー設定 } @Override public void onResume() { super.onResume(); gv.sound = new SoundPool(2, AudioManager.STREAM_MUSIC, 0); gv.Si0 = gv.sound.load(this, R.raw.chohan, 1); gv.Si1 = gv.sound.load(this, R.raw.ransuu, 1); gv.Si2 = gv.sound.load(this, R.raw.pyon, 1); gv.Si3 = gv.sound.load(this, R.raw.bororo, 1); gv.Idx[0] = gv.sound.load(this, R.raw.no0, 1); gv.Idx[1] = gv.sound.load(this, R.raw.no1, 1); gv.Idx[2] = gv.sound.load(this, R.raw.no2, 1); gv.Idx[3] = gv.sound.load(this, R.raw.no3, 1); gv.Idx[4] = gv.sound.load(this, R.raw.no4, 1); gv.Idx[5] = gv.sound.load(this, R.raw.no5, 1); gv.Idx[6] = gv.sound.load(this, R.raw.no6, 1); gv.Idx[7] = gv.sound.load(this, R.raw.no7, 1); gv.Idx[8] = gv.sound.load(this, R.raw.no8, 1); gv.Idx[9] = gv.sound.load(this, R.raw.no9, 1); } // クリックリスナー定義 class LotteryListener implements OnClickListener { // onClickメソッド(ボタンクリック時イベントハンドラ) public void onClick(View vw) { Log.v("FirstActivity ","v.fortune=" + v.fortune+" v.LineCount=" + v.LineCount); if(v.fortune == 99) { // SecondActivityが実行されている。 v.fortune = 0; // reset fortune gv.sound.play(gv.Si3, 1.0f, 1.0f, 0, 0, 1.0f); // S bororo delay.time(1000); System.exit(0); } // テキストボックスオブジェクト取得 EditText input = (EditText) findViewById(R.id.nametext); Editable str = input.getText(); String string = str.toString(); // 入力情報をトースト機能で画面表示 // インテントの生成(呼び出すクラスの指定) Intent intent = new Intent(FirstActivity.this, SecondActivity.class); // 選択された値をインテントに設定 intent.putExtra("PARTY_MEMBER", string); //Log.v("tag_name", "go new screen."); // 次のアクティビティの起動 startActivity(intent); } } public boolean onKeyDown(int keyCode, KeyEvent event){ // Back-key Log.v("FirstActivity-onKeyDown", "fortune="+v.fortune+" KeyCode="+keyCode); if(keyCode == KeyEvent.KEYCODE_BACK) v.fortune = 0; // reset fortune return super.onKeyDown(keyCode, event); } }
3.SecondActivity.java
package example.android.kuji; // Amida.java ---> Kuji.java import java.util.Random; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.os.Bundle; import android.util.Log; import android.view.View; class v{ /** global variable **/ public static int index=2; // side, vertical public static int x=5; // position-x public static int y=450; // position-y public static int LineCount=0; // party_member public static String string; // input data public static int fortune=0; // fortune-number public static int i=0; // menber/-id public static int end=-1; // end-text public static int node[][]= { // random-value, 10*46 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 0 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 1 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 2 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 3 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 4 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 5 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 6 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 7 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},// 8 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // 9 }; public static int co[]={Color.YELLOW , Color.BLUE , Color.CYAN , Color.DKGRAY , Color.GRAY , Color.GREEN , Color.LTGRAY , Color.MAGENTA , Color.RED , Color.BLACK}; } // MainClass public class SecondActivity extends Activity { /** Called when the activity is first created. **/ @Override public void onCreate(Bundle savedInstanceState) { // ?????????? super.onCreate(savedInstanceState); // make instance of ViewClass. MyCircleView view = new MyCircleView(getApplication()); setContentView(view); // set View. Log.v("SecondActivity", "LineCount=" + v.LineCount); // calc party-member. Intent data = getIntent(); // get additinal info of intent; Bundle extras = data.getExtras(); // get party-member from input-data. v.string = extras.getString("PARTY_MEMBER"); Resources resources = getResources(); // screen direction Configuration config = resources.getConfiguration(); v.index=2; v.x = 5; v.y = 450; v.LineCount = 0; v.i = 0; switch(config.orientation) { case Configuration.ORIENTATION_PORTRAIT: v.index = 0; break; case Configuration.ORIENTATION_LANDSCAPE: v.index = 1; v.x = 500; v.y = 20; break; } int end = -1; // line of input. for(int i=0; i int top = end + 1; int wrk = v.string.indexOf('\n', top); if(wrk == -1) break; end = wrk; ++v.LineCount; } v.fortune = 99; // for abnormal-finish Log.v("SecondActivity", "LineCount:" + v.LineCount+" Fortune="+v.fortune); if((v.LineCount < 3) || (v.LineCount > 10)){ gv.sound.play(gv.Si3, 1.0f, 1.0f, 0, 0, 1.0f); // S bororo delay.time(1000); System.exit(1);/*return;finish();*/ } long seed = System.currentTimeMillis(); // current-time, milisecond Random rnd = new Random(seed); v.fortune = rnd.nextInt(v.LineCount); // random:0~(v.LineCount-1) for(int i=0; i for(int j=0; j } int k=0; // yoko-line:4 /* gen */for(int i=1; i int d=0; // d:0~45, 46 for(int j=0; j= 46) {k=1;break;} // finish,yoko-line:3 if(v.node[i-1][d]==2){ // if equal, alert. d += 4; if(d >= 46) {k=1;break;} // finish,yoko-line:3 if(v.node[i-1][d]==2){ ++d; // if equal, alert. if(d >= 46) {k=1;break;} // finish,yoko-line:3 } } //Log.v("SecondActivity-3", "i="+i+"j="+j+"d="+d); v.node[i-1][d]=1; // start v.node[i][d]=2; // end } /* gen */} // ------------------- if(k==0) k = gv.Si1; // ransuu else k = gv.Si0; // chohan gv.sound.play(k, 1.0f, 1.0f, 0, 0, 1.0f); // L biyoon delay.time(2800); } // ?????????? } // display class class MyCircleView extends View { // View public MyCircleView(Context context) { // initialize View super(context); setFocusable(true); } /**/protected void onDraw(Canvas canvas) { // actualy,method of display. Paint paint = new Paint(); // make paint-object super.onDraw(canvas); canvas.drawColor(Color.WHITE); // set back-color. for(int i=0; i int x=i*50+8; // x-position float[] pts1 = {x+7, 25, x+7, 346}; // 2.vertical line canvas.drawLines(pts1, paint); // basic line if(i != (v.LineCount-1)){ // ########## for(int j=0; j if(v.node[i][j]==1){ // amida-yoko float[] pts0 = {x+7, j*7+25, x+57, j*7+25}; // yoko canvas.drawLines(pts0, paint); // yoko line } } } // ########## } // display basic form. paint.setStrokeWidth(4.0f); // line's thickness if(v.i == v.LineCount){ // draw amida-line. for(v.i=0; v.i display(gv.Si2, paint, canvas); // pyon, all } // final-proc int end = -1; // display member-name paint.setColor(Color.BLACK); // black line paint.setTextSize(24); // member name paint.setTypeface(Typeface.DEFAULT_BOLD); // thin for(int i=0; i paint.setColor(v.co[i]); // COLOR int x=i*50+8; // display character int top = end + 1; end = v.string.indexOf('\n', top); String s = v.string.substring(top, end); // MEMBER-NAME canvas.drawText(i + ":" + s, v.x+20, v.y+i*25+25, paint); String str = String.valueOf(i); // 0 1 2 3 4 5 6 if(i == v.fortune){ Log.v("SecondActivity", "i=" + i+" Fortune="+v.fortune); StringBuffer sb = new StringBuffer(str); str = sb.reverse().toString(); } canvas.drawText(str, x, 20, paint); } paint.setColor(v.co[5]); // GREEN canvas.drawText("笘", v.x, v.y+v.end*25+25, paint); // atari paint.setTextSize(20); // make display-object. paint.setColor(Color.MAGENTA); // display party_member canvas.drawText("蜿ょ刈閠・・" + v.LineCount + "莠コ縺ァ縺吶",v.x, v.y, paint); gv.sound.play(gv.Idx[v.end], 1.0f, 1.0f, 0, 0, 1.0f); // s no0 delay.time(250); paint.setTextSize(24); // lucky mark paint.setColor(v.co[5]); // GREEN canvas.drawText("笘", v.fortune*50+2, 395, paint); // atari paint.setColor(Color.BLUE); // announce lucky-man. canvas.drawText("蠖馴∈閠・・"+v.end+"逡ェ縺ァ縺吶", 5, 417, paint); v.fortune = 99; // if you down back-key, v.fortune=0. v.i = 0; return; /*System.exit(0);*/ } else{ // 0~(v.LineCount-1) display(gv.Si2, paint, canvas); // pyon ++v.i; } invalidate(); // repeat /**/} private void display(int si2, Paint paint, Canvas canvas) { // draw a kuji. gv.sound.play(si2, 1.0f, 1.0f, 0, 0, 1.0f); // s pyon delay.time(500); int y=0; int x=v.i; paint.setColor(v.co[v.i]); // COLOR for(int j=0; j yoko if(v.node[x][j]>0){ float[] pts1 = {x*50+15, y*7+25, x*50+15, j*7+25}; // tate canvas.drawLines(pts1, paint); // tate line y=j; int d=x; if(v.node[x][j]==1) ++x; else --x; float[] pts2 = {d*50+15, j*7+25, x*50+15, j*7+25}; // yoko canvas.drawLines(pts2, paint); // yoko line } } float[] pts1 = {x*50+15, y*7+25, x*50+15, 46*7+24}; // tate canvas.drawLines(pts1, paint); // tate line paint.setTextSize(20); // make display-object. String str = String.valueOf(v.i); // 6 5 4 3 2 1 0 canvas.drawText(str, x*50+8, 372, paint); if(x==v.fortune) v.end = v.i; // save forune-number } } // View
ファイル一覧を階層構造形式に示します。音声ファイルがres\rawフォルダに収納されていることに注目ください。
.\AMIDAKUJI │ .classpath │ .project │ amidakuji.apk │ AndroidManifest.xml │ default.properties │ lint.xml │ proguard.cfg │ project.properties │ ├─assets ├─bin │ │ AndroidManifest.xml │ │ classes.dex │ │ example.android.kuji.FirstActivity.apk │ │ resources.ap_ │ │ │ ├─classes │ │ └─example │ │ └─android │ │ └─kuji │ │ BuildConfig.class │ │ delay.class │ │ FirstActivity$LotteryListener.class │ │ FirstActivity.class │ │ gv.class │ │ MyCircleView.class │ │ R$array.class │ │ R$attr.class │ │ R$drawable.class │ │ R$id.class │ │ R$layout.class │ │ R$raw.class │ │ R$string.class │ │ R.class │ │ SecondActivity.class │ │ v.class │ │ │ └─res │ ├─drawable-hdpi │ │ icon.png │ │ │ ├─drawable-ldpi │ │ icon.png │ │ │ ├─drawable-mdpi │ │ icon.png │ │ │ └─drawable-xhdpi │ icon.png │ ├─gen │ └─example │ └─android │ └─kuji │ BuildConfig.java │ R.java │ ├─res │ ├─drawable │ ├─drawable-hdpi │ │ icon.png │ │ │ ├─drawable-ldpi │ │ icon.png │ │ │ ├─drawable-mdpi │ │ icon.png │ │ │ ├─drawable-xhdpi │ │ icon.png │ │ │ ├─layout │ │ firstlayout.xml │ │ main.xml │ │ secondlayout.xml │ │ │ ├─raw │ │ bororo.wav │ │ buin.wav │ │ chohan.wav │ │ no0.wav │ │ no1.wav │ │ no2.wav │ │ no3.wav │ │ no4.wav │ │ no5.wav │ │ no6.wav │ │ no7.wav │ │ no8.wav │ │ no9.wav │ │ pyon.wav │ │ ransuu.wav │ │ │ └─values │ strings.xml │ └─src └─example └─android └─kuji delay.java FirstActivity.java SecondActivity.java
プロジェクト内の全ファイルをZIP形式で一挙、公開です。 AmidaKuji.ZIP
1.あみだくじは遊び心で始まります。ひとりで全員のかばん6個を運ぶなど、仲間うちで負荷の大きい使役などは避けましょう。
2.のやっかいになるようなトトカルチョっぽいものもやめましょう。
3.あみだくじは、ひとりの当たり人を決める場合が多いのですが、冒頭の芋煮会準備くじにあるように多対多の対応づけに応用でき、ホテルの部屋割り、宴会の席順設定にも使えます。
4.あみだくじを記録するには、結果をファイル化してください。
5.あみだくじは、結果よりも途中のワクワク感を楽しむものです。このページを土台にしてビジュアル的に改良して楽しんでください。
6.くふうすれば、プロ野球ドラフト会議で競合者があった場合に、交渉権を決定するくじ引きに採用されるかも知れません。
7.あみだくじの参加者名を入力し終えて、「締め切り!」を押すと「乱数を発生させあみだくじ作成中です」がアナウンスされますが、稀に妙なメッセージが出力されことがありますが、これは開発者の遊び心です。ソースコードを詳しく眺めると出力条件がわかります。
8.javaはCと違ってstatic変数が初期化されず前回に実行されたメモリに残っている状態になり、Cから移植した場合に悩みの種となるようです。
9.今回の公開は「あみだくじ作成法」です。完成品ではありません。ご利用には利用規定をお読みください。
10.画面上の制限からテーブルサイズなど、解説した内容と実際のソースコードは異なっています。
11.くじ参加者名を全角文字で入力する代わりにアルファベットで、N,SA,A,SU,Yなどと入力する方法があります。
12.くじ運営者は最後に残ったものを引き当てた方が公平でしょう。
13.この作成手法を用いたあみだくじアプリを開発してGoogle Playに公開します。
2014-05-14追記
Google Playに以下の3点を出品しています。
①あみだくじ
②抽選機
③福引き管理ソフト
②電子式ふくびき管理ソフト
③スマホ用抽選器取り扱い説明書
④抽選箱から宝もの
⑤ゲーム考
⑥電子式福引き管理ソフト
⑦ブロックサイン式パスワード
⑧電子式福引き管理ソフト封切
⑨電子式福引き管理ソフト改2
⑩阿弥陀
⑪あみだくじ
⑫あみだくじ雑感
⑬あみだくじ参加人数
⑭あみだくじを引く取り扱い説明書
⑮あみだくじを引く
⑯多人数あみだくじ
井戸を掘る
という中国の言葉があり、井戸を掘ることを様々なことにたとえて語られます。
ここでは井戸や水の浄化に関わって探求してみたい。江戸時代は鎖国をしてほとんど自給自足で生活をしてきました。その時代に戻ることはできませんが、リサイクル精神は見習うべきことが多くあります。電気や石油機関もなく天から降る雨と地下水で生活しました。
我が国の井戸掘り技術は高水準でJICAでは発展途上国を応援しています。発展途上国では電動力で水を汲み上げるのではなく、地下水を自噴する方式です。動力なしで水を入手するとは信じられないでしょうが、我が国も60~70年前は手押しポンプは普通だったでしょう。
地下水を浄化しないで飲む仕組みは近隣の環境に影響を受けるので個人では困難ですが、電気料金が高騰するなか、世界的な水不足も心配です。連綿と続く先人の知恵をこれから整理していきたい。
飲水をろ過するには2方式あり、最近は薬品を用いる急速ろ過方式が多いが、明治期に導入され安全で安価な自然の仕組みに基づいた緩速ろ過が見直されています。
人口が増加し、潤沢な予算が使えるときは、10倍以上もの処理能力のある急速ろ過方式が圧倒的に有利でした。一挙に物事を進めるのは無理ですが、先達の教えである緩速ろ過方式も取り入れたいものです。
radiko周辺
スマホで日付から曜日の算出
目次
(1)概要 (2)演算式 (3)サポート範囲 (4)画面設計と処理手順 (5)プログラミング構想 (6)入力値チェック処理 (7)eclipseパッケージ・エクスプローラーの起動 (8)ブロック構造 (9)SourceCode (10)実行結果 (11)ファイル一覧 (12)全プロジェクトファイル (13)感想・概評本文
(1)概要 ツェラーの公式(Zeller’s congruence)を用いて西暦の年、月、日からその日が何曜日であるかを算出するANDROIDアプリケーションを開発します。ツェラーの公式は専門のフォーラムが存在するくらいに研究が盛んです。C言語の庵で述べましたが、技術月刊誌bitに記載された式を使います。 上左図は干支一覧です。エトは十干と十二支を組み合わせた60(10と12の最小公倍数)を周期としています。女の子を思う親心のため、出生率が下がる丙午(ひのえうま)は60年に一度、巡ってきます。 演算はガウス関数とモジュロ関数を必要としますが整数扱いと剰余演算子(%)を用いて表現すれば次の式になります。y:年,m:月,d:日とすれば、lに火曜日を0とする曜日が求まります。 (2)演算式 l = y + (m – 8) / 6; l = ((5 + (m + 9) % 12 * 26) / 10 + (l * 5) / 4 – l / 100 + l / 400 + d) % 7; // 0:火,1:水,2:木,3:金,4:土,5:日,6:月 (3)サポート範囲 グレゴリオ暦における日付から曜日を求めます。よってサポートする日付は1582年10月15日以降です。 (4)画面設計と処理手順 (5)プログラミング構想 このサイトではJavaの文法などにいっさい触れることなく、サンプルコードが実際に希望どおり実行できたことにより少しずつ先に進む方式です。しかしながら最低限のJavaの文法とガウス、モジュロなどの数学用語を理解する必要があります。今回はインテントを使用します。インテントは「意図、目的」などの意味があり、次のサービスを起動するために使用します。インテントは入力画面から表示画面を起動するために使います。インテントを手の内に入れましょう。 (6)入力値チェック処理 入力された日付が有効かどうかのチェック処理を以下に示します。入力日付は1582年10月15日以降をサポートし、うるう年かどうかを確認し月や日の有効性を調べます。 (7)eclipseパッケージ・エクスプローラーの起動 eclipseを起動するとパッケージ・エクスプローラーが現れるので、プロジェクトに関する様々なデータを作成しますが、何かの拍子にパッケージ・エクスプローラー画面が消えることがあります。赤矢印で示したボタンをクリックすれば、右のパッケージ・エクスプローラー画面が現れます。そのボタンさえ消えてしまったら、[ウィンドウ]-[ビューの表示]-[パッケージ・エクスプローラー]と指定して再び現れます。 (8)ブロック構造 文や画像などを表現するHTMLやC,JAVA言語ではブロック(塊まり)単位で表現されます。表現の基本はブロックやタグです。ブロックとタグに注目するとプログラミングや意志の伝達に役立ちます。ブロックは入れ子(ネスト)になることが多いですが、絡み合うことはありません。ブロックには始まりと終わりがあり、特定の記号から始まります。 ①ブロック構造 ②ブロック表現法 ・{ } ・.begin .end ・<pre> </pre> ・<strong> </strong> ・<head> </head> ・<title> </title> ・<body> </body> (9)SourceCode ・delaypackage example.android.dayoftheweek; public class delay { public static void time(int millis) { try { Thread.sleep(millis); } catch(InterruptedException e){System.out.println("delay failed");} } }・FirstActivity.java
package example.android.dayoftheweek; // FirstActivity.java : 日付を入力し、正当性をチェックする import android.app.Activity; import android.content.Intent; import android.media.AudioManager; import android.media.SoundPool; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; class gv{ /** global variable **/ public static SoundPool sound; // SoundPool public static int Si2; // buin public static int Si3; // bororo public static int day=0; // yy-mm-dd public static int y; // y public static int m; // m public static int d; // d public static int n; // n public static int max[]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; public static String[] week={"日","月","火","水","木","金","土"}; } public class FirstActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState){// onCreateメソッド(画面初期表示イベントハンドラ) super.onCreate(savedInstanceState); // スーパークラスのonCreateメソッド呼び出し setContentView(R.layout.firstlayout); // レイアウト設定ファイルの指定 Button button = (Button) findViewById(R.id.button1);// ボタンオブジェクト取得 button.setOnClickListener(new LotteryListener());// ボタンオブジェクトにクリックリスナー設定 } @Override public void onResume() { super.onResume(); gv.sound = new SoundPool(2, AudioManager.STREAM_MUSIC, 0); gv.Si2 = gv.sound.load(this, R.raw.buin, 1); gv.Si3 = gv.sound.load(this, R.raw.bororo, 1); } // クリックリスナー定義 class LotteryListener implements OnClickListener { // onClickメソッド(ボタンクリック時イベントハンドラ) public void onClick(View vw) { System.out.println("FirstActivity"); // テキストボックスオブジェクト取得 EditText input = (EditText) findViewById(R.id.nametext); String string = input.getText().toString(); // 入力情報をトースト機能で画面表示 //System.out.println("Number of itartion : " + string); try{ gv.day = Integer.parseInt(string); }catch(NumberFormatException e){ gv.sound.play(gv.Si3, 1.0f, 1.0f, 0, 0, 1.0f); // bororo System.out.println("数値でない値が入力されています"); delay.time(1000); // error System.exit(0); // プログラムを終了する } System.out.println("day = " + gv.day); gv.y = gv.day / 10000; // 日付の正当性をチェックする gv.m = gv.day % 10000; // 年、月、日を抽出する gv.d = gv.m % 100; gv.m /= 100; int normal = 0; // errorありに設定 gv.n = gv.y; if(gv.day >= 15821015){ if(gv.y % 100 == 0) gv.n = gv.y / 100; if(gv.n % 4 == 0) gv.max[1] = 29; else gv.max[1] = 28; if(gv.y >= 1582){ gv.n = gv.m - 1; if((gv.n>=0) && (gv.n=1) && (gv.d・SecondActivity.java [java] package example.android.dayoftheweek; // SecondActivity.java : 日付から曜日を求め、表示する import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.util.Log; import android.view.View; // MainClass public class SecondActivity extends Activity { /** Called when the activity is first created. **/ @Override public void onCreate(Bundle savedInstanceState) { // ?????????? super.onCreate(savedInstanceState); // make instance of ViewClass. MyCircleView view = new MyCircleView(getApplication()); setContentView(view); // set View. Log.v("SecondActivity", "day=" + gv.day); gv.n = gv.y + (gv.m - 8) / 6; gv.n = ((5 + (gv.m + 9) % 12 * 26) / 10 + (gv.n * 5) / 4 - gv.n / 100 + gv.n / 400 + gv.d) % 7; gv.n = (gv.n + 2) % 7; // 0,1,2,3,4,5,6 -> 2,3,4,5,6,0,1 Log.v("SecondActivity", "n=" + gv.n); } // ?????????? } // display class class MyCircleView extends View { // View public MyCircleView(Context context) { // initialize View super(context); setFocusable(true); } /**/protected void onDraw(Canvas canvas) { // actualy,method of display. Paint paint = new Paint(); // make paint-object super.onDraw(canvas); canvas.drawColor(Color.WHITE); // set back-color. paint.setStrokeWidth(4.0f); // line's thickness paint.setTextSize(20); // lucky mark paint.setColor(Color.BLUE); // announce lucky-man. canvas.drawText(gv.y+"蟷エ"+gv.m+"譛"+gv.d+"譌・縺ッ"+gv.week[gv.n]+"譖懈律縺ァ縺吶", 10, 160, paint); gv.sound.play(gv.Si2, 1.0f, 1.0f, 0, 0, 1.0f); // buin delay.time(1000); return; /*System.exit(0);*/ /**/} } // End Of SecondActivity.java(10)実行結果 (11)ファイル一覧 プロジェクト内のファイルを階層構造形式に表示します。 (12)全プロジェクトファイル 上記ファイル一覧DayOfTheWeekプロジェクト内の全ファイル(DayOfTheWeek.zip)を添付し一挙、全公開します。 DayOfTheWeek.ZIP (13)感想・概評 ①日付はハイフン、カンマ、スラッシュなどを含めず最後はreturnでなく完了を入力します。数字かどうかをチェックする例外処理が施されているので、「アプリケーションは予期しないエラーが起きました」を表示して止まることはありません。エラーを知らせる音が出てアプリは終了します。 ②入力値20120229はエラーになりませんが、20130229はエラーになります。 ③C言語ではBeepやSleep関数が用意されていますが、javaでは簡単な関数は用意されていないようです。適切な処理を見つけるまで、かなり時間を要しましたが、同じ悩みをお持ちの方に参考になるでしょう。 ④エンコード指定はencoding=”utf-8″に設定済みですが、ソースコードに妙な漢字が表示されていてもECLIPSE開発画面や実行表示結果が正しければそのままにしている箇所があります。 ⑤動作の検証は全てにわたってはおりません。誤動作等があればご教示ください。 ⑥スマートフォン向けに「アプリ甲子園」という全国大会を開催して小中高校生のソフト開発を応援している企業があります。次世代を背負う若者が大勢、育っていくことを願っています。このサイトが参考になれば幸いです。
ものづくり礼賛
今朝の新聞に情報化社会の次は「ものづくり」の時代がやってくる…。IT界の論客クリス・アンダーソンがインタービューに答えています。物づくりは大企業がリーダーシップを発揮し大学、職業訓練機関、行政機関が啓蒙活動を行うというのが定番のようでした。
これからはそれで良いのかなという疑問を感じていたところに「ものづくり民主化の波」の見出しをみて我が意を得たりと言えます。
上の画像はスマートフォン用のアプリケーションをクロス開発するときの中心となるツールのECLIPSEです。スマートフォンの実機がなくてもパソコン上でエミュレート実行ができるのでおおかたのアプリ開発が可能です。たいそれたことはできないですがものづくりを楽しむことに尽力したいと考えています。
Androidアプリ開発環境構築、再び
Androidアプリ第2弾
・初歩からスタートするAndroidアプリ開発
今回は、等差数列の和を求めるアプリを作ってみます。公差1でn項までの等差数列の和はn(n+1)/2で簡単に求めることができます。数式で表現すれば次のようになります。それでは早速、スタートします。
1)アルゴリズムは加算をn回繰り返して求めます。和をtとすればtをゼロに設定し、初項から順に加え新しいtとしてn項まで加算を繰り返します。n項の値が最初から分かっているので算出法は単純ですが、項数が増すほどn(n+1)/2で求めるよりも算出時間がかかり得策ではありません。
しかし、算出式のない大学共通学力試験の科目の合計点を求める場合などに応用できるので、敢えてこの方法を採用します。算出法が1つだけでない点に興味を抱いていただけるとありがたいです。
2)プロジェクトは前回と同様に、ECLIPSEプロジェクト新規作成画面で作成します。プロジェクト名とApplication NameにはSequenceを、ランチャーアイコンには星印を、Activity Nameにはcalculateを指定します。
3)srcフォルダのCalculate.javaに修正を加えます。
プロジェクト全ファイルは末尾に添付した圧縮を解凍して得られます。今回、プラグインツール[Syntax highlighter Evolved]をインストールしましたので、ソースコードに行番号が表示されて見やすくなりましたがコピー&ペーストしても行番号は付きません。
<SourceCode>
package com.sample.sequence; // 2012-11-12 import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.*; import android.os.Bundle; import android.view.View; // MainClass public class Calculate extends Activity { /** Called when the activity is first created. **/ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // make instance of ViewClass. MyCircleView view = new MyCircleView(getApplication()); // set View. setContentView(view); } } // display class @SuppressLint("DrawAllocation") class MyCircleView extends View { // initialize View public MyCircleView(Context context) { super(context); setFocusable(true); } // actualy,method of display. protected void onDraw(Canvas canvas) { int t = 0; // 和をクリアする for(int i = 0; i t += i; // 順次、項値を加え、新しい和にする } Paint paint = new Paint(); // make paint-object super.onDraw(canvas); // set back-color. canvas.drawColor(Color.WHITE); paint.setTextSize(20); // make display-object. // make display-object. canvas.drawText("等差数列の和=" + t, 40, 100, paint); // 算出した和を表示する } }
4)ビルドするために、「実行」します。
錠を右のスピーカまでドラッグして実行に移します。
5)ファイル一覧
C:. │ .classpath │ .project │ AndroidManifest.xml │ ic_launcher-web.png │ proguard-project.txt │ project.properties │ Tree.TXT │ ├─assets ├─bin │ │ AndroidManifest.xml │ │ classes.dex │ │ jarlist.cache │ │ resources.ap_ │ │ Sequence.apk │ │ │ ├─classes │ │ └─com │ │ └─user │ │ └─sequence │ │ BuildConfig.class │ │ Calculate.class │ │ MyCircleView.class │ │ R$attr.class │ │ R$drawable.class │ │ R$id.class │ │ R$layout.class │ │ R$menu.class │ │ R$string.class │ │ R$style.class │ │ R.class │ │ │ └─res │ ├─drawable-hdpi │ │ ic_action_search.png │ │ ic_launcher.png │ │ │ ├─drawable-ldpi │ │ ic_launcher.png │ │ │ ├─drawable-mdpi │ │ ic_action_search.png │ │ ic_launcher.png │ │ │ └─drawable-xhdpi │ ic_action_search.png │ ic_launcher.png │ ├─gen │ └─com │ └─user │ └─sequence │ BuildConfig.java │ R.java │ ├─libs │ android-support-v4.jar │ ├─res │ ├─drawable-hdpi │ │ ic_action_search.png │ │ ic_launcher.png │ │ │ ├─drawable-ldpi │ │ ic_launcher.png │ │ │ ├─drawable-mdpi │ │ ic_action_search.png │ │ ic_launcher.png │ │ │ ├─drawable-xhdpi │ │ ic_action_search.png │ │ ic_launcher.png │ │ │ ├─layout │ │ activity_calculate.xml │ │ │ ├─menu │ │ activity_calculate.xml │ │ │ └─values │ strings.xml │ styles.xml │ └─src └─com └─user └─sequence Calculate.java
6)Sequenceプロジェクト内の全ファイル(Sequence.zip)を添付します。エラーが発生することなく実行までこぎつけられましたが、開発環境が異なりエラーが発生することがあるかも知れません。エラーのガイドメッセージやネットのお助け情報により解決できそうです。