リバーシで時間表示したい

チェスクロック的な時間表示をさせたいなーって思ってたんだけど、時間設定とか秒読みとか切れ負けとか実装するのめんどくさそう。なので経過時間だけ表示させようと思う。

Chronometer

一番簡単なのがこれみたい。デザインとかは今の所どうでもいいのでサクッと作ってしまおう。…と思っていたんだけど、Chronometerはstopしても時間は流れていて、再開した時に止めてた分の時間も表示されてしまうとな?試してないから知らんけど。最初から暗礁に乗り上げてしまったぞ。どうしよう。

java.util.Timer

Javaに元からあるTimerっていうのを使うといいらしい。解説サイトをみてみると、マルチスレッドやらHandlerやら何やら難しい単語が並んでいる…。メインで動いてるプログラムとは別に用意するみたいな…?そんで別で実行した結果を渡したりするのがHandlerみたいな…?やばい、全然分からんぞ。調べてみても、start, stopに関する文章は出てくるけど、一時停止に関する文章は出てこないぞ。どういうことだ。うーんうーん。

java.util.concurrent.ScheduledExecutorService

一時停止する場合、こっちを使うらしい。もっと訳がわからないぞ。schedule, scheduleAtFixedRate, scheduleWithFixedDelayってTimer解説してるとこでも見たけど同じことやってるの?じゃTimerとの違いってなんじゃらほい…。あ、一時停止か。えーもうなんかわかんないよー。

再度Chronometer

なんか一時停止できるっぽい。タップされた時のシステム時間を取っておいて、現システム時間との差を使い、基準時間を設定し直してスタートさせるみたい。おっできそう。

private void setTimer(){

    switch(PlayerTurn){
        case(BLACK):
            BlackTimer.setBase(SystemClock.elapsedRealtime() + timeWhenStopped);
            BlackTimer.start();

            timeWhenStopped = WhiteTimer.getBase() - SystemClock.elapsedRealtime();
            WhiteTimer.stop();
            break;

        case(WHITE):
            WhiteTimer.setBase(SystemClock.elapsedRealtime() + timeWhenStopped);
            WhiteTimer.start();

            if(BlackStoneCount + WhiteStoneCount > 5) {
                timeWhenStopped = BlackTimer.getBase() - SystemClock.elapsedRealtime();
                BlackTimer.stop();
            }
            break;
    }
}

できた。黒手番が3手目ぐらいで時間変になってたので2手目以降にtimewhenstoppedに時間代入するようにした。

いつかまたちゃんとしたタイマーにも挑戦してみよう。

参考

https://so-zou.jp/mobile-app/tech/android/ui/widget/view/text-view/chronometer/

https://techbooster.org/android/application/934/

https://ameblo.jp/vegetable-it/entry-11245144566.html

http://www.02.246.ne.jp/~torutk/javahow2/timer.html

https://blog.mumei-himazin.info/?p=474

https://stackoverflow.com/questions/5594877/android-chronometer-pause

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

リバーシの終了処理を作りたい(+パスの処理も)

終了の判断を作りたい。今はプレイヤー任せ。

終了処理

終了処理の中に、パスの処理も含まれるみたいなので、どっちも作っていきたい。

終了条件は

  • マスが全部埋まる
    • 石数の多いほうが勝ち
    • 同数の場合は引き分け
  • それ以外
    • どちらか一色になる
    • どちらもパスする

これでいいみたい。

checkFinish()

void checkFinish (){
    int AllStone = BlackStoneCount + WhiteStoneCount;
    TextView ttv = parentView.findViewWithTag("turn");

    switch(AllStone){
        case(64):
            if(BlackStoneCount > WhiteStoneCount) {
                ttv.setText("黒の勝ちです");
            }else if(BlackStoneCount < WhiteStoneCount) {
                ttv.setText("白の勝ちです");
            }else{
                ttv.setText("引き分けです");
            }
            return;

        default:
             if(BlackStoneCount == 0){
                 ttv.setText("白の勝ちです");
                 return;
             }else if(WhiteStoneCount == 0){
                 ttv.setText("黒の勝ちです");
                 return;
             }

             if(!canPutStone()){
                 PlayerTurn = PlayerTurn * (-1);
                 setTurn();
                 scanBoard();
             }

             if(!canPutStone()){
                 if(BlackStoneCount > WhiteStoneCount) {
                     ttv.setText("黒の勝ちです");
                 }else if(BlackStoneCount < WhiteStoneCount) {
                     ttv.setText("白の勝ちです");
                 }else{
                     ttv.setText("引き分けです");
                 }
             }
    }
}
private boolean canPutStone(){
    String s;

    for(TextView[] cc : CellArray) {
        for (TextView c : cc) {
            s = c.getText().toString();

            if(s.equals("*")){ return true; }
        }
    }
    return false;
}

