Verschiebepuzzle

Status
Nicht offen für weitere Antworten.

Curse4Life

Mitglied
Hi,
ich muss für die Schule ein Verschiebepuzzle programmieren, das ist so, ein Bild wird geladen und das wird dann in 5*5 Teile geteilt, ein Teil wird weggelassen und ist leer und diese Zeile werden dann zufälig angeordnet, so das man das Orgianl wieder zusammenbasteln muss.

Ich habe aber keine Ahnung wie ich das machen soll. ;(
Ich weiß wie man ein Bild anzeigt usw.
Aber wie man das jetzt Splittet ist mir völlig fremd, kann mir einer von euch vielleicht helfen?


mfg
Curse4Life
 
B

Beni

Gast
Zum Splitten:
Mach dir 5*5 BufferedImages (new BufferedImage(..., TYPE_INT_RGB)), generiere für jedes dieser Images ein Graphics-Object (image.getGraphics), und zeichne ein Stücklein deines grossen Bildes mit Hilfe eines solchen Graphics-Object.

Also etwa so:
Code:
Image[][] images = new Image[5][5];
for( int i = 0; i < 5; i++ ){
  for( int j = 0; j < 5; j++ ){
    BufferedImage image = new BufferedImage( ... );
    Graphics g = image.getGraphics();
    g.drawImage( grossesImage, i*..., j*..., ... );
    image[i][j] = image;
  }
}
 

Curse4Life

Mitglied
Erst mal schon vielen lieben Dank, ich bin gerade dabei den Code einzubasteln, noch eine frage, wüsstest du vielleicht noch wie ich den Zufall simulieren könnte?

Die Bilder müssen bei einem neuen Spiel ja durcheinander angezeigt werden und bei jedem Spiel zufällig angeordnet.


mfg
Curse4Life
 

dotlens

Top Contributor
mit Math.random() bekommst du eine zufällige zahl zwischen 0 und 1. das rechnest du * 25, --> 25 Möglichkeiten
dann setzt du die Bilder so an zufällige Orte, musst allerdings beachten, dass nicht 2 am selben ort sein dürfen.
Würde die Zahlen die schon vorkamen in einem Array speichern und dann immer kontrollieren ob der Ort schon besetzt ist...
 

mic_checker

Top Contributor
Oder (wie dotlens geschrieben hat mit Math.random()):
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Math.html#random()

Vielleicht könntest du dir ja auch ein boolean Array anfertigen, wobei du die Elemente auf true setzt wenn das Bild schon da ist, dann musst du nur noch auf den Wert im Array kontrollieren.

Da gibts sicher zig möglichkeiten.
 

Curse4Life

Mitglied
WOW, also nochmal VIELEN Dank für eure reichen Antworten!

Aber, ich muss euch gestehen, ich habe erst heute RICHTIG mit Java begonnen und so ist noch lang nicht alles Gold was glenzt! ;(
Ich komme so von VB(.Net), Delphi usw., deshlab ist Java momentan irgendwie noch so...weit weg, wir sind noch nicht beste Freunde :)

Dehalb, poste ich jetzt mal hier meine Klasse, die ich gebastelt habe und es wäre klasse, wenn ihr die Bugs ausmerzt, was dazu sagt und meine Kommentarfragen, ergenzt.
Wäre euch superdankbar, ich denke dann bin ich wieder was näher an Java gekommen.

Code:
package puzzlemaster;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.math.*;



/**
 * 

Title: ImageSplitter</p>
 *
 * 

Description: Diese Klasse dient zum anzeigen eines Bildes und dann wird es geteilt</p>
 *
 * 

Copyright: Christian N. (c) 2005</p>
 *
 * 

Company: WebTec GbR</p>
 *
 * @author Christian N.
 * @version 1.0
 */
public class ImageSplitter extends JPanel
{
  private Image pic;
  private Image[][] Bilder;
  private Toolkit toolkit;
  private MediaTracker tracker;
  private int Hor_Teile = 0;
  private int Ver_Teile = 0;
  private int Teil_Breit = 0;
  private int Teil_Hoch = 0;
  private boolean[] HatteIchSchon;
  private double ZufallsZahl;

  public ImageSplitter(int Horizontal, int Vertikal)
  {
    Hor_Teile = Horizontal;
    Ver_Teile = Vertikal;
    Bilder = new Image[Hor_Teile][Ver_Teile];
  }


  public void BildSplitten(String Bild)
  {
    toolkit = Toolkit.getDefaultToolkit();
    tracker = new MediaTracker(this);
    pic = toolkit.getImage( Bild );
    tracker.addImage(pic , 0);

    Teil_Breit = pic.getWidth(this) / Hor_Teile;
    Teil_Breit = pic.getHeight(this) / Ver_Teile;

    // Die einzelnden Teile werden in ein BilderArray gespeichert
    for( int i = 0; i < Ver_Teile; i++ )
    {
      for( int j = 0; j < Hor_Teile; j++ )
      {
        BufferedImage image = new BufferedImage(Teil_Breit, Teil_Hoch, TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        g.drawImage(pic, i * Teil_Breit, j * Teil_Hoch, Teil_Breit, Teil_Hoch, this);
        Bilder[i][j] = image;
      }
    }
    
    // Die einzelden Teile werden nun gezeichnet
    for( int i = 0; i < Ver_Teile; i++ )
    {
      for( int j = 0; j < Hor_Teile; j++ )
      {
        ZufallsZahl = Math.random()*25;
        // Bis ich ein noch nicht angezeigtes Bild gefunden habe
        while(HatteIchSchon[(int)ZufallsZahl] == true)
        {
          ZufallsZahl = Math.random()*25;
        }
        // Hier jetzt irgendwie an Position i*Teil_Breit, j*Teil_Hoch
        // Bilder[(int)ZufallsZahl/Ver_Teile][(int)ZufallsZahl%Hor_Teile] auf mein Panel zeichen
        HatteIchSchon[(int)ZufallsZahl] = true;
      }
    }


    try
    {
      tracker.waitForAll();
    }
    catch(InterruptedException e)
    {

    }
  }


  public void paintComponent( Graphics g )
  {
    // Bruache ich das noch?
    //super.paintComponent( g );
    //g.drawImage( pic, 0, 0, this );
  }

}


### Known Bugs ###
1. TYPE_INT_RGB kennt er nicht.


Ich hoffe jemand tut mir diesen wahrlich großen Gefallen.


mfg
Curse4Life
 
B

Beni

Gast
Dann reissen wir diesen Code mal auseinander :-D :wink:
Code:
public class ImageSplitter extends JPanel
{
  private Image pic;
  private Image[][] Bilder;
  private Toolkit toolkit;
  private MediaTracker tracker;
  private int Hor_Teile = 0;
  private int Ver_Teile = 0;
  private int Teil_Breit = 0;
  private int Teil_Hoch = 0;
  private boolean[] HatteIchSchon;
  private double ZufallsZahl;

  public ImageSplitter(int Horizontal, int Vertikal)
  {
    Hor_Teile = Horizontal;
    Ver_Teile = Vertikal;
    Bilder = new Image[Hor_Teile][Ver_Teile];
  }

  public void BildSplitten(String Bild)
  {
Für Java gibt es strenge Codeconventions. Die werden von praktisch allen Programmieren (Ausnahme: Professoren + Lehrer) eingehalten. Daher kann jeder Java-Programmierer relativ leicht den Code eines anderen lesen.

Für nicht konstante Variablen gilt: Name beginnt mit Kleinbuchstaben, und wird mit CamelCase geschrieben (keine "_", sondern Grossbuchstaben im Namen).

Dasselbe gilt für Methoden.

Code:
    toolkit = Toolkit.getDefaultToolkit();
Benötigst du das Toolkit (oder auch zufallsZahl) noch an einem anderen Ort? Sieht nicht so aus, darum sollte "toolkit" keine Instanzvariable, sondern eine Methodenvariable sein. D.h. du kannst Zeile 27 löschen, und hier direkt "Toolkit toolkit = Toolkit.getDefaultToolkit();" hinschreiben.

Code:
    tracker = new MediaTracker(this);
    pic = toolkit.getImage( Bild );
    tracker.addImage(pic , 0);
Die Klasse ImageIO und die Methode ImageIO.read könnten interessant für dich sein. Dann kannst du den MediaTracker weglassen.

Code:
    Teil_Breit = pic.getWidth(this) / Hor_Teile;
    Teil_Breit = pic.getHeight(this) / Ver_Teile;

    // Die einzelnden Teile werden in ein BilderArray gespeichert
    for( int i = 0; i < Ver_Teile; i++ )
    {
      for( int j = 0; j < Hor_Teile; j++ )
      {
        BufferedImage image = new BufferedImage(Teil_Breit, Teil_Hoch, TYPE_INT_RGB);
In Java gibt es keine globalen Variablen (bzw. Konstanten), deshalb ist TYPE_INT_RGB hier unbekannt.
Als "Ersatz" gibt es sog. statische Variablen (und Konstanten), man spricht diese Werte über die Klasse an, in der sie definiert sind: "new BufferedImage( teilBreit, teilHoch, BufferedImage.TYPE_INT_RGB );"
Code:
        Graphics g = image.getGraphics();
        g.drawImage(pic, i * Teil_Breit, j * Teil_Hoch, Teil_Breit, Teil_Hoch, this);
        Bilder[i][j] = image;
      }
    }
Code:
    // Die einzelden Teile werden nun gezeichnet
    for( int i = 0; i < Ver_Teile; i++ )
    {
      for( int j = 0; j < Hor_Teile; j++ )
      {
        ZufallsZahl = Math.random()*25;
        // Bis ich ein noch nicht angezeigtes Bild gefunden habe
        while(HatteIchSchon[(int)ZufallsZahl] == true)
        {
          ZufallsZahl = Math.random()*25;
        }
        // Hier jetzt irgendwie an Position i*Teil_Breit, j*Teil_Hoch
        // Bilder[(int)ZufallsZahl/Ver_Teile][(int)ZufallsZahl%Hor_Teile] auf mein Panel zeichen
        HatteIchSchon[(int)ZufallsZahl] = true;
      }
    }
Das wird schon funktionieren (hoff ich mal, habs nicht ausprobiert), aber rein theoretisch könnte es passieren, dass bei unglücklichen Zufallszahlen hier ziemlich lange herumgewürfelt wird.
Ein alternativer Algorithmus: Ein Array mit den Zahlen 1 - 25. Nun wird ein Index zufällig erzeugt. Die Zahl an dieser Stelle wird mit der Zahl die an der letzten gültigen Position des Arrays steht vertauscht, und die Anzahl gülter Positionen um 1 verringert. Nun wird der nächste Index gezogen... (nun nicht mehr "Math.random()*25" sondern "Math.random()*(25-1)")
Code:
    try
    {
      tracker.waitForAll();
    }
    catch(InterruptedException e)
    {

    }
  }


  public void paintComponent( Graphics g )
  {
    // Bruache ich das noch?
    //super.paintComponent( g );
    //g.drawImage( pic, 0, 0, this );
  }

}
Hm, du willst ja die einzelnen Bilder im bilderArray zeichen. Die Methode "paintComponent" brauchst du also schon noch, nur der Inhalt sieht anders aus.

Hoffe das hilft dir weiter.
 

Curse4Life

Mitglied
Wieder einmal danke :)
Sich an die ganzen Konventionen halten wird was schwer, da ich schon Jahre über anders progge...


Aber zwei Fragen sind offen geblieben:
1) Was muss ich für folgendes schreiben?
Code:
// Hier jetzt irgendwie an Position i*Teil_Breit, j*Teil_Hoch 
// Bilder[(int)ZufallsZahl/Ver_Teile][(int)ZufallsZahl%Hor_Teile] auf mein Panel zeichen

