2010年9月18日 星期六

[Java] 貪食蛇

這是一個非常簡單的畫出移動及按鍵的控制..

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import javax.swing.*;


public class Snake extends JFrame implements Runnable {

  private PaintPanel paintPanel = new PaintPanel();

  private boolean isRunning = true;

  private long[] sleepTime  = {500, 400, 300, 200, 100};

  private int dir = KeyEvent.VK_RIGHT;

  static Snake s = null;

  private LinkedList<Point> snakeList = new LinkedList<Point>();

  private int resolution = 20;

  public Snake() {

    super("Java Snake");

    setSize(500, 500);

    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

    setLocation(((int)dim.getWidth() - 500) / 2, ((int)dim.getHeight() - 500) / 2);

    initComponent();

    initSnake();

    setVisible(true);

    setDefaultCloseOperation(EXIT_ON_CLOSE);

  }

  private void initSnake() {

    snakeList.add(new Point(7,0));

    snakeList.add(new Point(6,0));

    snakeList.add(new Point(5,0));

    snakeList.add(new Point(4,0));

    snakeList.add(new Point(3,0));

    snakeList.add(new Point(2,0));

    snakeList.add(new Point(1,0));

    snakeList.add(new Point(0,0));

  }

  private void initComponent() {

    setLayout(new BorderLayout());

    add(paintPanel);

    addKeyListener(new SnakeKeyListener());

    addComponentListener(new ComponentListener() {

      public void componentHidden(ComponentEvent arg0) {

      }

      public void componentMoved(ComponentEvent arg0) {

      }

      public void componentResized(ComponentEvent arg0) {

        Dimension d = s.getSize();

        if(d.width <= 500) s.setSize(500, 500);

        if(d.height <= 500) s.setSize(500, 500);

      }

      public void componentShown(ComponentEvent arg0) {

      }

    });


  }

  public void run() {

    while(isRunning) {

      try {

        Thread.sleep(sleepTime[0]);

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

      checkBoundary();

      moveSnake();

      paintPanel.repaint();

    }

  }

  private void moveSnake() {

    Point p = snakeList.get(0);

    Point newPoint = null;

    switch(dir) {

      case KeyEvent.VK_RIGHT:

        newPoint = new Point(p.x + 1, p.y);

        snakeList.addFirst(newPoint);

        break;

      case KeyEvent.VK_LEFT:

        newPoint = new Point(p.x - 1, p.y);

        snakeList.addFirst(newPoint);

        break;

      case KeyEvent.VK_UP:

        newPoint = new Point(p.x, p.y - 1);

        snakeList.addFirst(newPoint);

        break;

      case KeyEvent.VK_DOWN:

        newPoint = new Point(p.x, p.y + 1);

        snakeList.addFirst(newPoint);

        break;

    }

    snakeList.removeLast();

  }

  private void checkBoundary() {

    

  }

  public static void main(String[] args) {

      s = new Snake();

    Thread d = new Thread(s);

    d.start();


  }

  private final class SnakeKeyListener extends KeyAdapter {

    public void keyPressed(KeyEvent arg0) {

      int keyDir = arg0.getKeyCode();

      if(keyDir != KeyEvent.VK_UP && keyDir != KeyEvent.VK_DOWN &&

          keyDir != KeyEvent.VK_RIGHT && keyDir != KeyEvent.VK_LEFT) {

        return;

      }

      if((dir == KeyEvent.VK_UP && keyDir == KeyEvent.VK_DOWN) || 

         (dir == KeyEvent.VK_DOWN && keyDir == KeyEvent.VK_UP) ||

         (dir == KeyEvent.VK_RIGHT && keyDir == KeyEvent.VK_LEFT) ||

         (dir == KeyEvent.VK_LEFT && keyDir == KeyEvent.VK_RIGHT)) {

        System.out.println("return");

        return;

      }

      dir = keyDir;

    }

  }

  private final class PaintPanel extends JPanel {


    public PaintPanel() {

      setBackground(Color.DARK_GRAY);

    }

    public void paint(Graphics g) {

      CleanBackground(g);

      PaintSnake(g);

    }

    private void PaintSnake(Graphics g) {

      Dimension d = null;

      d = getSize(d);

      for(int i = 0; i < snakeList.size(); ++i) {

        g.setColor(new Color(0, 255 - i*(255 / (snakeList.size())), 0));

        Point p = snakeList.get(i);

        g.fill3DRect(

            p.x*(int)(d.width / resolution), 

            p.y*(int)(d.height / resolution), 

            d.width / resolution, d.height / resolution, 

            true

            );

      }

    }

    private void CleanBackground(Graphics g) {

      Dimension d = null;

      d = getSize(d);

      g.setColor(Color.RED);

      g.fillRect(0, 0, d.width, d.height);

      g.setColor(Color.DARK_GRAY);

      for(int i = 0; i < d.width / resolution; ++i) {

        for(int j = 0; j < d.height / resolution; ++j){

          g.fill3DRect(

              i*(int)(d.width / resolution), 

              j*(int)(d.height / resolution), 

              d.width / resolution, 

              d.height / resolution, 

              true);

        }

      }

    }

  }

}

2010年9月15日 星期三

[C++ template]有趣的template, 常被誤解的型別

通常我們要做==比較時, 會希望兩邊的型別是相同的, 如果是base type如int, double, char, 這些會自動轉型, 但是遇到class或是template時怎麼辦, 其實可以在一個class裡實作出一個template的operation overload就ok了..範例如下...

下面的例子可能比較複雜一點,  但其實也只是在一個template class裡再做另一個template member function而已...

template<typename T>

class MyType {

public:

    MyType(T value) {

        m_value = value;

    };

    T GetValue() {

        return m_value;

    };

    template<typename T2> bool operator==(T2 AnotherType) {

        if(this->GetValue() == AnotherType.GetValue()) {

            return true;

        }

        return false;

    };

public:

    T m_value;};

int main() {

    MyType<int> myInt(5);

    MyType<double> myDouble(5.0);

    if(myInt == myDouble) {

        cout << "Yes!!" << endl;

    }

    return 0;

}

-----

所謂的template型別(這裡指的是被指定後的型別), 應該這麼考慮的..

"MyType<int>"是一種型別..

"MyType<double>"亦是另一種型別

 

試想在所有的程式裡..宣告一個變數一定是 "型別名" "變數名"

所以上面兩種是不同型別, 另外在偏特化的例子中, 

SomeType<int, 6>

SomeType<int, 5>

這兩個是不同型別, 寫個程式來表達一下好了..

 

-----美麗的分隔線------

template <typename T>

inline T cost& max(T const& a, T const& b) {

    return a < b ? b : a;

}

 

int main() {

    std::string s = "apple";

    ::max("123456", "567890");    // OK!

    ::max("12345", "123456");      // ERROR!!

    ::max("apple", s);                   // ERROR!!

    return 0;

}

為什麼不行呢, 因為型別不同, 很多人可能會誤以為不都是字串嗎, 特別是第二個...

真是不好意思啊, 在compiler的眼裡,

"12345"和"123456"的型別, 分別是char[5]及char[6]

所以理所當然, 第三個max也不行了..一個是char[5], 一個是string...

要小心啊..型別的問題....