ローリングコインタワー

f:id:qnighy:20091210231617p:image

テレビでやってたやつ。
円柱状の物体、というか所謂コインを積んでいって、倒したら負けというゲーム。

あのゲームの、現時点での置ける範囲を計算するシミュレーションを作ってみた。

A simulation program for "Coin Tower", a coin-stacking game. — Gist

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;

public class CoinTower extends JFrame {
    private ArrayList<Coin> tower;
    public CoinTower() {
        super("Rolling Coin Tower Demo");
        tower = new ArrayList<Coin>();

        setSize(800,600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        getContentPane().add(panel = new MyPanel());
        setVisible(true);
    }
    private class Coin {
        private double w;
        private double x;
        private double y;
        private double r;
        public Coin(double w, double x, double y, double r) {
            this.w=w;this.x=x;this.y=y;this.r=r;
        }
    }
    private MyPanel panel;
    private class MyPanel extends JPanel implements MouseListener {
        private MyPanel() {
            super(true);
            addMouseListener(this);
        }
        @Override
        public void paint(Graphics g_) {
            Graphics2D g = (Graphics2D)g_;
            for(int i = 0; i < tower.size(); i++) {
                Coin c = tower.get(i);
                Arc2D arc = new Arc2D.Double(c.x-c.r, c.y-c.r, c.r*2, c.r*2, 0, 360, Arc2D.CHORD);
                g.setColor(Color.WHITE);
                g.fill(arc);
                g.setColor(Color.BLACK);
                g.draw(arc);
            }
            int ws=0, xs=0, ys=0;
            int nw=10;
            Area area = null;
            for(int i = tower.size()-1; i >= 0; i--) {
                Coin c = tower.get(i);
                // ( (xs+nx*nw) / (ws+nw) - c.x ) ^2 + ( (ys+ny*nw) / (ws+nw) - c.y ) ^2 < c.r^2
                // ( (xs+nx*nw) - c.x * (ws+nw) ) ^2 + ( (ys+ny*nw) - c.y * (ws+nw) ) ^2 < (c.r*(ws+nw))^2
                // ( nx*nw - (c.x*(ws+nw)-xs) ) ^2 + ( ny*nw - (c.y*(ws+nw)-ys) ) ^2 < (c.r*(ws+nw))^2
                // ( nx - (c.x*(ws+nw)-xs)/nw ) ^2 + ( ny - (c.y*(ws+nw)-ys)/nw ) ^2 < (c.r*(ws+nw)/nw)^2
                double nxc=(c.x*(ws+nw)-xs)/nw;
                double nyc=(c.y*(ws+nw)-ys)/nw;
                double nr=c.r*(ws+nw)/nw;
                System.out.println("("+nxc+","+nyc+")->"+nr);
                Arc2D arc = new Arc2D.Double(nxc-nr, nyc-nr, nr*2, nr*2, 0, 360, Arc2D.CHORD);
                Area carea = new Area(arc);
                if(area == null) {
                    area = carea;
                } else {
                    area.intersect(carea);
                }
                ws += c.w;
                xs += c.w*c.x;
                ys += c.w*c.y;
            }
            if(area != null) {
                Path2D path = new Path2D.Double();
                path.append(area.getPathIterator(null), false);
                g.setColor(new Color(255,0,0,128));
                g.fill(path);
            }
        }
        @Override public void mouseExited(MouseEvent evt) {}
        @Override public void mouseEntered(MouseEvent evt) {}
        @Override public void mouseReleased(MouseEvent evt) {}
        @Override public void mousePressed(MouseEvent evt) {}
        @Override public void mouseClicked(MouseEvent evt) {
            tower.add(new Coin(10, evt.getX(), evt.getY(), 200));
            repaint();
        }
    }
    public static void main(String[] args) {
        new CoinTower();
    }
}