From 6eea01482c41fec84fa58562d2e2b20d0f09d9f8 Mon Sep 17 00:00:00 2001 From: MrMcX Date: Sun, 11 Sep 2016 11:13:13 +0200 Subject: [PATCH] Experimental statistic room generation implemented --- nbproject/private/private.xml | 9 ++ src/dungeon/Dungeon.java | 155 ++++++++++++++++++++++++------- src/dungeon/Room.java | 29 +++--- src/main/DungeonGeneratorUI.form | 25 ++++- src/main/DungeonGeneratorUI.java | 112 +++++++++++++++++----- 5 files changed, 258 insertions(+), 72 deletions(-) diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml index d7d311b..ca6c2e6 100644 --- a/nbproject/private/private.xml +++ b/nbproject/private/private.xml @@ -3,8 +3,17 @@ + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/src/dungeon/Room.java + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/src/dungeon/Exit.java + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/.gitignore + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/src/dungeon/Dungeon.java file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/build.xml + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/nbproject/build-impl.xml file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/src/main/DungeonGeneratorUI.java + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/src/util/Counter.java + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/src/dungeon/Enemy.java + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/src/util/Dice.java + file:/C:/Users/MrMcX/ownCloud/Rollenspiel/DSA/Meister/DungeonGenerator/src/dungeon/Trap.java diff --git a/src/dungeon/Dungeon.java b/src/dungeon/Dungeon.java index ff3dfc6..37ece5d 100644 --- a/src/dungeon/Dungeon.java +++ b/src/dungeon/Dungeon.java @@ -24,8 +24,12 @@ package dungeon; import java.util.ArrayList; +import java.util.Dictionary; +import java.util.EnumMap; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import util.Counter; import util.Dice; import org.jgraph.graph.DefaultEdge; @@ -34,31 +38,48 @@ import org.jgrapht.graph.SimpleGraph; /** * Stores all information about the dungeon + * * @author MrMcX */ public class Dungeon { + private final List rooms; private final LinkedList toGenerate; private final Counter counter; - + private final HashMap greedyMap; + /** - * Stanard constructor, creates a new dungeon and then generates the contens + * Standard constructor, creates a new dungeon + * * @param size maximum number of rooms * @param type how the rooms are to construct - * @param mode determines room generation sequence */ - public Dungeon(int size, Type type, Mode mode){ + public Dungeon(int size, Type type) { rooms = new ArrayList<>(); toGenerate = new LinkedList<>(); counter = new Counter(); - generate(size, type, mode); + greedyMap = GreedyMap(size, type); + } + + /** + * Returns the greedy map + * @return + */ + public HashMap GetGreedyMap(){ + return greedyMap; } - private void generate(int size, Type type, Mode mode){ - toGenerate.add(Room.RandomRoom(true, Exit.Start(), counter, type)); - while(!toGenerate.isEmpty() && rooms.size() < size){ + /** + * Generates the dungeons contents + * @param size Size of the dungeon + * @param type type of environment + * @param mode generation mode + */ + public void generate(int size, Type type, Mode mode) { + toGenerate.add(Room.RandomRoom(true, Exit.Start(), counter, type, greedyMap)); + while (!toGenerate.isEmpty() && (rooms.size() < size || Experimental(type))) { Room next; - switch(mode){ + switch (mode) { case STRAIGHT: next = toGenerate.getLast(); break; @@ -66,37 +87,38 @@ public class Dungeon { next = toGenerate.getFirst(); break; case RANDOM: - next = toGenerate.get(Dice.Roll(toGenerate.size(), 1)-1); + next = toGenerate.get(Dice.Roll(toGenerate.size(), 1) - 1); break; default: next = toGenerate.getFirst(); break; } - next.generate(counter, type).stream().forEach((r) -> { - toGenerate.add(r); + next.generate(counter, type, greedyMap).stream().forEach((r) -> { + toGenerate.add((Room) r); }); toGenerate.remove(next); - rooms.add(next); + rooms.add(next); } } - + @Override - public String toString(){ + public String toString() { return rooms.stream().map((r) -> r.toLongString() + "\n").reduce("", String::concat); } - + /** * Creates a graph from the dungeon + * * @return UndirectedGraph from JGraphT */ - public UndirectedGraph toGraph(){ - UndirectedGraph g = new SimpleGraph(DefaultEdge.class); + public UndirectedGraph toGraph() { + UndirectedGraph g = new SimpleGraph(DefaultEdge.class); rooms.stream().forEach((r) -> { g.addVertex(r); }); rooms.stream().forEach((r) -> { - for(Exit e : r.exits){ - if(e.isStart || e.room.number == 0 || g.containsEdge(r, e.room)){ + for (Exit e : r.exits) { + if (e.isStart || e.room.number == 0 || g.containsEdge(r, e.room)) { continue; } g.addEdge(r, e.room, e); @@ -104,60 +126,131 @@ public class Dungeon { }); return g; } - + /** * Checks whether a type is natural + * * @param n type to check * @return is natural */ - public static boolean Natural(Type n){ + public static boolean Natural(Type n) { return (n == Type.NATURAL || n == Type.EXP_NATURAL); } - + + /** + * Checks whether a type is experimental + * + * @param n type to check + * @return is experimental + */ + public static boolean Experimental(Type n) { + return (n == Type.EXP_ARTIFICIAL || n == Type.EXP_NATURAL); + } + /** * Different room generation sequence modes */ - public static enum Mode{ + public static enum Mode { /** * FILO - straight dungeon */ STRAIGHT, - /** * FIFO - branched dungeon */ BRANCHED, - /** * Random - balanced dungeon */ RANDOM, } - + /** * The type of rooms to generate */ - public static enum Type{ + public static enum Type { /** * Nature-made rooms */ NATURAL, - /** * "Human"-made rooms */ ARTIFICIAL, - /** * Nature-made rooms in experimental mode */ EXP_NATURAL, - /** * "Human"-made rooms in experimental mode */ EXP_ARTIFICIAL } + + private static HashMap GreedyMap(int size, Type type) { + HashMap expMap = new HashMap(); + if (Experimental(type)) { + double expVal = 1.0 - (1.0 / size); + expMap.put(0, expVal); + int i = 1; + boolean a = true; + int b = 0; + while (expVal >= 1.0 / 20.0 && i <= 20) { + if (expVal >= (3.0 / 20.0)) { + expMap.put(i, 19); + expVal -= (3.0 / 20.0); + } else if (expVal >= 1.0 / 8.0) { + expMap.put(i, a ? 8 : 11); + expVal -= 1.0 / 8.0; + a = !a; + } else if (expVal >= 1.0 / 10.0) { + switch (b) { + case 1: + expMap.put(i, 1); + break; + case 2: + expMap.put(i, 5); + break; + default: + expMap.put(i, 18); + b = 0; + break; + } + expVal -= 1.0 / 10.0; + b++; + } else if (expVal >= 3.0 / 40.0) { + expMap.put(i, 13); + expVal -= 3.0 / 40.0; + } else { + expMap.put(i, 15); + expVal -= 1.0 / 20.0; + } + i++; + } + int c = 0; + while (i <= 20) { + switch (c) { + case 1: + expMap.put(i, 7); + break; + case 2: + expMap.put(i, 10); + break; + default: + expMap.put(i, 20); + c = 0; + break; + } + c++; + i++; + } + } else { + for (int i = 1; i <= 20; i++) { + expMap.put(i, i); + } + } + return expMap; + } } diff --git a/src/dungeon/Room.java b/src/dungeon/Room.java index da6d12b..51a0360 100644 --- a/src/dungeon/Room.java +++ b/src/dungeon/Room.java @@ -23,6 +23,7 @@ */ package dungeon; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import util.Counter; @@ -129,15 +130,16 @@ public class Room { * Generates the content of the room * @param c Room counter * @param type Environment type + * @param map Experimental map * @return Returns more rooms to generate */ - public List generate(Counter c, Dungeon.Type type){ + public List generate(Counter c, Dungeon.Type type, HashMap map){ number = c.Next(); List list = new LinkedList(); for(int i = 0; i < exits.length; i++){ if(exits[i] == null){ Exit predecessor = new Exit(this); - Room newRoom = RandomRoom(false, predecessor, c, type); + Room newRoom = RandomRoom(false, predecessor, c, type, map); exits[i] = new Exit(newRoom, predecessor.type); list.add(newRoom); } @@ -335,16 +337,8 @@ public class Room { } } - private static Room CorridorStraight(Exit predecessor, Counter c){ - return new Room(predecessor, 2, false, "gerader Gang", c); - } - - private static Room CorridorRight(Exit predecessor, Counter c){ - return new Room(predecessor, 2, false, "rechts abbiegender Gang", c); - } - - private static Room CorridorLeft(Exit predecessor, Counter c){ - return new Room(predecessor, 2, false, "links abbiegender Gang", c); + private static Room Corridor(Exit predecessor, Counter c){ + return new Room(predecessor, 2, false, "Gang", c); } private static Room CrossingT(Exit predecessor, Counter c){ @@ -365,16 +359,17 @@ public class Room { * @param predecessor Predecessor room * @param c Room counter * @param type Environment type + * @param map The map for experimental mode * @return random room */ - public static Room RandomRoom(boolean first, Exit predecessor, Counter c, Dungeon.Type type){ + public static Room RandomRoom(boolean first, Exit predecessor, Counter c, Dungeon.Type type, HashMap map){ int number; if(first){ number = Dice.Roll(6, 1); } else { number = Dice.Roll(20, 1); } - switch(number){ + switch(map.get(number)){ case 1: case 2: case 3: return RoomBigExits(predecessor, c, type); @@ -389,9 +384,9 @@ public class Room { case 12: return RoomSmallExitsStair(predecessor, c, type); case 13: case 14: return RoomGiant(predecessor, c, type); - case 15: return CorridorStraight(predecessor, c); - case 16: return CorridorRight(predecessor, c); - case 17: return CorridorLeft(predecessor, c); + case 15: + case 16: + case 17: return Corridor(predecessor, c); case 18: return CrossingT(predecessor, c); case 19: return Crossing(predecessor, c); case 20: return DeadEnd(predecessor, c); diff --git a/src/main/DungeonGeneratorUI.form b/src/main/DungeonGeneratorUI.form index da0ae9b..1faec82 100644 --- a/src/main/DungeonGeneratorUI.form +++ b/src/main/DungeonGeneratorUI.form @@ -75,13 +75,32 @@ - + + + + + + + + + + + + + + + + + + + + @@ -174,7 +193,7 @@ - + @@ -208,7 +227,7 @@ - + diff --git a/src/main/DungeonGeneratorUI.java b/src/main/DungeonGeneratorUI.java index 01afe65..69c7521 100644 --- a/src/main/DungeonGeneratorUI.java +++ b/src/main/DungeonGeneratorUI.java @@ -29,8 +29,10 @@ import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.util.mxCellRenderer; import com.mxgraph.util.mxConstants; import dungeon.Dungeon; +import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; +import java.awt.Desktop; import java.awt.Toolkit; import java.io.File; import java.io.FileWriter; @@ -51,7 +53,11 @@ import org.jgrapht.ext.GmlExporter; import org.jgrapht.ext.JGraphXAdapter; import java.awt.image.BufferedImage; import java.awt.Image; +import java.awt.Label; +import java.net.URI; +import java.net.URISyntaxException; import javax.swing.ImageIcon; +import javax.swing.JFrame; /** * @@ -113,7 +119,9 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { jMenuImage = new javax.swing.JMenuItem(); jMenuClose = new javax.swing.JMenuItem(); jMenuHelp = new javax.swing.JMenu(); - jMenuItem1 = new javax.swing.JMenuItem(); + jMenuItemHelp = new javax.swing.JMenuItem(); + jMenuItemContact = new javax.swing.JMenuItem(); + jMenuItemGithub = new javax.swing.JMenuItem(); jSeparator1 = new javax.swing.JPopupMenu.Separator(); jMenuItemAbout = new javax.swing.JMenuItem(); @@ -137,7 +145,7 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { jPanelSettings.setLayout(new java.awt.GridLayout(4, 2)); jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - jLabel4.setText("Raummaximum"); + jLabel4.setText("Raumanzahl"); jPanelSettings.add(jLabel4); jSpinSize.setModel(new javax.swing.SpinnerNumberModel(1, 1, null, 1)); @@ -146,7 +154,7 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { jPanelSettings.add(jSpinSize); jPanelSettings.add(filler1); - jCheckBoxExp.setText("Experimenteller Modus"); + jCheckBoxExp.setText("\nExperimenteller Modus
\nschränkt Raumzahl nicht direkt ein, sondern ändert die Zufallsfunktion so, dass ihr Erwartungswert der Raumanzahl entspricht"); jCheckBoxExp.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jCheckBoxExpActionPerformed(evt); @@ -265,9 +273,30 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { jMenuHelp.setText("Hilfe"); - jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0)); - jMenuItem1.setText("Hilfe"); - jMenuHelp.add(jMenuItem1); + jMenuItemHelp.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0)); + jMenuItemHelp.setText("Hilfe"); + jMenuItemHelp.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jMenuItemHelpActionPerformed(evt); + } + }); + jMenuHelp.add(jMenuItemHelp); + + jMenuItemContact.setText("Kontakt"); + jMenuItemContact.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jMenuItemContactActionPerformed(evt); + } + }); + jMenuHelp.add(jMenuItemContact); + + jMenuItemGithub.setText("Github"); + jMenuItemGithub.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jMenuItemGithubActionPerformed(evt); + } + }); + jMenuHelp.add(jMenuItemGithub); jMenuHelp.add(jSeparator1); jMenuItemAbout.setText("Über/Lizenz"); @@ -290,8 +319,20 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { }//GEN-LAST:event_jMenuCloseActionPerformed private void jButtonGenerateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonGenerateActionPerformed - mDungeon = new Dungeon((int) jSpinSize.getValue(), SelectedNatural(), SelectedMode()); - + Dungeon.Mode mode = SelectedMode(); + Dungeon.Type type = SelectedNatural(); + int size = (int) jSpinSize.getValue(); + mDungeon = new Dungeon(size, type); + if (false && Dungeon.Experimental(type)) { + JFrame frame = new JFrame("Debug"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + Label lab = new Label(); + lab.setText(mDungeon.GetGreedyMap().toString()); + frame.getContentPane().add(lab, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } + mDungeon.generate(size, type, mode); mGraph = mDungeon.toGraph(); JGraphXAdapter graphAdapter = new JGraphXAdapter(mGraph); mGraphComponent = new mxGraphComponent(graphAdapter); @@ -304,9 +345,9 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { jPanelDraw.add(mGraphComponent); jTextDescription.setText(mDungeon.toString()); - jLabelStatus1.setText("Max: " + jSpinSize.getValue()); - jLabelStatus2.setText("Type: " + SelectedNatural().toString()); - jLabelStatus3.setText("Mode: " + SelectedMode().toString()); + jLabelStatus1.setText("Max: " + size); + jLabelStatus2.setText("Type: " + type.toString()); + jLabelStatus3.setText("Mode: " + mode.toString()); jMenuSave.setEnabled(true); jMenuNew.setEnabled(true); @@ -420,12 +461,12 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { String number = vprops.getString("BUILDNUMBER"); String date = vprops.getString("BUILDDATE"); - JOptionPane.showMessageDialog(this, "DungeonGenerator Version " + number + "\n" - + "(compiled on " + date + ")\n" + JOptionPane.showMessageDialog(this, "DungeonGenerator Version " + number + "\n" + + "(compiled on " + date + ")\n" + "\n" - + "The MIT License (MIT)\n" + + "The MIT License (MIT)\n" + "\n" - + "Copyright (c) 2016 Simon Moser IT\n" + + "Copyright © 2016 Simon Moser IT\n" + "\n" + "Permission is hereby granted, free of charge, to any person\n" + "obtaining a copy of this software and associated documentation\n" @@ -448,13 +489,40 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { + "ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n" + "SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" + "\n" - + "Icons made by Revicon from www.flaticon.com", "Über", JOptionPane.QUESTION_MESSAGE); + + "Icons made by Revicon", "Über", JOptionPane.QUESTION_MESSAGE); }//GEN-LAST:event_jMenuItemAboutActionPerformed private void jCheckBoxExpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxExpActionPerformed - // TODO add your handling code here: + int a = JOptionPane.showConfirmDialog(this, "Diese Option kann zu einer Endlosschleife führen", "Achtung", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); + if (a == JOptionPane.CANCEL_OPTION) { + jCheckBoxExp.setSelected(false); + } }//GEN-LAST:event_jCheckBoxExpActionPerformed + private void jMenuItemContactActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemContactActionPerformed + try { + Desktop.getDesktop().mail(new URI("mailto:info@smoser.eu?subject=DungeonGenerator")); + } catch (URISyntaxException | IOException ex) { + Logger.getLogger(DungeonGeneratorUI.class.getName()).log(Level.SEVERE, null, ex); + } + }//GEN-LAST:event_jMenuItemContactActionPerformed + + private void jMenuItemHelpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemHelpActionPerformed + try { + Desktop.getDesktop().browse(new URI("https://github.com/MrMcX/DungeonGenerator/issues")); + } catch (URISyntaxException | IOException ex) { + Logger.getLogger(DungeonGeneratorUI.class.getName()).log(Level.SEVERE, null, ex); + } + }//GEN-LAST:event_jMenuItemHelpActionPerformed + + private void jMenuItemGithubActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemGithubActionPerformed + try { + Desktop.getDesktop().browse(new URI("https://github.com/MrMcX/DungeonGenerator/")); + } catch (URISyntaxException | IOException ex) { + Logger.getLogger(DungeonGeneratorUI.class.getName()).log(Level.SEVERE, null, ex); + } + }//GEN-LAST:event_jMenuItemGithubActionPerformed + /** * @param args the command line arguments */ @@ -503,13 +571,13 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { } private Dungeon.Type SelectedNatural() { - if(jComboBoxNatural.getSelectedItem().equals("Künstlich")){ - if(jCheckBoxExp.isSelected()){ + if (jComboBoxNatural.getSelectedItem().equals("Künstlich")) { + if (jCheckBoxExp.isSelected()) { return Dungeon.Type.EXP_ARTIFICIAL; } return Dungeon.Type.ARTIFICIAL; } else { - if(jCheckBoxExp.isSelected()){ + if (jCheckBoxExp.isSelected()) { return Dungeon.Type.EXP_NATURAL; } return Dungeon.Type.NATURAL; @@ -535,8 +603,10 @@ public class DungeonGeneratorUI extends javax.swing.JFrame { private javax.swing.JMenu jMenuGraph; private javax.swing.JMenu jMenuHelp; private javax.swing.JMenuItem jMenuImage; - private javax.swing.JMenuItem jMenuItem1; private javax.swing.JMenuItem jMenuItemAbout; + private javax.swing.JMenuItem jMenuItemContact; + private javax.swing.JMenuItem jMenuItemGithub; + private javax.swing.JMenuItem jMenuItemHelp; private javax.swing.JMenuItem jMenuNew; private javax.swing.JMenuItem jMenuSave; private javax.swing.JPanel jPanelCardDraw;