Oop lab/sokoban
- หน้านี้เป็นส่วนหนึ่งของ oop lab
เกม Sokoban เป็นเกมปัญหาที่โด่งดังมากในอดีต ทดลองเล่นได้ที่ [1] หรือ [2]
ในเกมนี้ผู้เล่นจะเดินเข็นกล่องไปมาให้ไปอยู่ในตำแหน่งปลายทาง ผู้เล่นจะดันกล่องได้เท่านั้น (ดึงไม่ได้ถ้าดันไปติดกำแพงก็จบเกม) และจะสามารถดันกล่องได้แค่ใบเดียวเท่านั้น (ถ้าติดกันสองใบจะหนักเกิน ดันไม่ไหว)
เนื้อหา
เริ่มต้น
เราจะพัฒนาเกมดังกล่าวด้วยกระบวนการ TDD และหัดใช้ git ไปพร้อม ๆ กัน ดังนั้นให้สร้างโปรเจ็ค จากนั้นให้สร้าง git repository ของโปรเจ็คด้วย (ดูวิธีการได้ในคลิป egit)
กระดานเกมทั่วไป และการแสดงผล
ด้านล่างเป็นคลาส GameBoard และ unit test เบื้องต้น GameBoardTest ให้สร้างคลาสดังกล่าวใน project และนำโค้ดด้านล่างไปใช้ อย่าลืมดูชื่อ package ให้สอดคล้องกับ project ที่สร้างขึ้นด้วย (โดยมากนิยมใช้ชื่อเดียวกัน)
ให้ทดลองสั่งให้ unit test ทำงาน ถ้าเขียวหมด ให้ commit เวอร์ชันนี้ลง git
GameBoard.java
package sokoban;
public class GameBoard {
private int height;
private int width;
private String[] baseBoard;
private int playerRow;
private int playerCol;
private int numBoxes;
private int[][] boxPositions;
public GameBoard(String[] map) {
loadBoard(map);
}
public void loadBoard(String[] map) {
height = map.length;
width = map[0].length();
numBoxes = 0;
boxPositions = new int[height*width][2];
baseBoard = new String[height];
for(int r = 0; r < height; r++) {
baseBoard[r] = "";
for(int c = 0; c < width; c++) {
char mch = map[r].charAt(c);
char sch = '.';
switch(mch) {
case 'A':
playerRow = r;
playerCol = c;
break;
case 'O':
boxPositions[numBoxes][0] = r;
boxPositions[numBoxes][1] = c;
numBoxes++;
break;
default:
sch = mch;
}
baseBoard[r] += sch;
}
}
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public int getPlayerRow() {
return playerRow;
}
public int getPlayerCol() {
return playerCol;
}
public void setPlayerPosition(int r, int c) {
playerRow = r;
playerCol = c;
}
public int getNumBoxes() {
return numBoxes;
}
public int[] getBoxPosition(int i) {
return new int[] {
boxPositions[i][0],
boxPositions[i][1]
};
}
public void setBoxPosition(int i, int r, int c) {
boxPositions[i][0] = r;
boxPositions[i][1] = c;
}
public boolean hasPlayerAt(int r, int c) {
return (playerRow == r) && (playerCol == c);
}
public boolean hasBoxAt(int r, int c) {
return false;
}
public boolean hasExitAt(int r, int c) {
return false;
}
public String toString() {
return "";
}
}
GameBoardTest.java
package sokoban;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
public class GameBoardTest {
static String smallBoardMap[] = {
" #####",
"#*O.A#",
"#...O#",
"##..*#",
" #####"
};
private GameBoard smallBoard;
@Before
public void setUp() {
smallBoard = new GameBoard(smallBoardMap);
}
@Test
public void testLoadBoardProperties() {
assertEquals(5, smallBoard.getHeight());
assertEquals(6, smallBoard.getWidth());
}
@Test
public void testLoadBoardPlayerPosition() {
assertEquals(1, smallBoard.getPlayerRow());
assertEquals(4, smallBoard.getPlayerCol());
}
@Test
public void testLoadBoardNumBoxes() {
assertEquals(2, smallBoard.getNumBoxes());
}
@Test
public void testLoadBoardBoxPositions() {
assertArrayEquals(new int[] {1, 2}, smallBoard.getBoxPosition(0));
assertArrayEquals(new int[] {2, 4}, smallBoard.getBoxPosition(1));
}
@Test
public void testPlayerPositionCheck() {
assertFalse(smallBoard.hasPlayerAt(0,0));
assertTrue(smallBoard.hasPlayerAt(1,4));
}
@Test
public void testPlayerPositionCheckAfterChange() {
smallBoard.setPlayerPosition(2, 3);
assertFalse(smallBoard.hasPlayerAt(1,4));
assertTrue(smallBoard.hasPlayerAt(2, 3));
}
}