ちょっと冗長な気もする。上の終了条件を順にコード化しただけ。

最後2ブロックがパスの処理で、canPutStone()で置ける場所があるかの判定を行い、手番を入れ替え、置き石表示を更新し、もう一度置ける場所があるか判断する。これでずっと俺のターン時にも対応できてるはず。

なかなかサクサク行った。ただなんかリバーシ作るの飽きてきたな。

追記

思ったんだけど、マスが全部埋まる場合も、オール一色になる場合も、盤面に「*」は表示されていないわけで。ていうことは、パスと、終了だけでいいのでは…?

つまり

void checkFinish() {
    TextView ttv = parentView.findViewWithTag("turn");

    if (!canPutStone()) {
        PlayerTurn = PlayerTurn * (-1);
        setTurn();
        scanBoard();
    }

    if (!canPutStone()) {
        if (BlackStoneCount > WhiteStoneCount) {
            ttv.setText("黒の勝ちです");
        } else if (BlackStoneCount < WhiteStoneCount) {
            ttv.setText("白の勝ちです");
        } else {
            ttv.setText("引き分けです");
        }
    }
}

こうね。動いたよおい。ちくしょうめ。

参考

http://bassy84.net/othello.rule2.html

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

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

石を置けない場所をタップした時にトーストを出す

考えたこと

すでに石があった場合(○●が表示されていた場合)「そこに石は置けません。」のトーストは出していた。前回置き石可能な場所の表示ができたので、その場所を配列かなんかで持っておいて、タップするごとにその配列の要素をチェックし、それ以外だったらトーストを出す。ってやればいけそうと考えていた。

実際

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

これを

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

こう。

終わり。

アホか俺は。

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

リバーシで8方向の処理をまとめる&置ける場所の表示


いろんなサイトを参考にしつつ、なんとなく頭の中にはできてきたので、サクサクいくかなぁと思ったらそんなことはなく、やたら手間取ってやっとできた。なんか色々あったけど全部は覚えてないのでさらっと書いとく。

8方向の処理をまとめる

CheckFlip**()を分割する

石を置けるかどうかの処理とそれを元に引っ繰り返す処理が一緒になっているので、それを分けた。

checkCanFlip()

public void checkCanFlip(TextView tv){
    int di;
    int taptag = Integer.parseInt(tv.getTag().toString());
    TextView ttv;
    int StoneColor;

    for(int d = 0 ; d <= 7 ; d++){
        di = MoveQuantity[d];

        for(int c = 1 ; c <= 8 ; c ++) {
            ttv = parentView.findViewWithTag(String.format("%02d",taptag + (c * di)));

            if(ttv == null) {
                canFlip[d] = false;
                break;
            }

            if (!existStone(ttv)) {
                canFlip[d] = false;
                break;
            }

            StoneColor = getStoneColor(ttv);

            if (PlayerTurn == StoneColor && StoneCount[d] < 1) {
                canFlip[d] = false;
                break;
            }

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

            if (PlayerTurn == StoneColor) {
                canFlip[d] = true;
                break;
            }
        }
    }
}

http://uguisu.skr.jp/othello/7gyou.html

こちらのサイトがすごく参考になった。ここまできれいには書けないけど、8方向の移動量を配列で持っておくっていうのがすごい。かっこいい。

  • MoveQuantity[]→方向ごとの移動量
  • StoneCount[]→方向ごとのひっくり返せる石の数
  • canFlip[]→方向ごとにひっくり返せるならtrue

としてばーっと8方向チェックする。上記3つはメンバ変数なので次の引っ繰り返す処理でも使える。

上端に来た時、getTag()すると”01″のはずが”1″になったりとint型にした弊害が出たのでString.formatで0埋めした。使い方がよく分かんなかった、特に引数が。のでコピペ。でも怒られる。怒られる内容がよくわかってなかったり。

