2008年7月27日星期日

扎绵羊机器人

玩扎绵羊走火入魔,一怒之下写了个扎绵羊机器人。

原理超级简单,就是让计算机自动判断绵羊的出现并在按钮上方点击鼠标。
很粗糙的一个Java程序,根据不同显示器分辨率和浏览器需要手动调整代码。
我的是1024*768,Firefox3默认布局,启动前滚动条滚动到扎绵羊开始页面顶部。

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;

public class Cap {
    static final int SIZE = 10;
    Robot robot;
    Rectangle rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
    Color[] detector = new Color[SIZE];;
    Point[] ps = new Point[SIZE];

    public Cap() throws AWTException {
        robot = new Robot();
        for (int i = 0; i < 10; i++) {
            ps[i] = new Point(255, 280 + i * 44);
        //    ps[10 + i] = new Point(355, 285 + i * 44);
        //    ps[20 + i] = new Point(410, 290 + i * 44);
        }
    }

    BufferedImage capture() {
        return robot.createScreenCapture(rect);
    }

    void shoot() {
        robot.mouseMove(550, 660);
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
    }
    void update(){
        for (int i=0; i < SIZE; i++){
            detector[i] = robot.getPixelColor(ps[i].x, ps[i].y);
        }
    }
    void showDetector() {// debug
        robot.delay(500);
        for (Point p : ps) {
            robot.mouseMove(p.x, p.y);
            robot.delay(200);
        }
    }
    static boolean closeTo(Color c1, Color c2){
        return c1.equals(c2);

    }
    public static void main(String args[]) throws AWTException, IOException {
        Cap c = new Cap();
        if (args.length > 0) {
            c.showDetector();
            return;
        }
        // wait to switch to firefox window
        c.robot.delay(1000);
        // press to start
        c.shoot();
        // wait the fog disappear
        c.robot.delay(500);
        // make detector
        c.update();
        // When different from detector, shoot
        int bullet = 5;
        while (bullet > 0) {
            c.robot.delay(20);
        //    long t = System.currentTimeMillis();
            for (int i = 0; i < SIZE; i++) {
                int x = c.ps[i].x;
                int y = c.ps[i].y;
                Color colorNow = c.robot.getPixelColor(x, y);
                if (!closeTo(colorNow, c.detector[i])) {
                    c.shoot();
                    bullet--;
                    System.out.println(i);
                //    c.detector[i] = colorNow;
                    c.robot.delay(500);
                    c.update();
                    break;
                }
            }
        //    System.out.println(System.currentTimeMillis() - t);
        }
    }

}
在 命令行启动程序后,赶快Alt+Tab切换到Firefox界面上来,然后你就看着绵羊一只只死在屏幕最左边吧XD(我现在作弊后的成绩是0.02秒多一 点,已经接近Flash Player的计时函数的误差了(在我机器上setTimeout的误差约0.01秒(测量误差不计)))
P.S.用了这么久Java,才知道有java.awt.Robot这么一个类,JDK里真是充满了宝藏啊~

2008年7月23日星期三

A simple picasa synchronizer in console

I wrote a simple utility to synchronize local picture directory with picasa web album. I'm pleased to share it :)
Python code, 41 lines.

This is the wiki page for it. Welcome to download and enjoy it :)

Install

Install python gdata client

Download http://gdata-python-client.googlecode.com/files/gdata.py-1.1.1.zip and install it according to the http://code.google.com/apis/gdata/articles/python_client_lib.html

Download this utility

Download http://picasup.googlecode.com/svn/trunk/picUp/src/picup/picu.py , and copy it to wherever you like, such as /home/todwong/sandbox/python/picupy/picu.py

Register it into PATH

Create a shell script in $PATH, such as /home/todwong/bin/picupy, with the content:

python /home/todwong/sandbox/python/picupy/picu.py

and make this scrtip executable:

chmod +x /home/todwong/bin/picupy

Use

Go to your directory with your jpg files, such as

cd /home/todwong/pic/hangzhou/

execute this shell directly

picupy

which refers /home/todwong/bin/picupy

Input you picasa web account username and password.

