ボーリングスコア計算プログラム

Mobster Partyでボーリングスコア計 算のプログラムを作ると言うテーマがありました。当日は、子供が通う幼稚園 の夕涼み会とぶつかってしまい、残念ながら参加できませんでした。

開催日の3日前、会社からの帰りの電車の中、ソースコードだけでも参加させ てやれ、とふと思い立って電車の中で10分間モデリングし、帰宅して速攻1時 間でソースコードを書きました。 テストしていたらバグがいくつか見つかり、30分かけてデバッグしました が10フレーム目のスコア計算を間違うバグの修正が完了せず、腹も減ったので 翌日に持ち越し、15分のデバッグで一応完了させました。 そのときのソースコードをここに掲載します。

電車内でのモデリングの際に、まずスコアの計算方法に着目しました。 (スコア計算のプログラムだから当然ですが) あるフレームまでの合計スコアは以下の式で求めることができます。

あるフレームまでの合計スコア=前のフレームまでの合計スコア
                            +そのフレームで倒したピン数
                            +ボーナスポイント(*)

* ストライクの場合は直後の2投で倒したピン数
  スペアの場合は直後の1投で倒したピン数

つまり、「前のフレーム」と「直後のn投」というキーワードをヒントにする と、フレームをリンクリストにするのがよさそうです。

というわけで、モデリングのポイントは Frame クラスをリンクリスト形式に してスコア計算に使った点と、スコアが計算できないところはすべて例外をあ げるようにした点です。

作ったクラスは以下の4つ。

クラス名概要
Bowling ボーリングスコア計算のモデルを動作させ、コンソールに計算結果を 出力するメインプログラム。
ScoreTable 1フレーム目から10フレーム目までをひとまとめにしたクラス。
Frame 1フレーム目から9フレーム目までに対応するクラス。
EndFrame 10フレーム目に対応するクラス。

さて、以下、そのソースコードです。 コメントもほどんど書いてないし、 リファクタリングもしていないので読みにくくて申し訳ない。

こんなソースでも欲しいという方は ここをクリックしてダウンロード してください。コンパイル済みの class ファイルも含んでいます。

起動はコマンドプロンプトからです。起動すると「input new point: 」と、 倒したピン数の入力を要求します。

D:\java\bowling> java -cp . Bowling
input new point: 
これに続いて倒したピン数を入力するとコンソールにスコア表を出力し、 次のポイントをたずねます。どうぞ、お試しください。

このような感じで動作します。


Frame.java

public class Frame {
    int point[];
    Frame prev;
    Frame next;
    protected static String MSG = "point unknown";

    public Frame(){
        point = new int[2];
        point[0] = -1;
        point[1] = -1;
        prev = null;
        next = null;
    }

    public void setPrevFrame(Frame f){
        prev = f;
    }

    public void setNextFrame(Frame f){
        next = f;
    }

    public void addPoint(int p){
        if(p < 0 || p > 10){
            throw new RuntimeException("range is 0 to 10");
        }
        if(point[0] < 0){
            point[0] = p;
        }else{
            if(point[0] + p > 10){
                throw new RuntimeException("range is 0 to " + (10 - point[0]));
            }
            point[1] = p;
        }
    }

    public void setPoint(int i, int p){
        point[i] = p;
    }

    public boolean isFilled(){
        if(point[0] == 10){
            return true;
        }
        return point[1] >= 0;
    }

    public int getStrikePoint(){
        int p = point[0];
        whenMinusThrowException(p);
        if(p == 10){
            if(next == null){
                throw new RuntimeException(MSG);
            }
            p += next.getFirstPoint();
        }else{
            whenMinusThrowException(point[1]);
            p += point[1];
        }
        return p;
    }

    public int getFirstPoint(){
        whenMinusThrowException(point[0]);
        return point[0];
    }

    public int getSecondPoint(){
        whenMinusThrowException(point[1]);
        return point[1];
    }

    public int getFramePoint(){
        if(!isFilled()){
            throw new RuntimeException(MSG);
        }
        if(point[0] == 10){
            return point[0];
        }
        return point[0] + point[1];
    }

    public int getTotal(){
        int total = 0;
        int fp = getFramePoint();
        if(prev != null){
            total = fp + prev.getTotal();
        }else{
            total += fp;
        }
        if(next != null){
            if(point[0] == 10){
                return total + next.getStrikePoint();
            }
            if(fp == 10){
                return total + next.getFirstPoint();
            }
            return total;
        }
        throw new RuntimeException("Internal Error");
    }

    protected void whenMinusThrowException(int p){
        if(p < 0){
            throw new RuntimeException(MSG);
        }
    }
}

EndFrame.java

public class EndFrame extends Frame {
    public EndFrame(){
        point = new int[3];
        point[0] = -1;
        point[1] = -1;
        point[2] = -1;
    }

    public void setPoint(int i, int p){
        point[i] = p;
    }

    public void addPoint(int p){
        if(p < 0 || p > 10){
            throw new RuntimeException("range is 0 to 10");
        }
        if(point[0] < 0){
            point[0] = p;
            return;
        }
        if(point[1] < 0){
            if(point[0] < 10 && point[0] + p > 10){
                throw new RuntimeException();
            }
            point[1] = p;
            return;
        }
        point[2] = p;
    }

