0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

第13回オフラインリアルタイムどう書くをJavaで

Last updated at Posted at 2013-09-14

積み木の水槽 〜 横へな 2013.9.6

めっちゃ時間かかった。自分才能なさすぎ。コード量多すぎ。

ロジックは以下。

  1. インプットの情報で積み木の水槽を作る
  2. とりあえず全部水で満たす
  3. 右左下のいずれかに移動できる水を削除

3番目のステップを、削除できる水が無くなるまで繰り返す。

実装

起動用クラス

BlockTank.java
package hoge;

import java.util.ArrayList;
import java.util.List;

public class BlockTank {
    
    public static void main(String[] args) {
        new BlockTank().execute(args[0]);
    }

    public void execute(String arg) {
        // 引数解析
        List<Integer> design = new ArrayList<>();
        for (int i=0; i<arg.length(); i++) {
            design.add(Integer.valueOf(arg.substring(i, i+1)));
        }
        
        Field field = new Field(design);
        field.spillWater();
        int amount = field.getAmountOfWater();
        
        // 結果表示
        System.out.println(field);
        System.out.println(amount);
    }
}

積み木を置くフィールド

Field.java
package hoge;

import static hoge.Cell.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Field {

    private int LEFT_EDGE = 0;
    private int RIGHT_EDGE;
    private int BOTTOM_EDGE = 0;
    
    private Cell[][] field;
    private int width;
    private int height;
    
    public Field(List<Integer> design) {
        this.initMatrix(design);
        this.fillWater();
        this.putBlocks(design);
    }
    
    private void initMatrix(List<Integer> design) {
        width = design.size();
        height = Collections.max(design);
        
        field = new Cell[width][height];
        
        RIGHT_EDGE = width - 1;
    }
    
    private void fillWater() {
        for (Cell[] column : field) {
            Arrays.fill(column, WATER);
        }
    }
    
    private void putBlocks(List<Integer> design) {
        for (int x=0; x<design.size(); x++) {
            int wallHeight = design.get(x);
            
            for (int y=0; y<wallHeight; y++) {
                field[x][y] = BLOCK;
            }
        }
    }
    
    public void spillWater() {
        boolean remove;
        
        do {
            remove = forEachFieldCell(new CallBack<Boolean>() {
                private boolean remove;
                
                @Override public void visit(int x, int y, Cell cell) {
                    if (cell == WATER) {
                        if (isEdge(x, y) || existsBlankAround(x, y)) {
                            field[x][y] = BLANK;
                            remove = true;
                        }
                    }
                }
                
                @Override public Boolean result() {
                    return remove;
                }
            });
        } while(remove);
    }
    
    private boolean existsBlankAround(int x, int y) {
        Cell left   = field[x-1][y];
        Cell right  = field[x+1][y];
        Cell bottom = field[x][y-1];
        
        return left == BLANK || right == BLANK || bottom == BLANK;
    }

    private boolean isEdge(int x, int y) {
        return x == LEFT_EDGE || x == RIGHT_EDGE || y == BOTTOM_EDGE;
    }
    
    public int getAmountOfWater() {
        return forEachFieldCell(new CallBack<Integer>() {
            private int amount = 0;
            
            @Override public void visit(int x, int y, Cell cell) {
                if (cell == WATER) {
                    amount++;
                }
            }
            
            @Override public Integer result() {
                return amount;
            }
        });
    }

    private <R> R forEachFieldCell(CallBack<R> callback) {
        for (int x=0; x<width; x++) {
            for (int y=0; y<height; y++) {
                callback.visit(x, y, field[x][y]);
            }
        }
        
        return callback.result();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int y=height-1; 0<=y; y--) {
            for (int x=0; x<width; x++) {
                sb.append(field[x][y]);
            }
            if (y != 0) {
                sb.append(System.getProperty("line.separator"));
            }
        }
        return sb.toString();
    }
    
    private static interface CallBack<R> {
        void visit(int x, int y, Cell cell);
        R result();
    }
}

フィールドに置けるもの

