撲克牌遊戲 簡易接龍 高慧君南港高中 準備一張牌桌的圖片 :porkboard.jpg 準備一張撲克牌的底圖 :blueflip.png 準備一張空的撲克牌 :empty.png 準備 13 張撲克牌的圖片 :1.png~13.png 開啟專案 Poke01 新建場景類別 Table, 設置圖像 porkboard.jpg 新建演員類別 Card 新建演員類別 Deck, 設置圖像 blueflip.png 編輯 Table 的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) * Write a description of class Table here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class Table extends World private Deck deck = new Deck(); public Table() super(600, 400, 1); addobject(deck, 50, 50); public void act() if (Greenfoot.mouseClicked(deck)) Card card = new Card(); card.setimage((1+greenfoot.getrandomnumber(13))+".png");
int x = Greenfoot.getRandomNumber(getWidth()); int y = Greenfoot.getRandomNumber(getHeight()); addobject(card, x, y); 程式碼說明 : 滑鼠事件 Greenfoot.mouseClicked() 方法簽名 : Public static Boolean mouseclicked(java.lang.object obj) 方法說明 : 如果滑鼠在某物件上按完左鍵 ( 按下並放開 ), 則傳回 true 參數 obj Typically one of Actor, Wolrd or null 傳回值 True / False 問題改進 在上例中, 我們使用亂數來取卡片, 這樣做會有重複發同一張牌的可能性 所以 接下來我們要用陣列串列 (ArrayList) 來儲存 13 張牌 編輯 Card 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) * Write a description of class Card here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class Card extends Actor private int value; public Card(int value) this.value = value;
public int getvalue() return value; * Act do whatever the Card wants to do. This method is called whenever * the 'Act' or 'Run' button gets pressed in the environment. public void act() // Add your action code here. 編輯 Deck 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) import java.util.arraylist; * Write a description of class Deck here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class Deck extends Actor private ArrayList<Card> cards = new ArrayList<Card>(); public Deck() for (int i=1; i<=13; i++) Card card = new Card(i); cards.add(card); public Card getcard() if (cards.size()>0) Card card = cards.get(0);
cards.remove(card); return card; return null; public int getsize() return cards.size(); * Act do whatever the Deck wants to do. This method is called whenever * the 'Act' or 'Run' button gets pressed in the environment. public void act() // Add your action code here. 修改 Table 類別的程式碼 public void act() if (Greenfoot.mouseClicked(deck)) Card card = deck.getcard(); card.setimage(card.getvalue()+".png"); int x = Greenfoot.getRandomNumber(getWidth()); int y = Greenfoot.getRandomNumber(getHeight()); addobject(card, x, y); if (deck.getsize()==0) removeobject(deck); 程式碼說明 : ArrayList 是 java.util 當中的一個類別 使用方法 : 以字串為例
1. 建構 ArrayList<String> myarraylist = new ArrayList<String>(); // 指定是 String 的型態 2. 加入元素 String s = new String(); mylist.add(s); 3. 查詢 list 大小 int thesize = mylist.size(); 4. 查詢特定元素 boolean isin = mylist.contains(s); // 若用上面的例子因為有 s 字串所以回傳 true 5. 查詢特定元素位置 int idx = mylist.indexof(s); // 會回傳 0 表第 0 個位置 6. 判斷 List 是否為空 boolean empty = mylist.isempty(); // 因為有一個元素會回傳 false 7. 刪除特定元素 mylist.remove(s); 8. 清除所有元素 mylist.clear(); 問題改進在上例中, 我們會依序發出 13 張牌, 但實務上, 我們在發牌前會先做洗牌的動作, 我們可以匯入 Collections 套件, 來做打亂陣列串列內容的動作 在 Deck 類別中增加程式碼 : Import java.util.collections; 在 Deck 的建構子中增加程式碼 : public Deck() for (int i=1; i<=13; i++) Card card = new Card(i);
cards.add(card); Collections.shuffle(cards); 問題改進 在上例中, 撲克牌的位置是隨機的, 接下來, 我們要產生一個牌疊 (Pile) 來存放發 出的撲克牌 新建演員類別 Pile, 設置圖像 empty.png 編輯 Pile 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) import java.util.arraylist; * Write a description of class Pile here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class Pile extends Actor private ArrayList<Card> cards = new ArrayList<Card>(); public void addcard(card card) cards.add(card); getworld().addobject(card, getx()+(cards.size() 1)*20, gety()); * Act do whatever the Pile wants to do. This method is called whenever * the 'Act' or 'Run' button gets pressed in the environment. public void act() // Add your action code here.
修改 Table 類別的程式碼 public class Table extends World private Deck deck = new Deck(); private Pile pile = new Pile(); public Table() super(600, 400, 1); addobject(deck, 50, 50); addobject(pile, 150, 50); public void act() if (Greenfoot.mouseClicked(deck)) Card card = deck.getcard(); card.setimage(card.getvalue()+".png"); pile.addcard(card); if (deck.getsize()==0) removeobject(deck); 問題改進 在上例中, 發出的撲克牌是固定不動的, 接下來, 我們要來讓撲克牌可以拖曳 修改 Card 類別的程式碼 public class Card extends Actor private int value; private int initx, inity; public Card(int value) this.value = value; public int getvalue() return value;
* Act do whatever the Card wants to do. This method is called whenever * the 'Act' or 'Run' button gets pressed in the environment. public void act() // Add your action code here. MouseInfo mouse = Greenfoot.getMouseInfo(); if (Greenfoot.mousePressed(this)) initx = getx(); inity = gety(); if (Greenfoot.mouseDragged(this)) setlocation(mouse.getx(), mouse.gety()); if (Greenfoot.mouseDragEnded(this)) setlocation(initx, inity); 程式碼說明 1. static boolean mousedragended(java.lang.object obj) 若滑鼠結束拖拉, 則傳回 true 2. static boolean mousedragged(java.lang.object obj) 若滑鼠正在這個物件上拖拉, 則傳回 true 3. static boolean mousepressed(java.lang.object obj) 若滑鼠按在這個物件上 ( 滑鼠鍵由沒按下狀態轉為按下狀態 ), 則傳回 true 4. static MouseInfo getmouseinfo()
取得滑鼠資訊物件, 內含滑鼠目前的狀態 問題改進 在上例中, 撲克牌可以拖曳, 但圖層效果不對, 我們希望拖曳中的撲克牌會在最 上層, 放開後會回到原地點原圖層 增加 Table 類別的程式碼 public Pile getpile() return pile; 增加 Pile 類別的程式碼 public void removecard(card card) cards.remove(card); public void redraw() for (Card card : cards) World world = getworld(); int x = card.getx(); int y = card.gety(); world.removeobject(card); world.addobject(card, x, y); 修改 Card 類別的程式碼 public void act() // Add your action code here. MouseInfo mouse = Greenfoot.getMouseInfo(); if (Greenfoot.mousePressed(this)) initx = getx(); inity = gety(); World world = getworld(); world.removeobject(this);
world.addobject(this, initx, inity); if (Greenfoot.mouseDragged(this)) setlocation(mouse.getx(), mouse.gety()); if (Greenfoot.mouseDragEnded(this)) Table table = (Table) getworld(); table.getpile().redraw(); setlocation(initx, inity); 問題改進 在上例中, 撲克牌可以拖曳, 接下來, 我們要來讓撲克牌可以依序由小到大收入 到目標牌疊 (CardStack) 中 撲克牌放入目標牌疊後就不能拖曳 新建演員類別 CardStack, 設置圖像 empty.png 修改 Table 類別的建構子程式碼 public Table() super(600, 400, 1); addobject(deck, 50, 50); addobject(pile, 150, 50); addobject(cardstack, 150, 150); 編輯 CardStack 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) import java.util.arraylist; * Write a description of class CardStack here. * * @author Jean, Hue Ching Kao * @version 2013.3.31
public class CardStack extends Actor private ArrayList<Card> cards = new ArrayList<Card>(); public void addcard(card card) cards.add(card); card.setcandrag(false); card.setlocation(getx(), gety()+(cards.size() 1)*15); public boolean isacceptcard(card card) if (cards.size()>0) Card lastcard = cards.get(cards.size() 1); if (lastcard.getvalue()+1==card.getvalue()) return true; else if (card.getvalue()==1) return true; return false; * Act do whatever the CardStack wants to do. This method is called whenever * the 'Act' or 'Run' button gets pressed in the environment. public void act() // Add your action code here. 修改 Card 類別的程式碼 public class Card extends Actor private int value; private int initx, inity; private boolean candrag=true; public Card(int value) this.value = value;
public int getvalue() return value; public void setcandrag(boolean candrag) this.candrag = candrag; * Act do whatever the Card wants to do. This method is called whenever * the 'Act' or 'Run' button gets pressed in the environment. public void act() // Add your action code here. if (!candrag) return; MouseInfo mouse = Greenfoot.getMouseInfo(); if (Greenfoot.mousePressed(this)) initx = getx(); inity = gety(); World world = getworld(); world.removeobject(this); world.addobject(this, initx, inity); if (Greenfoot.mouseDragged(this)) setlocation(mouse.getx(), mouse.gety()); if (Greenfoot.mouseDragEnded(this)) Table table = (Table) getworld(); Pile pile = table.getpile(); CardStack cardstack = (CardStack) getoneintersectingobject(cardstack.class); if (cardstack!= null)
if (cardstack.isacceptcard(this)) pile.removecard(this); cardstack.addcard(this); return; pile.redraw(); setlocation(initx, inity); 問題改進 在上例中, 目標牌疊 (CardStack) 的感應區只有一張牌的大小, 我們希望加大感應 區的縱向範圍 ( 加長 200 個像素 ) 修改 Table 類別的建構子程式碼 public Table() super(600, 400, 1); addobject(deck, 50, 50); addobject(pile, 150, 50); addobject(cardstack, 150, 250); 編輯 CardStack 類別的程式碼 public class CardStack extends Actor private ArrayList<Card> cards = new ArrayList<Card>(); public void addcard(card card) cards.add(card); card.setcandrag(false); card.setlocation(getx(), gety()+(cards.size() 1)*15 100); public boolean isacceptcard(card card) if (cards.size()>0) Card lastcard = cards.get(cards.size() 1);
if (lastcard.getvalue()+1==card.getvalue()) return true; else if (card.getvalue()==1) return true; return false; public void addedtoworld(world world) setimage("empty.png"); GreenfootImage image = new GreenfootImage(getImage().getWidth(), getimage().getheight()+200); image.drawimage(new GreenfootImage("empty.png"), 0, 0); setimage(image); * Act do whatever the CardStack wants to do. This method is called whenever * the 'Act' or 'Run' button gets pressed in the environment. public void act() // Add your action code here. 問題改進在上例中, 我們已經完成了 13 張撲克牌的簡易接龍, 接下來, 我們要來處理 52 張牌的情形, 並且能夠依不同的花色來處理接龍動作 在這裡, 我們用 52 張牌來再複習一遍上面所做過的動作 準備一張牌桌的圖片 :porkboard.jpg 準備一張撲克牌的底圖 :blueflip.png 準備一張空的撲克牌 :empty.png 準備 52 張撲克牌的圖片 :spades1.png~diamonds13.png 開啟專案 Poke02 新建場景類別 Table, 設置圖像 porkboard.jpg
新建演員類別 Card 新建演員類別 Deck, 設置圖像 blueflip.png 新建演員類別 Pile, 設置圖像 empty.png 新建演員類別 CardStack, 設置圖像 empty.png 編輯 Card 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) * Write a description of class Card here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class Card extends Actor public enum Suit spades, hearts, clubs, diamonds; private Suit suit; private int value; private boolean candrag=true; public Card(Suit suit, int value) this.suit = suit; this.value = value; setimage(suit+""+value+".png"); public Suit getsuit() return suit; public int getvalue() return value; public void setcandrag(boolean candrag) this.candrag = candrag;
程式碼說明 在上例中, 我們使用了列舉 (Enum) 來儲存撲克牌的花色, 列舉可以賦予常數值可 讀意義的簡便方法, 基於 Java 語言的特性, Enum 應用在方法的參數傳遞與回 傳值上, 具有提高表達能力以及強制內容檢查的兩種好處 編輯 Deck 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) import java.util.arraylist; import java.util.collections; * Write a description of class Deck here. * * @author (your name) * @version (a version number or a date) public class Deck extends Actor private ArrayList<Card> cards = new ArrayList<Card>(); public Deck() for (Card.Suit suit: Card.Suit.values()) for (int i=1; i<=13; i++) Card card = new Card(suit, i); cards.add(card); Collections.shuffle(cards); public Card getcard() if (cards.size()>0) Card card = cards.get(0); cards.remove(card); return card;
return null; public int getsize() return cards.size(); 編輯 CardStack 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) * Write a description of class CardStack here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class CardStack extends Actor public void addedtoworld(world world) setimage("empty.png"); GreenfootImage image = new GreenfootImage(getImage().getWidth(), getimage().getheight()+200); image.drawimage(new GreenfootImage("empty.png"), 0, 0); setimage(image); 編輯 Table 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) import java.util.arraylist; * Write a description of class Table here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class Table extends World
private Deck deck = new Deck(); private Pile pile = new Pile(); private ArrayList<CardStack> cardstacks = new ArrayList<CardStack>(); * Constructor for objects of class Table. * public Table() // Create a new world with 600x400 cells with a cell size of 1x1 pixels. super(600, 400, 1); addobject(deck, 50, 50); addobject(pile, 150, 50); for (int i=0; i<4; i++) CardStack cardstack = new CardStack(); cardstacks.add(cardstack); addobject(cardstack, 150+i*100, 250); 任務一 : 發牌到牌疊上 編輯 Pile 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) import java.util.arraylist; * Write a description of class Pile here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class Pile extends Actor private ArrayList<Card> cards = new ArrayList<Card>();
public void addcard(card card) cards.add(card); getworld().addobject(card, getx()+(cards.size() 1)*8, gety()); public void removecard(card card) cards.remove(card); 修改 Table 類別的程式碼 public void act() if (Greenfoot.mouseClicked(deck)) Card card = deck.getcard(); pile.addcard(card); if (deck.getsize()==0) removeobject(deck); 任務二 : 讓牌疊上的撲克牌可以拖曳, 拖曳時會顯示在最上層, 拖曳完後會回到 原來的圖層 編輯 Card 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) * Write a description of class Card here. * * @author Jean, Hue Ching Kao * @version 2013.3.31 public class Card extends Actor public enum Suit spades, hearts, clubs, diamonds; private Suit suit;
private int value; private boolean candrag=true; private int initx, inity; public Card(Suit suit, int value) this.suit = suit; this.value = value; setimage(suit+""+value+".png"); public Suit getsuit() return suit; public int getvalue() return value; public void setcandrag(boolean candrag) this.candrag = candrag; * Act do whatever the Card wants to do. This method is called whenever * the 'Act' or 'Run' button gets pressed in the environment. public void act() // Add your action code here. if (!candrag) return; MouseInfo mouse = Greenfoot.getMouseInfo(); Table table = (Table) getworld(); Pile pile = table.getpile(); if (Greenfoot.mousePressed(this)) initx = getx(); inity = gety(); World world = getworld();
world.removeobject(this); world.addobject(this, initx, inity); if (Greenfoot.mouseDragged(this)) setlocation(mouse.getx(), mouse.gety()); if (Greenfoot.mouseDragEnded(this)) pile.redraw(); setlocation(initx, inity); 新增 Table 類別的程式碼 public Pile getpile() return pile; 新增 Pile 類別的程式碼 public void redraw() for (Card card: cards) int x = card.getx(); int y = card.gety(); World world = getworld(); world.removeobject(card); world.addobject(card, x, y); 任務三 : 撲克牌可以拖曳到目標牌疊上, 依花色排列, 放入後就不能再拖曳 編輯 CardStack 類別的程式碼 import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) import java.util.arraylist; * Write a description of class CardStack here.
* * @author Jean, Hue Ching Kao * @version 2013.3.31 public class CardStack extends Actor private ArrayList<Card> cards = new ArrayList<Card>(); public void addcard(card card) cards.add(card); card.setcandrag(false); card.setlocation(getx(), gety()+(cards.size() 1)*15 100); public boolean isacceptcard(card card) if (cards.size()>0) Card lastcard = cards.get(cards.size() 1); if (lastcard.getsuit() == card.getsuit()) if (lastcard.getvalue()+1==card.getvalue()) return true; else if (card.getvalue()==1) return true; return false; public void addedtoworld(world world) setimage("empty.png"); GreenfootImage image = new GreenfootImage(getImage().getWidth(), getimage().getheight()+200); image.drawimage(new GreenfootImage("empty.png"), 0, 0); setimage(image); 編輯 Card 類別的程式碼
public class Card extends Actor public void act() // Add your action code here. if (!candrag) return; MouseInfo mouse = Greenfoot.getMouseInfo(); Table table = (Table) getworld(); Pile pile = table.getpile(); if (Greenfoot.mousePressed(this)) initx = getx(); inity = gety(); World world = getworld(); world.removeobject(this); world.addobject(this, initx, inity); if (Greenfoot.mouseDragged(this)) setlocation(mouse.getx(), mouse.gety()); if (Greenfoot.mouseDragEnded(this)) CardStack cardstack = (CardStack) getoneintersectingobject(cardstack.class); if (cardstack!= null && cardstack.isacceptcard(this)) cardstack.addcard(this); pile.removecard(this); return; pile.redraw(); setlocation(initx, inity); 編輯 Pile 類別的程式碼 public class Pile extends Actor
private ArrayList<Card> cards = new ArrayList<Card>(); private static int cardnumber=0; public Pile() cardnumber=0; public void addcard(card card) cards.add(card); cardnumber++; getworld().addobject(card, getx()+(cardnumber 1)*8, gety());