Hunt The Wumpus/Java: Difference between revisions
Content added Content deleted
mNo edit summary |
m (let's initialize enum with warning directly) |
||
Line 16: | Line 16: | ||
public class Wumpus extends JPanel { |
public class Wumpus extends JPanel { |
||
enum Hazard { |
enum Hazard { |
||
Wumpus( |
Wumpus("there's an awful smell"), |
||
⚫ | |||
Pit("you feel a draft"); |
|||
Hazard( |
Hazard(String warning) { |
||
warning = |
this.warning = warning; |
||
} |
} |
||
final String warning; |
final String warning; |
||
final String[] warnings = {"there's an awful smell", |
|||
⚫ | |||
} |
} |
||
Revision as of 23:29, 18 April 2016
In this version, arrows only fire a distance of one room. Since bats relocate, we don't have to worry
about the wumpus room being unreachable. There are also 3 bats instead of 2, and you get 3 arrows instead of 5.
Code
<lang java>import java.awt.*; import java.awt.event.*; import java.awt.geom.Path2D; import java.util.*; import java.util.List; import static java.util.stream.Collectors.joining; import javax.swing.*; import static javax.swing.SwingUtilities.*;
public class Wumpus extends JPanel {
enum Hazard { Wumpus("there's an awful smell"), Bat("you hear a rustling"), Pit("you feel a draft");
Hazard(String warning) { this.warning = warning; } final String warning; }
static final Random rand = new Random();
final int caveSize = 45; final int playerSize = 16;
boolean gameOver = true; int currRoom, numArrows, wumpusRoom; List<String> messages; Map<Integer, List<Hazard>> hazards;
public Wumpus() { setPreferredSize(new Dimension(721, 677)); setBackground(Color.white); setForeground(Color.lightGray); setFont(new Font("SansSerif", Font.PLAIN, 18)); setFocusable(true);
addMouseListener(new MouseAdapter() { boolean firedArrow = false;
@Override public void mousePressed(MouseEvent e) { if (gameOver) { startNewGame();
} else { int selectedRoom = -1; int ex = e.getX(); int ey = e.getY();
for (int link : links[currRoom]) { int cx = rooms[link][0]; int cy = rooms[link][1]; if (insideRoom(ex, ey, cx, cy)) { selectedRoom = link; break; } }
if (selectedRoom == -1) return;
if (isLeftMouseButton(e)) { currRoom = selectedRoom; situation();
} else if (isRightMouseButton(e)) { if (!firedArrow) { firedArrow = true; shoot(selectedRoom); } } } repaint(); }
@Override public void mouseReleased(MouseEvent e) { firedArrow = false; }
boolean insideRoom(int ex, int ey, int cx, int cy) { return ((ex > cx && ex < cx + caveSize) && (ey > cy && ey < cy + caveSize)); } }); }
void startNewGame() { currRoom = rand.nextInt(rooms.length); numArrows = 3; messages = new ArrayList<>();
hazards = new HashMap<>(); for (int i = 0; i < rooms.length; i++) hazards.put(i, new LinkedList<>());
// hazards can share rooms int[] ordinals = {0, 1, 1, 1, 2, 2}; Hazard[] values = Hazard.values(); for (int ord : ordinals) { int room; do { room = rand.nextInt(rooms.length); } while (tooCloseForComfort(room));
if (ord == 0) wumpusRoom = room;
hazards.get(room).add(values[ord]); }
gameOver = false; }
// don't place hazards close to the starting room boolean tooCloseForComfort(int room) { if (currRoom == room) return true; for (int link : links[currRoom]) if (room == link) return true; return false; }
void situation() { List<Hazard> lst = hazards.get(currRoom); if (lst.contains(Hazard.Wumpus)) { messages.add("you've been eaten by the Wumpus"); gameOver = true;
} else if (lst.contains(Hazard.Pit)) { messages.add("you fell into a pit"); gameOver = true;
} else if (lst.contains(Hazard.Bat)) { messages.add("a bat dropped you in a random room");
// teleport, but avoid 2 teleports in a row do { currRoom = rand.nextInt(rooms.length); } while (hazards.get(currRoom).contains(Hazard.Bat));
// relocate the bat, but not to the player room lst.remove(Hazard.Bat); int newRoom; do { newRoom = rand.nextInt(rooms.length); } while (newRoom == currRoom); hazards.get(newRoom).add(Hazard.Bat);
// re-evaluate situation();
} else {
// look around for (int link : links[currRoom]) { for (Hazard hazard : hazards.get(link)) messages.add(hazard.warning); } } }
void shoot(int room) { if (hazards.get(room).contains(Hazard.Wumpus)) { messages.add("You win! You've killed the Wumpus!"); gameOver = true;
} else { numArrows--; if (numArrows == 0) { messages.add("You ran out of arrows."); gameOver = true;
} else if (rand.nextInt(4) != 0) { hazards.get(wumpusRoom).remove(Hazard.Wumpus); wumpusRoom = links[wumpusRoom][rand.nextInt(3)]; if (wumpusRoom == currRoom) { messages.add("You woke the Wumpus and he ate you"); gameOver = true; } else { messages.add("You woke the Wumpus and he moved"); hazards.get(wumpusRoom).add(Hazard.Wumpus); } } } }
void drawPlayer(Graphics2D g) { int x = rooms[currRoom][0] + (caveSize - playerSize) / 2; int y = rooms[currRoom][1] + (caveSize - playerSize) - 2;
Path2D player = new Path2D.Double(); player.moveTo(x, y); player.lineTo(x + playerSize, y); player.lineTo(x + playerSize / 2, y - playerSize); player.closePath();
g.setColor(Color.white); g.fill(player); g.setStroke(new BasicStroke(1)); g.setColor(Color.black); g.draw(player); }
void drawStartScreen(Graphics2D g) { g.setColor(new Color(0xDDFFFFFF, true)); g.fillRect(0, 0, getWidth(), getHeight() - 60);
g.setColor(Color.darkGray); g.setFont(new Font("SansSerif", Font.BOLD, 48)); g.drawString("hunt the wumpus", 160, 240);
g.setFont(getFont()); g.drawString("left-click to move, right-click to shoot", 210, 310); g.drawString("be aware that hazards may be in the same room", 175, 345); g.drawString("click to start", 310, 380); }
void drawRooms(Graphics2D g) { g.setColor(Color.darkGray); g.setStroke(new BasicStroke(2)); for (int i = 0; i < links.length; i++) { for (int link : links[i]) { int x1 = rooms[i][0] + caveSize / 2; int y1 = rooms[i][1] + caveSize / 2; int x2 = rooms[link][0] + caveSize / 2; int y2 = rooms[link][1] + caveSize / 2; g.drawLine(x1, y1, x2, y2); } }
g.setColor(Color.orange); for (int[] r : rooms) g.fillOval(r[0], r[1], caveSize, caveSize);
if (!gameOver) { g.setColor(Color.magenta); for (int link : links[currRoom]) g.fillOval(rooms[link][0], rooms[link][1], caveSize, caveSize); }
g.setColor(Color.darkGray); for (int[] r : rooms) g.drawOval(r[0], r[1], caveSize, caveSize); }
void drawMessage(Graphics2D g) { if (!gameOver) g.drawString("arrows " + numArrows, 610, 30);
if (messages != null) { g.setColor(Color.black); String msg = messages.stream().distinct().collect(joining(" & ")); g.drawString(msg, 20, getHeight() - 30); messages.clear(); } }
@Override public void paintComponent(Graphics gg) { super.paintComponent(gg); Graphics2D g = (Graphics2D) gg; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
drawRooms(g); if (gameOver) { drawStartScreen(g); } else { drawPlayer(g); } drawMessage(g); }
public static void main(String[] args) { invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setTitle("Hunt The Wumpus"); f.setResizable(false); f.add(new Wumpus(), BorderLayout.CENTER); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); }
int[][] rooms = {{334, 20}, {609, 220}, {499, 540}, {169, 540}, {62, 220}, {169, 255}, {232, 168}, {334, 136}, {435, 168}, {499, 255}, {499, 361}, {435, 447}, {334, 480}, {232, 447}, {169, 361}, {254, 336}, {285, 238}, {387, 238}, {418, 336}, {334, 393}};
int[][] links = {{4, 7, 1}, {0, 9, 2}, {1, 11, 3}, {4, 13, 2}, {0, 5, 3}, {4, 6, 14}, {7, 16, 5}, {6, 0, 8}, {7, 17, 9}, {8, 1, 10}, {9, 18, 11}, {10, 2, 12}, {13, 19, 11}, {14, 3, 12}, {5, 15, 13}, {14, 16, 19}, {6, 17, 15}, {16, 8, 18}, {19, 10, 17}, {15, 12, 18}};
}</lang>