Cell.java
package hoge;

public enum Cell {
    BLANK(" "),
    BLOCK("■"),
    WATER("水"),
    ;
    
    private String value;
    private Cell(String value) {
        this.value = value;
    }
    @Override
    public String toString() {
        return this.value;
    }
}

JUnit

BlockTankTest.java
package hoge;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import hoge.BlockTank;
import java.io.PrintStream;
import org.junit.Before;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;

@RunWith(Theories.class)
public class BlockTankTest {
    
    @DataPoints
    public static Fixture[] fixtures = {
        new Fixture() {{
            input = "83141310145169154671122";
            expected = 24;
        }},
        new Fixture() {{
            input = "923111128";
            expected = 45;
        }},
        new Fixture() {{
            input = "923101128";
            expected = 1;
        }},
        new Fixture() {{
            input = "903111128";
            expected = 9;
        }},
        new Fixture() {{
            input = "3";
            expected = 0;
        }},
        new Fixture() {{
            input = "31";
            expected = 0;
        }},
        new Fixture() {{
            input = "412";
            expected = 1;
        }},
        new Fixture() {{
            input = "3124";
            expected = 3;
        }},
        new Fixture() {{
            input = "11111";
            expected = 0;
        }},
        new Fixture() {{
            input = "222111";
            expected = 0;
        }},
        new Fixture() {{
            input = "335544";
            expected = 0;
        }},
        new Fixture() {{
            input = "1223455321";
            expected = 0;
        }},
        new Fixture() {{
            input = "000";
            expected = 0;
        }},
        new Fixture() {{
            input = "000100020003121";
            expected = 1;
        }},
        new Fixture() {{
            input = "1213141516171819181716151413121";
            expected = 56;
        }},
        new Fixture() {{
            input = "712131415161718191817161514131216";
            expected = 117;
        }},
        new Fixture() {{
            input = "712131405161718191817161514031216";
            expected = 64;
        }},
        new Fixture() {{
            input = "03205301204342100";
            expected = 1;
        }},
        new Fixture() {{
            input = "0912830485711120342";
            expected = 18;
        }},
        new Fixture() {{
            input = "1113241120998943327631001";
            expected = 20;
        }},
        new Fixture() {{
            input = "7688167781598943035023813337019904732";
            expected = 41;
        }},
        new Fixture() {{
            input = "2032075902729233234129146823006063388";
            expected = 79;
        }},
        new Fixture() {{
            input = "8323636570846582397534533";
            expected = 44;
        }},
        new Fixture() {{
            input = "2142555257761672319599209190604843";
            expected = 41;
        }},
        new Fixture() {{
            input = "06424633785085474133925235";
            expected = 51;
        }},
        new Fixture() {{
            input = "503144400846933212134";
            expected = 21;
        }},
        new Fixture() {{
            input = "1204706243676306476295999864";
            expected = 21;
        }},
        new Fixture() {{
            input = "050527640248767717738306306596466224";
            expected = 29;
        }},
        new Fixture() {{
            input = "5926294098216193922825";
            expected = 65;
        }},
        new Fixture() {{
            input = "655589141599534035";
            expected = 29;
        }},
        new Fixture() {{
            input = "7411279689677738";
            expected = 34;
        }},
        new Fixture() {{
            input = "268131111165754619136819109839402";
            expected = 102;
        }},
    };
    
    @Before
    public void setup() {
        System.setOut(new PrintStream(System.out) {
            @Override
            public void println(int i) {
                actual = i;
                System.out.println("amount of water = " + i);
            }
        });
    }
    
    private int actual;
    
    @Theory
    public void test(Fixture fixture) {
        System.out.println("input = " + fixture.input);
        
        // exercise
        new BlockTank().execute(fixture.input);
        
        // verify
        assertThat(fixture.input, actual, is(fixture.expected));
        
        System.out.println();
    }
    
    private static class Fixture {
        public String input;
        public int expected;
    }
}

単純なコールバック関数が欲しいときに Java の限界を感じた。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?