for文も1方向ずつのコードからほぼ流用できたけど、return, break, continueの使い方がこんがらがり、1回1回ステップインしながら置き換えて確かめていった。大変だった。。。

引っ繰り返す処理を作る

public void FlipStone(TextView tv){
    int di;
    int taptag = Integer.parseInt(tv.getTag().toString());
    TextView ttv;

    for(int d = 0 ; d <= 7 ; d++) {
        di = MoveQuantity[d];

        if(canFlip[d]){
            setStoneToCell(tv);

            for(int c = 1 ; c <= StoneCount[d] ; c++){
                ttv = parentView.findViewWithTag(String.format("%02d",taptag + (c * di)));
                setStoneToCell(ttv);
            }
        }
    }

    canFlip = new boolean[]{false, false, false, false, false, false, false, false};
    StoneCount = new int[]{0,0,0,0,0,0,0,0};
}

上で使った3つの変数を元に、石をひっくり返していく。実際for文で回したり、使ってる変数は同じなんだけど、ここを分けとかないと次の置き石の表示でcheckcanflipを使い回せないと思ったので。最初、処理の最後で配列を初期化してなくて、置くごとにえらい場所に置き石可能の表示が出てた。

置ける場所の表示

この前作ったCellArrayを使ってマスを全部検査していく。思ったんだけど、別にCellArray作んなくても、findViewWithTagで回しても別に良かったんじゃ…。どっちのが楽なんだろ。ていうか最初にちゃんと方針を決めて自分に分かりやすいように作っていってないのが悪いんだろうな。やっぱりあれが必要、とか、これいらなかった、とかが多いので、自分でも把握ができなくなってしまいます。

scanBoard()

この名前の関数はTextView達を配列にぶっこむ関数だったけど、そっちはmakeCellArrayに名前変えて、こっちでこの名前を利用することにした。

public void scanBoard(){

    for(TextView[] cc : CellArray){
        for(TextView c : cc) {
            if(existStone(c)){

            }else{
                checkCanFlip(c);

                for (boolean b : canFlip) {
                    if (b) {
                        c.setText("*");
                        break;
                    } else {
                        c.setText("");
                    }
                }
                canFlip = new boolean[]{false, false, false, false, false, false, false, false};
                StoneCount = new int[]{0, 0, 0, 0, 0, 0, 0, 0};
            }
        }
    }
}

ここに来るまでが長かった。これ作ってる間に、checkcanflipの不具合が見つかったりして、どっちがダメなのか分かんなくなった。置ける場所には「*」を表示することにした。

その前は

c.setBackgroundColor(Color.rgb(150, 255, 170));

こんな感じで色を付けようとしていたんだけど、色を付けると枠線が消えた。

こんな。

枠線はもう完全に理解しないでコピペしてきてるので、直し方も分からず。調べる気も起きず。なので「*」にした。それによって(“”)で判定していた部分、existStone()とか、に支障が出たので、「*」の場合も空白扱いにするようにコード変えた。これは3ヶ所ぐらいだったので助かった。

ここまで

書いた以外にも細かい所でいっぱい引っかかってるんだけど、書くのがめんどい。

あ、あとforとかifがなんだか深くなってしまうな。解消したいけど、そこまで頭が回らない…。

置き石可能かの表示ができたので、こっから「そこには置けません」のトーストと、パス機能に広げられるんじゃないかなと思ってる。やっぱり頭の中で考えるのと、実際書くんじゃ大違いだなぁ。頑張っていっぱい考えたけど、思い通りに動かないこと山の如し、先が思いやられるぞ。でもやっぱ完成させたい気持ちのほうがあるかな。うまくいくといいなぁ。

参考

http://write-remember.com/program/java/format/

https://www.javadrive.jp/start/array/

https://www.javadrive.jp/android/textview/index4.html

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

手番の表示と石数の表示ができた

簡単そうなやつから作ってこーと思い、手番と石数の表示を作ってみた。

手番と石数の表示

手番の表示

サブクラスに親Viewを渡す

今までonClickの時に子Viewを渡して、先の関数内で親Viewを取得してたけど、それ以外でも使えると便利そうだなーと考え調べてみたら、onCreateでサブクラスをnewする前にfindViewByIdで取得しといて、それを渡せばいいみたい。

ので、onCreateで

GridLayout glv = findViewById(R.id.gridLayout1);
board = new Board(context, glv);