If you have already got an album named hangzhou online, continue to use that album, else create a new album named hangzhou and use it.

Upload those JPG files in your local directory /home/todwong/pic/hangzhou/ and not in your online album hangzhou yet.

To some extent, this utility is a one-way synchronizer, synchronizing from local directory to online picasa web album, with the current directory name to be the album title, and with the name of each file in current directory to be the title of each photo in the album. It is quite easy to use, because except for the account info, nothing else you have to input. Synchronizing processes automatically.


Thanks to
http://code.google.com/apis/picasaweb

Welcome to subscribe with my blog
http://todwang.blogspot.com

2008年7月12日星期六

Ubuntu Opera Flash Player Plug-in

locate libflashplayer.so

如果找到,直接把这个so文件复制到

/usr/lib/opera/plugins

即可

否则去Adobe网站下载

http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash

安装,再locate libflashplayer.so

2008年7月5日星期六

解析法计算两圆交点

中学解析几何知道圆的方程,因此计算两圆交点只需要将两个方程联立,解这个二元二次方程组即可。很容易降幂,化成二元一次方程和圆方程,几何意义是计算直线和圆的交点。下面是用Java实现的代码,可以直观验证解的正确性。
package chap9;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Arrays;

import javax.swing.JFrame;

public class CrossPoint extends JFrame {
    private static final long serialVersionUID = 1L;

    public CrossPoint() {
        super("Cross Point");
        setSize(400, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        play();
    }

    private double rnd(double k) {
        return Math.random() * k;
    }

    @Override
    public void paint(Graphics g) {
        g.clearRect(0, 0, getWidth(), getHeight());
        Circle c1 = new Circle(rnd(200), rnd(280), 100 + rnd(100));
        c1.drawOn(g);
        Circle c2 = new Circle(rnd(250), rnd(200), 100 + rnd(200));
        c2.drawOn(g);
        Point[] ps = c1.crossAt(c2);
        if (ps == null)
            System.out.println("not cross");
        else
            System.out.println(Arrays.toString(ps));
    }

    public static void main(String[] args) {
        new CrossPoint();
    }

    private void play() {
        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                Point p = e.getPoint();
                setTitle(p.toString());
            }
        });
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                repaint();
            }
        });
    }

}

class Circle {
    double x, y, d;

    public Circle(double x, double y, double d) {
        super();
        this.x = x;
        this.y = y;
        this.d = d;
    }

    public void drawOn(Graphics g) {
        int r = (int) d / 2;
        g.setColor(Color.BLACK);
        g.drawOval((int) x - r, (int) y - r, (int) d, (int) d);
    }

    public double distanceTo(Circle c2) {
        return Point.distance(x, y, c2.x, c2.y);
    }

    public Point[] crossAt(Circle c2) {
        double r1 = d / 2;
        double r2 = c2.d / 2;
        double L = distanceTo(c2);
        if (L > r1 + r2)
            return null;
        double dx = x - c2.x;
        double dy = y - c2.y;
        double dr = (r2 * r2 - r1 * r1 - dx * dx - dy * dy) / 2;
        double a = dx * dx + dy * dy;
        double b, c, d, x01, x02, y01, y02;
        if (isZero(dx)) {
            b = -2 * dx * dr;
            c = dr * dr - r1 * r1 * dy * dy;
            d = Math.sqrt(b * b - 4 * a * c);
            x01 = (-b + d) / (2 * a);
            x02 = (-b - d) / (2 * a);
            y01 = (dr - x01 * dx) / dy;
            y02 = (dr - x02 * dx) / dy;
        } else {
            b = -2 * dy * dr;
            c = dr * dr - r1 * r1 * dx * dx;
            d = Math.sqrt(b * b - 4 * a * c);
            y01 = (-b + d) / (2 * a);
            y02 = (-b - d) / (2 * a);
            x01 = (dr - y01 * dy) / dx;
            x02 = (dr - y02 * dy) / dx;
        }
        return new Point[] { new Point((int) (x01 + x), (int) (y01 + y)),
                new Point((int) (x02 + x), (int) (y02 + y)) };
    }

    private boolean isZero(double dx) {
        return Math.abs(dx) < 0.001;
    }
}