    public boolean isFilled(){
        if(point[1] < 0){
            return false;
        }
        if(point[0] == 10 && point[2] < 0){
            return false;
        }
        if(point[0] + point[1] < 10){
            return true;
        }
        return point[2] >= 0;
    }

    public int getStrikePoint(){
        whenMinusThrowException(point[0]);
        whenMinusThrowException(point[1]);
        return point[0] + point[1];
    }

    public int getFirstPoint(){
        whenMinusThrowException(point[0]);
        return point[0];
    }

    public int getSecondPoint(){
        whenMinusThrowException(point[1]);
        return point[1];
    }

    public int getThirdPoint(){
        whenMinusThrowException(point[2]);
        return point[2];
    }

    public int getFramePoint(){
        if(!isFilled()){
            throw new RuntimeException(MSG);
        }
        int p = point[0] + point[1];
        if(point[2] >= 0){
            p += point[2];
        }
        return p;
    }

    public int getTotal(){
        int fp = getFramePoint();
        if(prev == null){
            return fp;
        }
        return fp + prev.getTotal();
    }
}

ScoreTable.java

public class ScoreTable {
    private Frame frames[];

    public ScoreTable(){
        frames = new Frame[10];
        Frame prev = null;
        for(int i = 0; i < 10; i++){
            if(i != 9){
                frames[i] = new Frame();
            }else{
                frames[i] = new EndFrame();
            }
            frames[i].setPrevFrame(prev);
            if(prev != null){
                prev.setNextFrame(frames[i]);
            }
            prev = frames[i];
        }
    }

    public Frame getFrame(int i){
        return frames[i];
    }

    public boolean isGameOver(){
        return frames[9].isFilled();
    }
}

Bowling.java

import java.io.*;

public class Bowling {
    private ScoreTable scoreTable;

    public static void main(String args[]){
        Bowling b = new Bowling();
        b.doGame();
    }

    public Bowling(){
        scoreTable = new ScoreTable();
    }

    public void doGame(){
        int no = 0;
        while(!scoreTable.isGameOver()){
            int p = getNewPoint();
            Frame frame = scoreTable.getFrame(no);
            try{
                frame.addPoint(p);
            }catch(Exception e){
                e.printStackTrace();
                continue;
            }
            if(frame.isFilled()){
                no++;
            }
            printScoreTable();
        }
    }

    public void printScoreTable(){
        // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        // | | | | | | | | | | | | | | | | | | | | | |
        // | +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+-+-+-+
        // |   |   |   |   |   |   |   |   |   |     |
        // +---+---+---+---+---+---+---+---+---+-----+
        System.out.println("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
        printUpperRow();
        System.out.println("+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+-+-+-+");
        printLowerRow();
        System.out.println("+---+---+---+---+---+---+---+---+---+-----+");
    }

    private void printUpperRow(){
        System.out.print("|");
        for(int i = 0; i < 10; i++){
            Frame frame = scoreTable.getFrame(i);
            int p;
            try{
                p = frame.getFirstPoint();
                if(p == 10){
                    if(frame instanceof EndFrame){
                        System.out.print("x");
                    }else{
                        System.out.print(" |x|");
                        continue;
                    }
                }else{
                    System.out.print(p);
                }
            }catch(Exception e){
                System.out.print(" ");
            }
            System.out.print("|");
            try{
                p = frame.getSecondPoint();
                if(frame instanceof EndFrame){
                    if(p == 10){
                        System.out.print("x");
                    }else
                    if(p + frame.getFirstPoint() == 10){
                        System.out.print("/");
                    }else{
                        System.out.print(p);
                    }
                }else{
                    if(frame.getFramePoint() == 10){
                        System.out.print("/");
                    }else{
                        System.out.print(p);
                    }
                }
            }catch(Exception e){
                System.out.print(" ");
            }
            System.out.print("|");
            if(frame instanceof EndFrame){
                try{
                    p = ((EndFrame)frame).getThirdPoint();
                    if(p == 10){
                        System.out.print("x");
                    }else{
                        System.out.print(p);
                    }
                }catch(Exception e){
                    System.out.print(" ");
                }
                System.out.print("|");
            }
        }
        System.out.println();
    }

    private void printLowerRow(){
        System.out.print("|");
        for(int i = 0; i < 10; i++){
            Frame frame = scoreTable.getFrame(i);
            if(frame instanceof EndFrame){
                try{
                    int total = frame.getTotal();
                    if(total < 10){
                        System.out.print("    " + total);
                    }else
                    if(total < 100){
                        System.out.print("   " + total);
                    }else{
                        System.out.print("  " + total);
                    }
                }catch(Exception e){
                    System.out.print("     ");
                }
            }else{
                try{
                    int total = frame.getTotal();
                    if(total < 10){
                        System.out.print("  " + total);
                    }else
                    if(total < 100){
                        System.out.print(" " + total);
                    }else{
                        System.out.print(total);
                    }
                }catch(Exception e){
                    System.out.print("   ");
                }
            }
            System.out.print("|");
        }
        System.out.println();
    }

    public int getNewPoint(){
        int p = 0;
        try{
            System.out.print("input new point: ");
            System.out.flush();
            BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
            String s = r.readLine();
            p = Integer.parseInt(s);
        }catch(Exception e){}
        return p;
    }
}

     デル株式会社




HOME お勧め書籍 / Profile / リンク