と変更し、Boardクラスのコンストラクタを

public Board(Context context, View v){

    this.con = context;
    parentView = v;

と変更したら、parentViewがどっからでも使えるようになった。やったね。

setTurn()

<TextView
    android:id="@+id/textViewTurn"
    android:layout_height="10dp"
    android:layout_row="8"
    android:layout_rowWeight="1"
    android:layout_column="0"
    android:layout_columnSpan="8"
    android:layout_columnWeight="1"
    android:layout_gravity="fill"
    android:layout_marginTop="10dp"
    android:background="@drawable/tv_border"
    android:gravity="center"
    android:tag="turn"
    android:text="黒番です"
    app:autoSizeTextType="uniform" />
public void setTurn(){
    TextView tv = parentView.findViewWithTag("turn");

    switch(PlayerTurn){
        case(BLACK):
            tv.setText("黒番です");
            break;
        case(WHITE):
            tv.setText("白番です");
            break;
    }
}

GridLayoutの行数を変更してから、xmlにTextViewを追加。

あとはtagから引っ張ってきてあげて、PlayerTurnの値ごとにSwitchする。やっぱ簡単だった。

石数の表示

石数を表示するためには、全部のマスを調べて黒白の数を数えてけばいい。そんで合計を表示すればいい。はず。新たに石数表示用のTextViewを作っておいてる。

マス目を配列にぶっこむ

最初一つの関数で完結させようと思ったけど、TextViewの配列を持っとけば後々便利そうと思ったので、ちょっと分けてみた。

メンバ変数

TextView[][] CellArray;

コンストラクタ

CellArray = new TextView[8][8];
scanBoard();

scanBoard()

private void scanBoard () {
    for(int r = 0 ; r <= 7  ; r++){
        for(int c = 0 ; c <= 7 ;  c++){
            CellArray[r][c] = getTextViewFromTag(r, c);
        }
    }
}

前作ったgetTextViewFromTag()が役に立った。

配列で勘違いしてた。配列の要素数は1始まりだけど、インデックスは0始まりなのね。最初に要素数7で初期化してて、IndexOutOfBoundsExceptionつって強制終了してた。

ていうか、すっごい回りくどい気がする。なんだろうこれは、合ってるんだろうか。

石を数える

public void StoneCountOnBoard(){
    BlackStoneCount = 0;
    WhiteStoneCount = 0;
    int color;
    TextView btv = parentView.findViewById(R.id.textViewBlackStone);
    TextView wtv = parentView.findViewById(R.id.textViewWhiteStone);

    for(TextView[] cc : CellArray){
        for(TextView c : cc){
            color = getStoneColor(c);
            switch(color) {
                case (BLACK):
                    BlackStoneCount++;
                    break;
                case(WHITE):
                    WhiteStoneCount++;
                    break;
            }
        }
    }

    btv.setText(String.valueOf(BlackStoneCount)+"個");
    wtv.setText(String.valueOf(WhiteStoneCount)+"個");
}

拡張for文というものを初めて使った。最初、2次元配列の際、入れ子にするのを知らなくて、cc.getText()ってやってもできなくて悩んだ。入れ子にするのと、前作ったgetStoneColor()使えばいんじゃんって気づいたのでこんな感じになった。

うーん

コードがごちゃごちゃして見辛い。8方向まとめるほうが先かなぁ。

参考

http://java-lab.com/array-multidimensional-enhanced_for/

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

Androidアプリ リバーシのソース (Board.java)

package net.dalomo.reversi;

import android.content.Context;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

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

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

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

    private Integer SplitStrRCtoIntRow (String s){
        int r;
        r = Integer.parseInt(s.substring(0,1));
        return r;
    }

    private Integer SplitStrRCtoIntColumn (String s){
        int c;
        c = Integer.parseInt(s.substring(1));
        return c;
    }

    private String TagToString(TextView v){
        String s;
        s = v.getTag().toString();
        return s;
    }

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

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

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

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

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

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

            if(tv == null) return;

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

            StoneColor = getStoneColor(tv);

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

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

            if(PlayerTurn == StoneColor){

                setStoneToCell(v);

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

                break;
            }
         }
    }

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

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

            if(tv == null) return;

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

            StoneColor = getStoneColor(tv);

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

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

            if(PlayerTurn == StoneColor){

                setStoneToCell(v);

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

                break;
            }
        }
    }

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

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

            if(tv == null) return;

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

            StoneColor = getStoneColor(tv);

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

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

            if(PlayerTurn == StoneColor){

                setStoneToCell(v);

                for(int j = (ri - 1) ; (ri - StoneCount - 1) < j ; j--){
                    tv = getTextViewFromTag(r,j);
                    setStoneToCell(tv);
                }

                break;
            }
        }
    }

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

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

            if(tv == null) return;

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

            StoneColor = getStoneColor(tv);

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

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

            if(PlayerTurn == StoneColor){

                setStoneToCell(v);

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

                break;
            }
        }
    }

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

        for(int urr = (r - 1),urc = (c + 1) ; -1 < urr || urc < 8 ; urr--, urc++){
            tv = getTextViewFromTag(urr, urc);

            if(tv == null) return;

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

            StoneColor = getStoneColor(tv);

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

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

            if (PlayerTurn == StoneColor) {

                setStoneToCell(v);

                for (int inurr = (urr + 1),inurc = (urc - 1 ) ; (urr + StoneCount + 1) > inurr || (urc - StoneCount - 1) < inurc; inurr++, inurc--) {
                        tv = getTextViewFromTag(inurr, inurc);
                        setStoneToCell(tv);
                }

                break;
            }
        }
    }

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

        for(int drr = (r + 1),drc = (c + 1) ; drr < 8 || drc < 8 ; drr++ , drc++){
            tv = getTextViewFromTag(drr, drc);

            if(tv == null) return;

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

            StoneColor = getStoneColor(tv);

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

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

            if (PlayerTurn == StoneColor) {

                setStoneToCell(v);

                for (int indrr = (drr - 1),indrc = (drc - 1 ) ; (drr - StoneCount - 1) < indrr || (drc - StoneCount - 1) < indrc; indrr--, indrc--) {
                    tv = getTextViewFromTag(indrr, indrc);
                    setStoneToCell(tv);
                }

                break;
            }
        }
    }

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

        for(int dlr = (r + 1),dlc = (c - 1) ; dlr < 8 || -1 < dlc ; dlr++ , dlc--){
            tv = getTextViewFromTag(dlr, dlc);

            if(tv == null) return;

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

            StoneColor = getStoneColor(tv);

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

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

            if (PlayerTurn == StoneColor) {

                setStoneToCell(v);

                for (int indlr = (dlr - 1),indlc = (dlc + 1 ) ; (dlr - StoneCount - 1) < indlr || (dlc + StoneCount + 1) > indlc; indlr--, indlc++) {
                    tv = getTextViewFromTag(indlr, indlc);
                    setStoneToCell(tv);
                }

                break;
            }
        }
    }

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

        for(int ulr = (r - 1), ulc = (c - 1) ; -1 <ulr || -1 < ulc ; ulr-- , ulc--){
            tv = getTextViewFromTag(ulr, ulc);

            if(tv == null) return;

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

            StoneColor = getStoneColor(tv);

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

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

            if (PlayerTurn == StoneColor) {

                setStoneToCell(v);

                for (int inulr = (ulr + 1),inulc = (ulc + 1 ) ; (ulr + StoneCount + 1) > inulr || (ulc + StoneCount + 1) > inulc; inulr++, inulc++) {
                    tv = getTextViewFromTag(inulr, inulc);
                    setStoneToCell(tv);
                }

                break;
            }
        }
    }

    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;
        }

        CheckFlipUP(tv,Row,Column);
        CheckFlipDOWN(tv,Row,Column);
        CheckFlipRIGHT(tv,Row,Column);
        CheckFlipLEFT(tv,Row,Column);
        CheckFlipUPRIGHT(tv,Row,Column);
        CheckFlipDOWNRIGHT(tv,Row,Column);
        CheckFlipDOWNLEFT(tv,Row,Column);
        CheckFlipUPLEFT(tv,Row,Column);

        stone = tv.getText().toString();
        if(!stone.equals("")) {
            PlayerTurn = PlayerTurn * (-1);
        }
    }
}
カテゴリー: のーと | タグ: , , , | コメントする

