下右左方向をひっくり返せるようになった。

上方向だけだと2個しか石が置けなくてつまんないし、早く遊びたくなったので、やっぱりとりあえず動くものを完成させようと思い、コピペ手直しで下右左方向の石をひっくり返せるようにした。

for文が変わっただけなのでそれだけ書き留めとこう。

下右左

for(int di = (r + 1) ; 8 > di ; di++ ){
    tv = getTextViewFromTag(di,c);

これと

for(int j = (di - 1) ; (di - StoneCount - 1) < j ; j--){
    tv = getTextViewFromTag(j,c);

ひっくり返していく方

for(int ri = (c + 1) ; 8 > ri ; ri++ ){
    tv = getTextViewFromTag(r,ri);
for(int j = (ri - 1) ; (ri - StoneCount - 1) < j ; j--){
    tv = getTextViewFromTag(r,j);

for(int li = (c - 1) ; -1 < li ; li-- ){
    tv = getTextViewFromTag(r,li);
for(int j = (li + 1) ; (li + StoneCount + 1) > j ; j++){
    tv = getTextViewFromTag(r,j);

 

これだけなんだけど色々あった。頭の中で今どの位置にいるかを覚えながらあーでもないこーでもないとやっていたので変に疲れた。

次は斜め方向だな、あとちょっとだ。

カテゴリー: したい | タグ: , , , | コメントする

石をひっくり返したい

いよいよコアな部分だー

まずは一方向だけのを作ってみたいな。

考え方

は、から拝借しつつ参考にした。

でも結局番兵とかがよく分かんなかった。

いいんだ、作りながら考えるんだ。

タップされた位置を取得

GridLayoutのxmlを書いた時点でrow, columnという馴染み深い単語を目にしていたので、てっきり簡単にTextViewの位置を取得できるもんだと思っていたら、全然見つからないでやんの。

view.getid()は意味の分からん数字だし、getRow()的なメソッドも見当たらない。

唯一見つけれた

GridLayout.LayoutParams params = (GridLayout.LayoutParams) tv.getLayoutParams();
GridLayout.Spec p = params.rowSpec;

GridLayout.LayoutParamsで宣言して子View.getLayoutParams()使ってrowSpec使う、みたいなのをやってみたけど、rowSpecの取扱がよく分からず…。

最終的にTextViewのxmlに

android:tag="00"

とTagを設定した。64個。手動で。そして、これをInteger.ParseInt(tv.getTag().toString)してRC代わりに使ったろうと思う。

あー疲れた、絶対もっといいやり方があるんだろうなぁ。あとなんで0始まりにしちゃったかなぁ。

関数をいっぱい作る

どう書こう。処理の流れに沿って書いてく。

putStone()

public void putStone(TextView tv){
    String stone = tv.getText().toString();
    int Row = SplitStrRCtoIntRow(TagToString(tv));
    int Column = SplitStrRCtoIntColumn(TagToString(tv));

    parentView = (View) tv.getParent();

    if(!stone.equals("")){
        Toast.makeText(this.con,"そこに石は置けません", Toast.LENGTH_SHORT).show();
        return;
    }

    CheckReversibleUP(tv,Row,Column);

こうなった。

タップされたTextViewのTagを取得。TagからRow,Columnに分けてあげてCheckReversibleUPにviewとともに渡してあげる。

親Viewを取得する

初めは取得したTextViewをそのまま渡してて、findViewWithTagやっても取得できず詰まってた。で、

parentView = (View) tv.getParent();

と、親View取得してからやるもんだと分かってからが捗った。parentViewはBoardクラスのメンバ変数にして、どの関数からでも使えるようにした。

tagをRowとColumnに分ける
private String TagToString(TextView v){
    String s;
    s = v.getTag().toString();
    return s;
}
private Integer SplitStrRCtoIntColumn (String s){
    int c;
    c = Integer.parseInt(s.substring(1));
    return c;
}
private Integer SplitStrRCtoIntRow (String s){
    int r;
    r = Integer.parseInt(s.substring(0,1));
    return r;
}

TagがObject型だったのでStringに変換する。それをさらに1文字目と2文字目に分割する。戻り値が2個の場合の関数の作り方がわかんない、のでこうなった。関数作るの楽しい。でも作り過ぎかなぁ。

CheckReversibleUP()

private void CheckReversibleUP(TextView v,int r,int c){
    TextView tv;
    int StoneColor;
    int StoneCount = 0;

    for(int i = (r - 1) ; -1 < i ; i-- ){
        tv = getTextViewFromTag(i,c);

        if(!existStone(tv)){
            break;
        }

        StoneColor = getStoneColor(tv);

        if(PlayerTurn == StoneColor && StoneCount < 1){
            break;
        }

        if(PlayerTurn != StoneColor){
            StoneCount++;
            continue;
        }

        if(PlayerTurn == StoneColor){
            for(int j = (i + 1) ; (i + StoneCount + 1) > j ; j++){
                tv = getTextViewFromTag(j,c);
                setStoneToCell(tv);
            }

            setStoneToCell(v);
            PlayerTurn = PlayerTurn * (-1);
        }
     }
}

Checkと言いつつ、引っ繰り返すところまでやっている。良くないね。まぁそれは置いといて。

for文でタップ位置のRCを元に、上方向の石を調べていく。javaのfor文初めて書いたぜ。

上方向の場合、列は変わらないので行だけ-1していく。初期値を(タップされた行番号-1)にして、カウンタ変数が盤面外にあたる-1になったら終わり。

  1. 石があるか調べる。
  2. 石の色を調べる。
  3. 違う色の石だったらStoneCountに+1。
  4. 同じ色の石が出てきたら間を引っ繰り返す。

という流れ。まぁだらだら書いてこ。

getTextViewFromTag()
private TextView getTextViewFromTag (int a, int b){
    String s = String.valueOf(a) + String.valueOf(b);
    TextView res = parentView.findViewWithTag(s);
    return res;
}

Tagをがっちゃんこして指定Viewを取ってくる。ここで親Viewが必要だった。ずっと何度もできないできないと悩んで、これは詰んでしまったか…と諦めかけていた時に、デバッグしてみたらちゃんとViewを取れてないことを発見。ずっと子Viewの中を探していたことになる。なるほど、そりゃ無いわな、とホッとした思い出。

existStone()
private boolean existStone(TextView v){
    return !(v.getText().toString().equals(""));
}

この書き方IDEに教えてもらった。あいついいヤツだ。TextViewが空白でなかったらtrueを返す。

getStoneColor()
private int getStoneColor(TextView v){
    int sc = 0;

    switch (v.getText().toString()){
        case("●"):
            sc = BLACK;
            break;
        case("○"):
            sc = WHITE;
    }
    return sc;
}

色を数値で扱ったほうが具合が良いらしいので作ってみた。確かに手番の交換がPlayerTurn*(-1)するだけなのでスムーズ。

setStoneToCell
private void setStoneToCell(TextView v){
    switch(PlayerTurn){
        case(BLACK):
            v.setText("●");
            break;
        case(WHITE):
            v.setText("○");
            break;
    }
}

手番によって置く石を変える。引っ繰り返す石も新たに置く石も同じ色なので使い回せる。ただこの関数2回使ってるので減らしたい。

引っ繰り返す処理
if(PlayerTurn == StoneColor){

    setStoneToCell(v);

    for(int j = (i + 1) ; (i + StoneCount + 1) > j ; j++){
        tv = getTextViewFromTag(j,c);
        setStoneToCell(tv);
    }

    PlayerTurn = PlayerTurn * (-1);
    break;
}

同じ色の石をめっけたら戻りつつ石を引っ繰り返す。そんで手番を変える。

ここのif文でめっちゃ怒られてて、

Condition ‘PlayerTurn == StoneColor’ is always ‘true’ less… (Ctrl+F1)
This inspection analyzes method control and data flow to report possible conditions that are always true or false, expressions whose value is statically proven to be constant, and situations that can lead to nullability contract violations.
Variables, method parameters and return values marked as @Nullable or @NotNull are treated as nullable (or not-null, respectively) and used during the analysis to check nullability contracts, e.g. report NullPointerException (NPE) errors that might be produced.
More complex contracts can be defined using @Contract annotation, for example:
@Contract(“_, null -> null”) — method returns null if its second argument is null @Contract(“_, null -> null; _, !null -> !null”) — method returns null if its second argument is null and not-null otherwise @Contract(“true -> fail”) — a typical assertFalse method which throws an exception if true is passed to it
The inspection can be configured to use custom @Nullable
@NotNull annotations (by default the ones from annotations.jar will be used)

こんな。ここがちょっと理解できなくて、なんで常にtrueになっとるぞと言われるんだろう。breakとcontinueで離脱してるから…?てことはここのif文いらないのかな…。でもあったほうがあとで分かりやすいんじゃないかなぁ…。だから無視してる。

感想と展望

CheckReversibleUPはもうちょいスッキリ書けるんじゃなかろうか。なんというか置き石可能かどうかの調査と、実際に石を返す処理をもうちょっとキレイに分離させたい。けど、せっかくできたのを崩すのも惜しい。

ていうか、楽しくなっていっぱい書いちゃったけど、内部での処理でこんなに関数分割していいもんなんだろうか。クラス外部から利用する関数putStoneの一つしかないもんな。あと関数書く順もわからん。今は分けたかったらてきとーな位置に書いてる。から時々あれ?あの関数どこだ?ってなる。

あと、Boardが肝心の盤面の状態を保持してないような。画面のTextViewらがその役割を担っちゃってるし、てきとーだけどBoard.getStoneArrayとかBoard.getStateみたいなんがあった方がいいのかなぁ。なにに使うかは決まってないけど。なんかそっちのがかっこよそう。

とりあえず、上方向はできた!嬉しいなぁ。画面的には動きが少なくなってきているけど、思ったような制限を作れてるってことだもんな。あと7個おんなじようなのを書けばいいんだ。7個、7個ね。7個かぁ。めんどいな。正直おんなじような処理なんだし、まとめて書くような方法がないもんかね。どうなのかね。調べてみよ。

参考

http://koga-app.tumblr.com/post/49431453714/findviewwithtag%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9

https://www.javadrive.jp/start/wrapper_class/index4.html

https://dev.classmethod.jp/smartphone/android/android-tips-34-grid-layout/

https://ja.stackoverflow.com/questions/29886/gridlayout%E3%81%AE%E5%AD%90view%E3%81%8B%E3%82%89%E7%8F%BE%E5%9C%A8%E9%85%8D%E7%BD%AE%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8Bcolumn%E3%81%A8row%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95

http://s-prism3.seesaa.net/article/429144291.html

カテゴリー: したい | タグ: , , , | コメントする

クラス使ってみたい

やってみよう。書いたのもったいないけど。

紆余曲折

クラス作り

リバーシ作った人のやつ見ると

  • プレーヤー(人間対人間、人間対機械)
  • マス
  • ルール

あたりが必要みたい。

自分の場合、機械のプレーヤーなんてそもそも作れんし、石は○●だし、マスはTextViewだし、作るの盤ぐらいでいっかなーって。ルールは盤に含めるとかできんじゃないかな、どうなのかな。

Board.javaを作った

public class Board {
    final int BLACK = 1;
    final int WHITE = -1;
    int PlayerTurn = 1;
    private Context con;

    public Board(Context context){
        this.con = context;
    }

    public void putStone(TextView tv){
        String stone = tv.getText().toString();

        if(!stone.equals("")){
            Toast.makeText(this.con,"そこに石は置けません", Toast.LENGTH_SHORT).show();
        }else{
            switch (PlayerTurn){
                case(BLACK):
                    tv.setText("●");
                    PlayerTurn = WHITE;
                    break;
                case(WHITE):
                    tv.setText("○");
                    PlayerTurn = BLACK;
                    break;
            }
        }
    }
}

いちおこれで動いた。あっさりできたわけではなくかなり手間取った。

Toast表示するのに引数Contextが必要で、前と同じようにthisってやるとBoardの方と認識される。メインの方でgetApplicationContext()しておき、インスタンス化する時に引数で渡してあげると。ほいでBoardのコンストラクタで受け取ってあげる。なるほどなぁ。調べなきゃ分かんないよ。

Reversi.javaを変更

メインの方でNewする位置もよく分かってなかった。最初BoardのコンストラクタにTextViewの引数を設定していたし、メインのocClick内でNewしていた。でもそれだとClickされるたびにNewされて、NewされるたびにPlayerTurnが初期化され、黒石連打になっていた。だもんでじゃあonCreate内でNewすりゃいいのかとやってみたら、今度はonClick内でBoardが使えない。オブジェクト変数の宣言とNewをいっぺんにやってたのが原因だった。ので、変数の宣言を頭でやって、onCreate内でNewすると、onClick内でも使えるようになり、解決した。試行錯誤の連続です。

ということで、メインのReversi.javaは

最初

public class Reversi extends AppCompatActivity {
    Board board;

onCreate内

Context context = getApplicationContext();
board = new Board(context);

onClick内

TextView tv = findViewById(id);
board.putStone(tv);

と書けた。

なんだろな、やっぱりスコープがちゃんと分かってないからこんな手間取るのかな。それだけじゃないんだろうけども。うーむ。

PlayerTurnってここでいいんだろうか、Playerって付いてるし、Playerクラスを作ったほうがいいのかなぁ。でも手番管理って盤面の仕事な気もするし。

あとクラスを作ったからといって、そこまで楽になったのかというとそうでもないような気がする。メインは見晴らしが良くなったけど、Boardの方はこっからちょっとづつ足してくわけだもんね、やることは一緒なんじゃないだろうか。このままいくとputStoneが肥大化していくような気がしてならない。まぁせっかく作ったんだしこれを使っていこう、そうしよう。

参考

http://rui-phone.hatenablog.com/entry/2014/09/23/213642

http://kmaebashi.com/programmer/object/othello.html

http://d.hatena.ne.jp/prime503/20100106/1262767141

http://www.aerith.net/design/othello-j.html

https://akira-watson.com/android/class-method.html

カテゴリー: したい | タグ: , , , | コメントする

初期画面を設定し、白と黒を交互に置きたい

あと石が置いてある場所には置けないようにしたい。

そんでまぁ、とりあえず書いてみることにした。

目的の機能だけ作った

初期画面

真ん中の4つのマスにTextを設定するだけ。この機会にルールをちゃんと見てみたら、置き方にも決まりがあるのね。黒が右って初めて知った。

石が置いてある時に置けないようにする

TextView tv = findViewById(id);
String stone;
stone = tv.getText().toString();

if(!stone.equals("")){
    Toast.makeText(this,"そこに石は置けません", Toast.LENGTH_SHORT).show();
}

タップした所のTextを取得。それが空白以外(○、●)だったらToastを表示する。

ほんとは文言はString.xmlから引っ張るほうが良いみたい。

手番によって置く石を変える

int PlayerTurn = 1;
final int BLACK = 1;
final int WHITE = -1;
}else{
    switch(PlayerTurn){
        case BLACK:
            tv.setText("●");
            PlayerTurn = WHITE;
            break;

        case WHITE:
            tv.setText("○");
            PlayerTurn = BLACK;
            break;
    }
}

PlayerTurnで手番を管理して、手番によって置く石を変更して、石置いた後は手番を変える。

これでできた。finalって初めて使ったなぁ。

できたはできたんだけど、今後もこんな感じで処理の流れを見つつ間に追記したりするのか?と不安になる。そいで色んなオセロ・リバーシのソースを見てみたら、クラスを作ると良いみたい。ただ、VBA書いてる時は、クラスとか使ったことないし、自分に書けるかというと、どうだろう。ただやってみたくはあるなぁ。やってみようかなぁ。

参考

https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%BB%E3%83%AD_(%E9%81%8A%E6%88%AF)#%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AA%E3%83%AB%E3%83%BC%E3%83%AB

https://developer.android.com/reference/android/widget/Toast

https://java-reference.com/java_basic_final.html

カテゴリー: したい | タグ: , , , | コメントする

タップすると石が置けるようになった

石は置けるが、こっから拡張していけるんだろうか。

石を置けた。

最初タップすらできなかった

まぁ、文字を表示する用だもんな、それをタップしてどうのこうのなんて普通やらないんだろうな、とちょっと凹んだとこで調べてみると。

clickableという設定があるみたい。

android:clickable="true"

そんでclickableだけだと

‘clickable’ attribute found, please also add ‘focusable’ less… (Ctrl+F1)
A widget that is declared to be clickable but not declared to be focusable is not accessible via the keyboard. Please add the focusable attribute as well. Issue id: KeyboardInaccessibleWidget

と言われる。キーボードで操作してる人が困るよってことなんだろうけど、これをキーボードで操作する人なんているかな…と思う。でもまぁ、せっかく言ってくれてるんで

android:focusable="true"

も入れてみた。これでタップできるようになった。

TextViewの縦横長を指定

最初電卓と同じようにリスナ作ってハンドラ書いてー、と、ひとマス分だけ書いてみた。

そんでタップすると「○」が表示された。でも列の幅が何故か変わってしまった。

おそらくTextViewのheight,widthをwrap_contentにしてたのが原因かなーと。

android:layout_width="10dp"
android:layout_height="10dp"

と、10dpにしてみたら幅も動かなくなった。

dpで大丈夫なのかな。そこらへんがいまいち分からない。

リスナを64個も書くのやだな

1個だけは書いてみたんだけど、これを64個も繰り返すの…?と思ったら嫌になってきたので、なにか方法はないかと探す。

xmlにonClickの値を設定するといいみたい。

android:onClick="PutStone"

とxmlに追加して、Reversi.javaに

public void PutStone(View view) {
    int id = view.getId();
    switch(id) {
        case R.id.textView00:
//略
TextView output = findViewById(id);
output.setText("○");

とやってみたらできた。

ちなみにswitchのcaseはむっちゃ長い。

探したけどよく分からないの…。

参考

https://qiita.com/nein37/items/0a92556a80c6c14503b2

https://sandragon.hatenablog.com/entry/2013/07/09/014639

http://gucci1208.com/android%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%83%AA%E3%82%B9%E3%83%8A%E3%83%BC%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81-197.html

 

カテゴリー: したい | タグ: , , , | コメントする

AndroidStudioでリバーシの画面を作った

まずは画面を作りたいなぁと思って色々調べた。

盤面づくり

先人たちのサンプルを見るとcanvasというものを使っているようだ。

なにそれ。

画面サイズ取得してー、計算で位置設定してー、とか。

そしたら石を置くマスの位置取得とかどうやるんだーとか。

ちょっととっつきにくいなぁ…と思ったので、他の表現方法を探す。

ていうかできることが見よう見まねでxmlを編集することだけだし、その延長でなんとかならんかなぁと思ったのでTextViewを並べりゃいんじゃね?となった。

そんでlinearlayoutを入れ子にしてみたりしたけどなんかうまくいかない。

ていうか、正方形の格子状のレイアウトみたいなやつって無いのね。

カスタムViewというものを使って自作してる人や、Tablelayoutを使って試行錯誤している人や色々。手に余ってしまう…。

失敗集

で、Gridlayoutを使ってみることにした。

TextViewを計64個配置すれば盤面ぽくなるはず…!

できたのがこちら

ぽく見えるっちゃ見える。

でも実機のP20Proで見ると

こうなる!

想像でしかないけど、

app:autoSizeTextType="uniform"

が縦方向の長さを基準にフォントサイズを決めちゃってんのかなーと。

ということは、画面サイズの横幅を取得して、GridLayoutの縦サイズに設定すればいいのでは…?と思い調べてこんな感じでコピペしてみたけど

WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();

Point realSize = new Point();
disp.getRealSize(realSize);

int realScreenWidth = realSize.x;

GridLayout gridLayout = findViewById(R.id.gridLayout1);
GridLayout.LayoutParams params = new GridLayout.LayoutParams();
params.height = realScreenWidth;
gridLayout.setLayoutParams(params);

結局うまくいかず、アプリが強制終了してしまった。。。

もうこれは欲を出さずに、直でサイズ指定しろや、ということなのだろうな。

ということで、GridLayoutのw,hを

android:layout_width="match_parent"
android:layout_height="400dp"

とすることに。

あと枠線さえあればそれっぽく見えるだろと調べ、こちらの

http://d.hatena.ne.jp/yokkong/20111116/1321425474

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke android:width="2px" android:color="#CCCCCC" />
    <padding android:left="2px" android:top="2px"
        android:right="2px" android:bottom="2px" />
    <corners android:radius="2px" />
</shape>

をDrawableに作成。

そんでTextViewに

android:background="@drawable/tv_border"

を追加した。

 

できあがり

うむ。

とりあえずそれっぽくはなったが、果たして動かせるのだろうか。

でもやっぱ楽しいな、試行錯誤が楽しい。

参考

 

https://qiita.com/yysk/items/da65ae4c82c84d0c0449

https://qiita.com/hmiyado/items/5e2c9f2b4423e629f4d0

https://dev.classmethod.jp/smartphone/android/android-tips-34-grid-layout/

https://akira-watson.com/android/screen-size.html

http://d.hatena.ne.jp/yokkong/20111116/1321425474

カテゴリー: したい | タグ: , , , | コメントする

ちょこちょこ作るやつがほしい

電卓できてからなんか燃え尽き症候群みたいになってる。

そういえば、小数の計算がおかしいなーと思って確認してみたら、BigDecimalとかいうものを使わないとならないみたい。

それはまぁ、めんどくさくなってしまったので置いといて。

リバーシを作りたい。作りたいけどそんなすぐにホイホイっとできるわけでもない。

こう、なんか煮詰まった時に息抜きで作れるレベルのものがほしいな、リバーシごときで煮詰まるなよという声が聞こえてきそうだけれども。

と、思ったので、ちょっと考えて。また計算機作ることにした。

数学の公式集みたいなやつがいいな。入力→計算→出力だけで、演算子とか気にしない感じのやつ。

んで、いろんな公式をちょこらちょこら足していくの。

ていうかGooglePlayに公開してみたい。あわよくば広告もつけてみたい。

ちょっと調べてみたら↑みたいなアプリは腐るほどあるので、俺みたいな素人が作ったアプリが紛れ込んでも問題ないだろう。

あと本買った。

[amazon asin=”4798152021″ kw=”android 開発”]

これで百人力やで。

ゆっくりコツコツやってけたらいいな。

カテゴリー: したい | タグ: , , | コメントする

AndroidStudioで電卓できた②

心変わり

昨日(一昨日になった)できあがったことで、満足しててきとーな記事になってしまった。

でもやっぱり、初めてちゃんとできあがったアプリだし

考えたこととか、分かんないこととか残しとこうと思う。

ソースはこっち。電卓の中身とかは書けるほど考えてない。

import

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

そもそもimportって…なに…?というレベルだったので

コードで「ここアカンぞ」って言われた時にAlt+Enterを

押すと勝手に追加されていった。べんり。

未だに何の為に追加されているのか分からないっていう。

viewとかwidgetとかついてるからこれら使うのに必要なんだろう。

変数の宣言

public class MainActivity extends AppCompatActivity {
    String opText;
    String outText;
    boolean afterOp;
    boolean isStacked;
    Float StackedValue;

変数を書く位置も分かってなかった。

最初onClickの中で宣言してたのだが、そうすると変数に値が保持されていない。

booleanはいつもfalseだし、StackedValueはいつも空。

ボタンを押すごとに突飛な数字が表示されるし、最悪落ちる。

あ、ここに書けばいいんだって分かった時は腑に落ちた感がすごかった。

Activity全体で使う変数はここに書けばいいんだね。

あと初期化してない、そういえば。でも動く。すごい。

ボタンにリスナを設定

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button bt1Click = findViewById(R.id.button1);
        ButtonClick bt1listener = new ButtonClick();
        bt1Click.setOnClickListener(bt1listener);
//省略

ここが冗長な気がしてる。

画面の作り方をもっと調べれば、簡単に書けるんじゃないだろか。

ただ今はこれしか知らんので、こうやった。

あと@Overrideの意味が分からない…。もう全然分からない。

最初プロジェクトを新規作成した時にあったのでそのままにしてる。

いつか謎が解けるんだろうか。

ここがボタンのイベントハンドラなの?

private class ButtonClick implements View.OnClickListener{
    TextView output = findViewById(R.id.tvOutput);

これはもう、こう書けばTextViewを取得できるよっていうのをそのまま書いた。

ただ書く場所は果たしてここでよかったのか、動いてるからいいんだろうけど

確証があってこうしてるわけではないので、完全に手探り。

関数AppendTexts

void appendTexts(String t){
    outText = output.getText().toString();

    if (!afterOp && !(outText.equals("0"))) {
        t = outText + t;
    }else if(t.equals(".")) {
        t = "0" + t;
    }

    output.setText(t);
    afterOp = false;
}

参考にしたサイトから引っ張ってきている。

ただ、そのまま引っ張ってきたら、「0」の後に「1」を押すと「01」って

表示されちゃったので、!(outText.equals(“0”))で0を除外。

あと表示が「0」の時に「.」を押すと「.123」みたいになってしまったので

それ用に処理を入れた。

文字列の比較で「==」を使ったら

String values are compared using ‘==’, not ‘equals()’ less… (Ctrl+F1)
Reports any use of == or != to test for String equality, rather than the equals() method.

「equals」使えって怒られた。

あと多分全然分かってないのが関数の宣言方法ね。

↑になる以前はvoidの前にPublicって入ってた。

「java 関数 作り方」とかでググったサイトにそう載ってたからね。

でもPublicって入ってると

Access can be package-private less… (Ctrl+F1)
This inspection reports all fields, methods or classes, found in the specified inspection scope, that may have their access modifier narrowed down.

つってさ、怒られるの。多分スコープが適切じゃねえよ?つってるんだろうけど

じゃあどうすればいいの?ってさ、なるじゃない。スコープなんてまだ分かってないんだし。

で、とりあえず取ってみたら消えた。ので、一安心。

残る謎はvoidだ。これ一体なんの為に付いてるんだろう。

そういえば、これが初めて作った関数なんだなぁ。

VBAでも使ったことなかったりする。

同じような処理は同じコードをコピペして使いまわしてた。

それに比べればだいぶ進歩したなぁ。

関数Calculation

void Calculation(String o, Float s){
    Float r = 0.0f;

    if(o.equals("+")){
        r = s + Float.parseFloat(output.getText().toString());

    }else if(o.equals("-")){
        r = s - Float.parseFloat(output.getText().toString());

    }else if(o.equals("×")){
        r = s * Float.parseFloat(output.getText().toString());

    }else if(o.equals("÷")) {
        r = s / Float.parseFloat(output.getText().toString());
    }

    if(r == r.intValue() ){
        output.setText(String.valueOf(r.intValue()));
    }else{
        output.setText(r.toString());
    }
}

計算する関数~!

Float.parseFloat(output.getText().toString())で表示からText取得してStringに変換した後

Floatに型変換…のつもり。これもっと短く書けないのかな。

でもとりあえずやりたいことができてるんでいいかな。

引数はButtonの文字とTextViewの数字だったな確か。

引数2個のも作れた。最高やね。

1個目のifのところで

‘if’ statement replaceable with ‘switch’ statement less… (Ctrl+F1)
Reports any if statements with which can be replaced by a switch statement. This inspection will automatically suggest string switches when the project language level is Java 7 or higher.

Switch文も書けないの?ぷぷぷwって言われてるけど無視してる。

あ、あとAppendTextsのpublicも再び。

2個目のifは計算結果が整数値だったときに、「2.0」って小数部分を表示

させるんじゃなく、「2」って表示させたいがために入れてる。

output.setText(r.toString());のところで

Number formatting does not take into account locale settings. Consider using String.format instead. less… (Ctrl+F1)
When calling TextView#setText * Never call Number#toString() to format numbers; it will not handle fraction separators and locale-specific digits properly. Consider using String#format with proper format specifications (%d or %f) instead. * Do not pass a string literal (e.g. “Hello”) to display text. Hardcoded text can not be properly translated to other languages. Consider using Android resource strings instead. * Do not build messages by concatenating text chunks. Such messages can not be properly translated. Issue id: SetTextI18n More info: http://developer.android.com/guide/topics/resources/localization.html

て、怒られるんですけどよく分かんないんです。

String.format使えよって言われてるのかな。でも、この使い方でちゃんと

整形されるような引数が分からなかった。まぁ、動いてるので…。

今思ったんだけど

void Calculation(String o, Float s){
    Float r = 0.0f;
    Float t = Float.parseFloat(output.getText().toString());

    if(o.equals("+")){
        r = s + t;

    }else if(o.equals("-")){
        r = s - t;

    }else if(o.equals("×")){
        r = s * t;

    }else if(o.equals("÷")) {
        r = s / t;
    }

    if(r == r.intValue() ){
        output.setText(String.valueOf(r.intValue()));
    }else{
        output.setText(r.toString());
    }
}

とかのがかっこいいかな。好みか。

onClickメソッド

public void onClick(View view) {
    String apText;
    int id = view.getId();
    Button btn = (Button) view;

apTextってなんでここで宣言してるんだろう。なんとなく、かな。

view.getId();で押されたボタンのidを取ってきて、switchで振る方法を取ることに。

あとButtonのTextを取得したいのでviewからキャスト。全部受け売りです。

数字ボタン

switch(id){
    case R.id.button0:
    case R.id.button1:
    case R.id.button2:
    case R.id.button3:
    case R.id.button4:
    case R.id.button5:
    case R.id.button6:
    case R.id.button7:
    case R.id.button8:
    case R.id.button9:
        apText = btn.getText().toString();
        appendTexts(apText);
        break;

caseをもっときれいに書けないのかな。なんかありそうだけど。

forで回すとか?

btn.getText().toString();でButtonのTextを取得してappendTextsに渡してるだけ。

ButtonのTextを取得する方法を見つけるまでは

0~9までに同じようなコードが並んでたなぁ…

演算子ボタン(+-*/)

case R.id.buttonplus:
case R.id.buttonminus:
case R.id.buttonby:
case R.id.buttondiv:
    if(isStacked) {
        Calculation(opText, StackedValue);
    }

    StackedValue = Float.parseFloat(output.getText().toString());
    isStacked = true;
    afterOp = true;
    opText = btn.getText().toString();
    break;

ここで結構詰まった。

opTextに押された演算子を代入しておくわけだけど

最初case~if(isStacked)の間に書いていた。

そうすると例えば、10+30-20という計算をするとき「-」を押した際に

本来であれば40と表示されなければならないのだが-20と表示されてしまう。

StackedValueに10が入っていて、表示が30。この状態で「-」ボタンを押すと

10-30になってしまうというわけだ。

この時点では「=」を実装していなかった為か、どのタイミングでどの演算子を

使う、ということがきちんと理解して組み立てられていなかった。

結果、演算子代入のタイミングをCalculationメソッド呼び出しの後にすることで

事なきを得た。設計からやっていないとやっぱダメなんだなぁと思った。ちぇ。

演算子ボタン(=)

case R.id.buttonequal:
    if(isStacked){
        Calculation(opText,StackedValue);
    }

    isStacked = false;
    afterOp = true;
    break;

前記の事があったので、特に悩まず。

今ちょっと思ったのが、ここでisStackedをfalseにしとくのが正しいのか。

StackedValueの値を更新するべきなんじゃないかとか。

あとでtrueにした時、どんな事が起こるか試そっと。

ていうか本物の電卓と比べりゃいいのか。

「.」ボタン

case R.id.buttonperiod:
    String dplText;
    dplText = output.getText().toString();

    if (!dplText.contains(".")){
        appendTexts(".");
    }
    break;

表示文字列を取ってきて、「.」が含まれてなかったら「.」をつなげると。

.contains()っていうのを覚えました^^

Cボタン

case R.id.buttonc:
    output.setText("0");
    isStacked = false;
    afterOp = false;
    StackedValue = null;
    break;

変数とTextViewの表示を初期化してあげる。

なんとなくStackedValueをnullで初期化してしまってるんだけど

これでいいんだろうか。これじゃダメだった場合の理由を知りたいな。

0.0fとかの方がいいのかな。うむむ。

その他

演算子を連続で押したときの挙動が変かも。

例えば3+-+と押した時に3→3→6→0となる。

理由はわかるけど直し方が微妙だ。

 

0除算の処理もつけてない。

ただやってみたら表示が「Infinity」になったので

かっこいいと思ってそのままにした。

 

デバッグのやり方を覚えた。これが一番大きいかも。

VBAではF8を押すと1行ずつ処理が確認できて、把握しやすかった。

Androidでは実機で動かす以外のやり方を知らんかったので

把握しづらいなぁと思ってた。ちゃんと探すべきよね…。

 

こんな感じかな!

いかに自分が分かってないで作ってるかが分かっただけでも良し!

次はリバーシだ、1年ぐらいかなぁ~

カテゴリー: のーと | タグ: , , , | コメントする

AndroidStudioで電卓できた

ついに電卓できた

こないだから再開して、色々調べてみたらできた。

やばい超うれしい。

前回の

https://dalomo.net/blog/2018/04/22/60/

に比べたら、自分で言うのもなんだけどすごい進歩したと思う。

動いてるとこ

おソース

https://dalomo.net/blog/2018/11/01/86/

apk

http://apk.dalomo.net/Calc.apk

色々あった

作るにあたってこちらのサイトが大変参考になりました。

http://msyk.net/keio/JavaBook/eclipse-indigo/ch12.html

正直一から自分で作ったわけではない。

そこは、それはそれ。流石に無理でした。

色々あったんだけど作るのに夢中で詰まったとこ書き留めるの忘れてた。

心の中にしまっておこう。

覚えてるのだけリンクしておこう。

参考

http://www.techscore.com/blog/2012/11/28/%E6%95%B0%E5%80%A4-%E2%87%94-%E6%96%87%E5%AD%97%E5%88%97%E5%A4%89%E6%8F%9B-java%E7%B7%A8/

https://stackoverflow.com/questions/5620772/get-text-from-pressed-button

https://developer.android.com/studio/run/?utm_source=android-studio#instant-run

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1295175227

 

次はなに作ろう。

と、考えてたら、リバーシが面白そう。

今度はある程度できるごとにメモしてこっと。

カテゴリー: できた | タグ: , , , | コメントする

電卓ソース

package net.dalomo.calc;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    String opText;
    String outText;
    boolean afterOp;
    boolean isStacked;
    Float StackedValue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button bt1Click = findViewById(R.id.button1);
        ButtonClick bt1listener = new ButtonClick();
        bt1Click.setOnClickListener(bt1listener);

        Button bt2Click = findViewById(R.id.button2);
        ButtonClick bt2listener = new ButtonClick();
        bt2Click.setOnClickListener(bt2listener);

        Button bt3Click = findViewById(R.id.button3);
        ButtonClick bt3listener = new ButtonClick();
        bt3Click.setOnClickListener(bt3listener);

        Button bt4Click = findViewById(R.id.button4);
        ButtonClick bt4listener = new ButtonClick();
        bt4Click.setOnClickListener(bt4listener);

        Button bt5Click = findViewById(R.id.button5);
        ButtonClick bt5listener = new ButtonClick();
        bt5Click.setOnClickListener(bt5listener);

        Button bt6Click = findViewById(R.id.button6);
        ButtonClick bt6listener = new ButtonClick();
        bt6Click.setOnClickListener(bt6listener);

        Button bt7Click = findViewById(R.id.button7);
        ButtonClick bt7listener = new ButtonClick();
        bt7Click.setOnClickListener(bt7listener);

        Button bt8Click = findViewById(R.id.button8);
        ButtonClick bt8listener = new ButtonClick();
        bt8Click.setOnClickListener(bt8listener);

        Button bt9Click = findViewById(R.id.button9);
        ButtonClick bt9listener = new ButtonClick();
        bt9Click.setOnClickListener(bt9listener);

        Button bt0Click = findViewById(R.id.button0);
        ButtonClick bt0listener = new ButtonClick();
        bt0Click.setOnClickListener(bt0listener);

        Button btpClick = findViewById(R.id.buttonplus);
        ButtonClick btplistener = new ButtonClick();
        btpClick.setOnClickListener(btplistener);

        Button btmClick = findViewById(R.id.buttonminus);
        ButtonClick btmlistener = new ButtonClick();
        btmClick.setOnClickListener(btmlistener);

        Button btbClick = findViewById(R.id.buttonby);
        ButtonClick btblistener = new ButtonClick();
        btbClick.setOnClickListener(btblistener);

        Button btdClick = findViewById(R.id.buttondiv);
        ButtonClick btdlistener = new ButtonClick();
        btdClick.setOnClickListener(btdlistener);

        Button bteClick = findViewById(R.id.buttonequal);
        ButtonClick btelistener = new ButtonClick();
        bteClick.setOnClickListener(btelistener);

        Button btpeClick = findViewById(R.id.buttonperiod);
        ButtonClick btpelistener = new ButtonClick();
        btpeClick.setOnClickListener(btpelistener);

        Button btcClick = findViewById(R.id.buttonc);
        ButtonClick btclistener = new ButtonClick();
        btcClick.setOnClickListener(btclistener);
    }

    private class ButtonClick implements View.OnClickListener{
        TextView output = findViewById(R.id.tvOutput);

        void appendTexts(String t){
            outText = output.getText().toString();

            if (!afterOp && !(outText.equals("0"))) {
                t = outText + t;
            }else if(t.equals(".")) {
                t = "0" + t;
            }

            output.setText(t);
            afterOp = false;
        }

        void Calculation(String o, Float s){
            Float r = 0.0f;

            if(o.equals("+")){
                r = s + Float.parseFloat(output.getText().toString());

            }else if(o.equals("-")){
                r = s - Float.parseFloat(output.getText().toString());

            }else if(o.equals("×")){
                r = s * Float.parseFloat(output.getText().toString());

            }else if(o.equals("÷")) {
                r = s / Float.parseFloat(output.getText().toString());
            }

            if(r == r.intValue() ){
                output.setText(String.valueOf(r.intValue()));
            }else{
                output.setText(r.toString());
            }
        }

        @Override
        public void onClick(View view) {
            String apText;
            int id = view.getId();
            Button btn = (Button) view;

            switch(id){
                case R.id.button0:
                case R.id.button1:
                case R.id.button2:
                case R.id.button3:
                case R.id.button4:
                case R.id.button5:
                case R.id.button6:
                case R.id.button7:
                case R.id.button8:
                case R.id.button9:
                    apText = btn.getText().toString();
                    appendTexts(apText);
                    break;

                case R.id.buttonplus:
                case R.id.buttonminus:
                case R.id.buttonby:
                case R.id.buttondiv:
                    if(isStacked) {
                        Calculation(opText, StackedValue);
                    }

                    StackedValue = Float.parseFloat(output.getText().toString());
                    isStacked = true;
                    afterOp = true;
                    opText = btn.getText().toString();
                    break;

                case R.id.buttonequal:
                    if(isStacked){
                        Calculation(opText,StackedValue);
                    }

                    isStacked = false;
                    afterOp = true;
                    break;

                case R.id.buttonperiod:
                    String dplText;
                    dplText = output.getText().toString();

                    if (!dplText.contains(".")){
                        appendTexts(".");
                    }
                    break;

                case R.id.buttonc:
                    output.setText("0");
                    isStacked = false;
                    afterOp = false;
                    StackedValue = null;
                    break;
            }
        }
    }
}
カテゴリー: のーと | タグ: , , , , | コメントする