2) Und was muss genau in PaintComponent?


mfg
Curse4Life
 

mic_checker

Top Contributor
Curse4Life hat gesagt.:
Code:
        BufferedImage image = new BufferedImage(Teil_Breit, Teil_Hoch, TYPE_INT_RGB);

Code:
BufferedImage image = new BufferedImage(Teil_Breit, Teil_Hoch,BufferedImage.TYPE_INT_RGB);


edit: ui, hab ganz übersehen das Beni das schon geschrieben hat - sorry ;)
 
B

Beni

Gast
Curse4Life hat gesagt.:
Aber zwei Fragen sind offen geblieben:
1) Was muss ich für folgendes schreiben?
Code:
// Hier jetzt irgendwie an Position i*Teil_Breit, j*Teil_Hoch 
// Bilder[(int)ZufallsZahl/Ver_Teile][(int)ZufallsZahl%Hor_Teile] auf mein Panel zeichen

2) Und was muss genau in PaintComponent?

Ich sehe kein Unterschied in den Fragen? :bahnhof:

PaintComponent muss in etwa so aussehen:
Code:
for( int i = 0; i < bilderArray.length; i++ ){
  for( int j = 0; j < bilderArray[i].length; j++ )
    g.drawImage( i*teilchenBreite, j*teilchenHöhe, bilderArray[i][j], this );
}
Da wird einfaches jedes Bildteilchen neben dem anderen hingezeichnet.
 
Status
Nicht offen für weitere Antworten.

Oben