Androidアプリ リバーシのソース (Reversi.java)

package net.dalomo.reversi;

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

public class Reversi extends AppCompatActivity {
    Board board;

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

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

    public void onClick(View view) {
        int id = view.getId();

        switch(id) {
            case R.id.textView00:
            case R.id.textView01:
            case R.id.textView02:
            case R.id.textView03:
            case R.id.textView04:
            case R.id.textView05:
            case R.id.textView06:
            case R.id.textView07:
            case R.id.textView10:
            case R.id.textView11:
            case R.id.textView12:
            case R.id.textView13:
            case R.id.textView14:
            case R.id.textView15:
            case R.id.textView16:
            case R.id.textView17:
            case R.id.textView20:
            case R.id.textView21:
            case R.id.textView22:
            case R.id.textView23:
            case R.id.textView24:
            case R.id.textView25:
            case R.id.textView26:
            case R.id.textView27:
            case R.id.textView30:
            case R.id.textView31:
            case R.id.textView32:
            case R.id.textView33:
            case R.id.textView34:
            case R.id.textView35:
            case R.id.textView36:
            case R.id.textView37:
            case R.id.textView40:
            case R.id.textView41:
            case R.id.textView42:
            case R.id.textView43:
            case R.id.textView44:
            case R.id.textView45:
            case R.id.textView46:
            case R.id.textView47:
            case R.id.textView50:
            case R.id.textView51:
            case R.id.textView52:
            case R.id.textView53:
            case R.id.textView54:
            case R.id.textView55:
            case R.id.textView56:
            case R.id.textView57:
            case R.id.textView60:
            case R.id.textView61:
            case R.id.textView62:
            case R.id.textView63:
            case R.id.textView64:
            case R.id.textView65:
            case R.id.textView66:
            case R.id.textView67:
            case R.id.textView70:
            case R.id.textView71:
            case R.id.textView72:
            case R.id.textView73:
            case R.id.textView74:
            case R.id.textView75:
            case R.id.textView76:
            case R.id.textView77:

                TextView tv = findViewById(id);
                board.putStone(tv);
                break;
        }
    }
}
カテゴリー: のーと | タグ: , , , | コメントする

Androidアプリ リバーシのソース (activity_reversi.xml)

<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/gridLayout1"
    android:layout_width="match_parent"
    android:layout_height="400dp"
    android:layout_weight="1"
    android:columnCount="8"
    android:rowCount="8">


    <TextView
        android:id="@+id/textView00"
        android:layout_width="10dp"
        android:layout_height="10dp"
        android:layout_row="0"
        android:layout_rowWeight="1"
        android:layout_column="0"
        android:layout_columnWeight="1"
        android:layout_gravity="fill"
        android:background="@drawable/tv_border"
        android:clickable="true"
        android:focusable="true"
        android:gravity="center"
        android:text=""
        app:autoSizeTextType="uniform"
        android:onClick="onClick"
        android:tag="00"/>

//数字を変えて、あと63個続く。

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

AndroidStudioでリバーシできた

基本はできた

懸念していた盤端にかかった時のエラーも解消され基本的な部分は完成したと思う。

  • 動いてるとこ

  • apkファイル

https://apk.dalomo.net/Reversi.apk

  • ソース

https://dalomo.net/blog/2018/11/17/149/

https://dalomo.net/blog/2018/11/17/151/

https://dalomo.net/blog/2018/11/17/153/

エラーの原因

デバッグでステップインして調べていったら、やっぱり盤外のTextViewを取得しようとして落ちてた。ということで、取得できなかった時の処理を追加してあげる。

findViewWithTagで取得できない時の戻り値

if(tv == null) return;

はnullです!8方向全ての関数に上記コードを追加した。そしたら無事、端の行列でもエラーは発生せず、ちゃんと動いてくれました。

これが有名な「ぬるぽ」のnullかー。ガッ!ガッ!

機能追加したい

できたはできたのだけど、これで遊ぶにはちょっと物足りなさが残る。こんな機能がついてたらいいな、というのが結構あるので書いてみる。大体のリバーシには付いてるんだろうけどね。

着手の可否

一人で二役のゲームをしているので、手番がこんがらがって誤タップしたりする。なので着手できない所をタップした時、「そこに置けません」を出したい。もしくは、「現状で石が置ける場所」を何らかの方法で表現したい。

手番の表示

上記に関連してるけど、あれ?今どっちだっけ?ってよく考える。なので、現在の手番を表示させておきたい。PlayerTurnを変数で設定してたので、簡単なはず。

現在の石数の表示

今どっちが勝ってんだかが全然わからないのでこれも表示させたい。あとゲーム終わった時に手作業で石数えるのがめんどい。終わったら整地とかできるとかっこよさそう。作り方わからんけど。

勝利判定

そもそもどっちが勝ったか判定すりゃいいんだよな。ただ、石が置けなくなったら、なのか、盤面が全部埋まったら、なのか置いてある石が全部片方の色になったら、なのか。その判定が難しそう。

パス機能

片方は置けるけど、片方は置けないって状況は終盤結構発生する。だけど今は、そこで物理的にゲームが終わってしまう。本家ルールだとパスはいくらでもしていいそうなので、パスが実装できればいいなと。上記の勝利判定と絡みそうだからやっぱり追加するの難しそうだな。

時間経過

囲碁・将棋・チェスってチェスクロック方式の対局時計があるので、それも表現したい。なんかかっこいいよね。あ、だと設定画面とかも作らなきゃなのかな。そういえば文字の逆立ちってできるのかな。隣同士で一つの画面見ながらいちゃいちゃするのもいいけど、やっぱ向かい合ってできるようにするのがいいよね。

COM戦を作りたい

俺には無理だ…って思ってたけど、例えば石が置けるとこが見つかったら置く。みたいな単純なCOMだったら俺にも作れないかな。ちょっと欲が出てきた。できるかな。どうだろ。書くだけはタダだし、書いとこ!

コード改善

8方向への探査の所、やっぱりもうちょっとなんとかなんないかなと思う。とりあえず完成させることを優先にしたので、似たような処理がこんもりだし、あそこの部分だけ長いので見辛いし。なんか良い考え方見つかんないかなー。

わくわく

楽しみ

参考

https://developer.android.com/reference/android/view/View.html#findViewWithTag(java.lang.Object)

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

斜めできた+問題発生

斜めできた。眠い。

斜め

右上

for(int urr = (r - 1),urc = (c + 1) ; -1 < urr || urc < 8 ; urr--, urc++){
    tv = getTextViewFromTag(urr, urc);
for (int inurr = (urr + 1),inurc = (urc - 1 ) ; (urr + StoneCount + 1) > inurr || (urc - StoneCount - 1) < inurc; inurr++, inurc--) {
        tv = getTextViewFromTag(inurr, inurc);

右下

for(int drr = (r + 1),drc = (c + 1) ; drr < 8 || drc < 8 ; drr++ , drc++){
    tv = getTextViewFromTag(drr, drc);
for (int indrr = (drr - 1),indrc = (drc - 1 ) ; (drr - StoneCount - 1) < indrr || (drc - StoneCount - 1) < indrc; indrr--, indrc--) {
    tv = getTextViewFromTag(indrr, indrc);

左下

for(int dlr = (r + 1),dlc = (c - 1) ; dlr < 8 || -1 < dlc ; dlr++ , dlc--){
    tv = getTextViewFromTag(dlr, dlc);
for (int indlr = (dlr - 1),indlc = (dlc + 1 ) ; (dlr - StoneCount - 1) < indlr || (dlc + StoneCount + 1) > indlc; indlr--, indlc++) {
    tv = getTextViewFromTag(indlr, indlc);

左上

for(int ulr = (r - 1), ulc = (c - 1) ; -1 <ulr || -1 < ulc ; ulr-- , ulc--){
    tv = getTextViewFromTag(ulr, ulc);
for (int inulr = (ulr + 1),inulc = (ulc + 1 ) ; (ulr + StoneCount + 1) > inulr || (ulc + StoneCount + 1) > inulc; inulr++, inulc++) {
    tv = getTextViewFromTag(inulr, inulc);

見てわかるように引っ繰り返す部分のfor文が長い。見栄え悪いな。やだな。

for文って変数2つ以上使えるんだね。初めて知った。条件式も論理演算子使えばいいと分かったし、発見が多いなぁ。

問題点

てっきり、これで完成~!と思って遊んでみたのだけれど、端っこに石を置こうとしたら強制終了してしまった。おそらくTextViewが無いのにfindviewwithtagで取得しようとしてしまって、エラーになってしまっているんだと思う。だから番兵って必要なのか。いや確かめたわけじゃないんだけど。取得できなかったときの処理を入れれば大丈夫かなぁ。大丈夫だといいなぁ。

参考

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

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