add ipi9
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
#include <string>
|
||||
|
||||
struct BoundaryCondition
|
||||
{
|
||||
virtual bool boundary(Board& board, int i, int j) = 0;
|
||||
};
|
||||
|
||||
class Board {
|
||||
public :
|
||||
// Konstruktor, erzeuge bool* _fields
|
||||
Board(int width, int height, BoundaryCondition cond);
|
||||
|
||||
// Desktruktor, raeume bool* _fields auf
|
||||
~Board();
|
||||
|
||||
// copy constructor, intializes by copying from 'other'
|
||||
Board(Board& other);
|
||||
|
||||
// assignment operator
|
||||
Board& operator=(Board& other);
|
||||
|
||||
// gibt die Breite des Bretts zurueck
|
||||
double width();
|
||||
|
||||
// gibt die Hoehe des Bretts zurueck
|
||||
double height();
|
||||
|
||||
// schreibe value an den Pixel (i,j)
|
||||
// Ueberlegen Sie wie aus (i,j) den flachen Index bei row-major bekommen
|
||||
void updateField(int i, int j, bool value);
|
||||
|
||||
// Zugang zum Pixel (i,j) im 1D Array
|
||||
// Ueberlegen Sie wie aus (i,j) den flachen Index bei row-major bekommen
|
||||
int operator()(int i, int j);
|
||||
|
||||
// Gibt zurueck ob Feld am Rand liegt
|
||||
bool touchesBoundary(int i, int j);
|
||||
|
||||
// Gibt Zahl der lebenden Zellen zurueck, die das Feld umgeben
|
||||
int livingCells(int i, int j);
|
||||
|
||||
// Prueft ob Zelle lebt oder nicht
|
||||
bool isLiving(int i, int j);
|
||||
|
||||
// Gibt die BoundaryCondition zurueck
|
||||
BoundaryCondition boundaryCondition();
|
||||
|
||||
private :
|
||||
int _width;
|
||||
int _height;
|
||||
bool* _fields;
|
||||
void copy(Board& other);
|
||||
BoundaryCondition _boundCond;
|
||||
};
|
||||
|
||||
Board::Board(int width, int height, BoundaryCondition cond) {
|
||||
// initialize all values
|
||||
_width = width;
|
||||
_height = height;
|
||||
_boundCond = cond;
|
||||
_fields = new bool[width * height];
|
||||
}
|
||||
|
||||
Board::~Board() {
|
||||
_fields = 0;
|
||||
}
|
||||
|
||||
void Board::copy(Board& other) {
|
||||
_width = other.width();
|
||||
_height = other.height();
|
||||
_boundCond = other.boundaryCondition();
|
||||
_fields = new bool[_width * _height];
|
||||
for (int i = 0; i < _height; i++) {
|
||||
for (int j = 0; j < _width; j++) {
|
||||
updateField(i, j, other.isLiving(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Board::Board(Board& other) {
|
||||
copy(other);
|
||||
}
|
||||
|
||||
Board& Board::operator=(Board& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
double Board::width() {
|
||||
return _width;
|
||||
}
|
||||
|
||||
double Board::height() {
|
||||
return _height;
|
||||
}
|
||||
|
||||
BoundaryCondition Board::BoundaryCondition() {
|
||||
return _boundCond;
|
||||
}
|
||||
|
||||
void Board::updateField(int i, int j, bool value) {
|
||||
// i = Zeile und wegen row-major Konvention muss i mit der Breite
|
||||
// multipliziert werden
|
||||
_fields[i * _width + j] = value;
|
||||
}
|
||||
|
||||
bool Board::touchesBoundary(int i, int j) {
|
||||
return i == _height - 1 || i == -1 || j == _width - 1 || j == -1;
|
||||
}
|
||||
|
||||
int Board::livingCells(int i, int j) {
|
||||
bool surround[8] = { isLiving(i+1, j+1), isLiving(i, j+1), isLiving(i-1, j+1)
|
||||
, isLiving(i+1, j), isLiving(i-1, j)
|
||||
, isLiving(i+1, j-1), isLiving(i, j-1), isLiving(i-1, j-1)};
|
||||
int numLiving = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (surround[i] == true) {
|
||||
numLiving += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Board::isLiving(int i, int j) {
|
||||
if (touchesBoundary(i, j)) {
|
||||
return _boundCond.boundary(i, j);
|
||||
} else {
|
||||
return _fields[i * _width + j];
|
||||
}
|
||||
}
|
||||
|
||||
int Board::operator()(int i, int j) {
|
||||
// i = Zeile und wegen row-major Konvention muss i mit der Breite
|
||||
// Pixel multipliziert werden
|
||||
return _fields[i * _width+ j];
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#include <string>
|
||||
#include "pgm.hh"
|
||||
|
||||
// Komplexe Zahl
|
||||
struct Complex
|
||||
{
|
||||
double real;
|
||||
double imag;
|
||||
};
|
||||
|
||||
class Canvas
|
||||
{
|
||||
public :
|
||||
// Konstruktor, erzeuge int* _pixels
|
||||
Canvas(double center_x, double center_y,
|
||||
double width, double height,
|
||||
int horPixels, int vertPixels);
|
||||
|
||||
// Desktruktor, raeume int* _pixels auf
|
||||
~Canvas();
|
||||
|
||||
// gibt die Breite des Bildes zurueck
|
||||
double width();
|
||||
|
||||
// gibt die Hoehe des Bildes zurueck
|
||||
double height();
|
||||
|
||||
// gibt die Anzahl an horizontalen Pixeln
|
||||
int horPixels();
|
||||
|
||||
// gibt die Anzahl an vertikalen Pixeln
|
||||
int vertPixels();
|
||||
|
||||
// gebe die Koordinaten des Pixels (i,j) als Complex zurueck
|
||||
Complex coord(int i, int j);
|
||||
|
||||
// schreibe value an den Pixel (i,j)
|
||||
// Ueberlegen Sie wie aus (i,j) den flachen Index bei row-major bekommen
|
||||
void writePixel(int i, int j, int value);
|
||||
|
||||
// Zugang zum Pixel (i,j) im 1D Array
|
||||
// Ueberlegen Sie wie aus (i,j) den flachen Index bei row-major bekommen
|
||||
int operator()(int i, int j);
|
||||
|
||||
// schreibe Bild mit Dateinamen filename
|
||||
void write(std::string filename);
|
||||
private :
|
||||
double _center_x;
|
||||
double _center_y;
|
||||
double _width;
|
||||
double _height;
|
||||
int _horPixels;
|
||||
int _vertPixels;
|
||||
int* _pixels;
|
||||
};
|
||||
|
||||
// diese Methode ist bereits implementiert
|
||||
void Canvas::write(std::string filename)
|
||||
{
|
||||
write_pgm(_pixels,_horPixels,_vertPixels,filename);
|
||||
}
|
||||
|
||||
Canvas::Canvas(double center_x, double center_y, double width, double height, int horPixels,
|
||||
int vertPixels) {
|
||||
// initialize all values
|
||||
_center_x = center_x;
|
||||
_center_y = center_y;
|
||||
_width = width;
|
||||
_height = height;
|
||||
_horPixels = horPixels;
|
||||
_vertPixels = vertPixels;
|
||||
_pixels = new int[horPixels * vertPixels];
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
_pixels = 0;
|
||||
}
|
||||
|
||||
double Canvas::width() {
|
||||
return _width;
|
||||
}
|
||||
|
||||
double Canvas::height() {
|
||||
return _height;
|
||||
}
|
||||
|
||||
int Canvas::horPixels() {
|
||||
return _horPixels;
|
||||
}
|
||||
|
||||
int Canvas::vertPixels() {
|
||||
return _vertPixels;
|
||||
}
|
||||
|
||||
Complex Canvas::coord(int i, int j) {
|
||||
Complex c;
|
||||
// Bringe die Pixel mit den echten Laengen ins Verhaeltnis
|
||||
double y = i * (_height / _vertPixels) - _height / 2;
|
||||
double x = j * (_width / _horPixels) - _width / 2;
|
||||
// Gebe die Koordinaten in Relation zum gewuenschten Zentrum aus
|
||||
c.imag = y + _center_y;
|
||||
c.real = x + _center_x;
|
||||
return c;
|
||||
}
|
||||
|
||||
void Canvas::writePixel(int i, int j, int value) {
|
||||
// i = Zeile und wegen row-major Konvention muss i mit der Zahl der horizontalen
|
||||
// Pixel multipliziert werden
|
||||
_pixels[i*_horPixels + j] = value;
|
||||
}
|
||||
|
||||
int Canvas::operator()(int i, int j) {
|
||||
// i = Zeile und wegen row-major Konvention muss i mit der Zahl der horizontalen
|
||||
// Pixel multipliziert werden
|
||||
return _pixels[i*_horPixels + j];
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
#include <iostream>
|
||||
#include <unistd.h> // needed for usleep
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "board.hh"
|
||||
|
||||
// Basisklassen
|
||||
struct Regel
|
||||
{
|
||||
virtual void anwenden(Board& board) = 0;
|
||||
};
|
||||
|
||||
class TorusCondition : public BoundaryCondition
|
||||
{
|
||||
bool boundary(Board& board, int i, int j) {
|
||||
if (i == board.height() - 1) {
|
||||
return board.isLiving(0, j);
|
||||
} else if (i == -1) {
|
||||
return board.isLiving(board.height() - 1, j);
|
||||
} else if (j == board.width() - 1) {
|
||||
return board.isLiving(i, 0);
|
||||
} else if (j == -1) {
|
||||
return board.isLiving(i, board.width() - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AliveCondition : public BoundaryCondition
|
||||
{
|
||||
bool boundary(Board& board, int i, int j) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class DeadCondition : public BoundaryCondition
|
||||
{
|
||||
bool boundary(Board& board, int i, int j) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class GameOfLifeRules : public Regel
|
||||
{
|
||||
public :
|
||||
//void anwenden(Board& board) {
|
||||
// // copy new board from old board
|
||||
// Board updated = Board(board.width(), board.height());
|
||||
// for (int i = 0; i < board.height(); i++) {
|
||||
// for (int j = 0; i < board.width(); i++) {
|
||||
// int n = board.livingCells(i, j);
|
||||
// int self = board.isLiving(i, j);
|
||||
// if (self && n < 2) {
|
||||
// updated.updateField(i, j, false);
|
||||
// } else if (!self && n == 3) {
|
||||
// updated.updateField(i, j, true);
|
||||
// } else if (self && n > 3) {
|
||||
// updated.updateField(i, j, false);
|
||||
// } else {
|
||||
// updated.updateField(i, j, self);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// board = updated;
|
||||
//}
|
||||
};
|
||||
|
||||
// Ein zellulaerer Automat, der Regeln und Datenstrukturen von aussen bekommt
|
||||
class Automat
|
||||
{
|
||||
public :
|
||||
// der Datentyp fuer das 2D Bool Array
|
||||
Automat(Board& board, Regel& regel)
|
||||
: _board(board)
|
||||
, _regel(regel)
|
||||
{}
|
||||
|
||||
// mache n Schritte
|
||||
void doSteps(int n=1)
|
||||
{
|
||||
for (int i=0; i<n; ++i)
|
||||
{
|
||||
// Linux-spezifische Art und Weise den Inhalt der Konsole zu loeschen
|
||||
// und den Cursor nach oben links zu setzen.
|
||||
//std::cout << "\x1B[2J\x1B[H" << "Step " << i << std::endl << _board;
|
||||
// Das Wiedergeben der Loesung soll immer 10 Sekunden (=1e7 Mikrosekunden)
|
||||
// dauern. Sie koennen diesen Wert auch aendern.
|
||||
usleep(1.e7/n);
|
||||
//_regel.anwenden(_board);
|
||||
}
|
||||
}
|
||||
|
||||
private :
|
||||
Board& _board;
|
||||
Regel& _regel;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cout << "Usage: ./<progname> <txt-file>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Board board = Board(2, 2, AliveCondition);
|
||||
board.updateField(1,1, true);
|
||||
board.livingCells(1,1);
|
||||
|
||||
// Initialisiere Datenstruktur des 2D Bool Array
|
||||
// TODO
|
||||
// Ueberlegen Sie sich wie Sie einen Startzustand in das 2D Bool Array bekommen
|
||||
// Lesen Sie ggf.
|
||||
// (1) eine solche Textdatei mittels Filestream ein
|
||||
// (2) ueberladen Sie Operatoren operator<< oder operator>>
|
||||
|
||||
// TODO
|
||||
// - legen Sie eine Instanz der Randbedingung an
|
||||
// - legen Sie eine Instanz des Regelsystems an
|
||||
// - Initialisieren Sie den zellulaeren Automaten
|
||||
|
||||
// Experimentieren Sie hier mit Ihrem Automaten
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
\documentclass[uebung]{../../../lecture}
|
||||
|
||||
\title{IPI: Übungsblatt 9}
|
||||
\author{Samuel Weidemaier, Christian Merten}
|
||||
|
||||
\usepackage[]{listings}
|
||||
|
||||
\usepackage{xcolor}
|
||||
|
||||
\lstdefinestyle{mystyle}{
|
||||
commentstyle=\color{gray},
|
||||
language=C++,
|
||||
keywordstyle=\color{blue},
|
||||
numberstyle=\tiny\color{gray},
|
||||
stringstyle=\color{black},
|
||||
basicstyle=\ttfamily\footnotesize,
|
||||
breakatwhitespace=false,
|
||||
breaklines=true,
|
||||
captionpos=b,
|
||||
keepspaces=true,
|
||||
numbers=left,
|
||||
numbersep=5pt,
|
||||
showspaces=false,
|
||||
showstringspaces=false,
|
||||
showtabs=false,
|
||||
tabsize=2
|
||||
}
|
||||
|
||||
\lstset{style=mystyle}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\begin{aufgabe}[Mandelbrot-Menge]
|
||||
(a) und (b) siehe \textit{mandelbrot.cc} und \textit{canvas.hh}.
|
||||
|
||||
(c) Je höher \lstinline{threshold}, desto heller wird das Bild, allerdings ist bereits zwischen 100 und 1000
|
||||
kein großer Unterschied mehr zu erkennen. Bei sehr kleinen \lstinline{threshold}s werden die Randbereiche
|
||||
wieder schwarz.
|
||||
|
||||
Bei geringen \lstinline{maxIt}s ist die Genauigkeit sehr gering, je höher desto feiner wird das Bild.
|
||||
Allerdings ist auch hier zwischen 100 und 1000 bereits kein Unterschied mehr zu erkennen.
|
||||
\end{aufgabe}
|
||||
|
||||
\end{document}
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
// Datentyp Complex in der Datei canvas.hh
|
||||
#include "canvas.hh"
|
||||
|
||||
// Summiert zwei komplexe Zahlen z und c und schreibt das Ergebnis in z
|
||||
void add_complex(Complex& z, Complex& c) {
|
||||
z.real += c.real;
|
||||
z.imag += c.imag;
|
||||
}
|
||||
|
||||
// Multipliziert zwei komplexe Zahlen z und c und schreibt das Ergebnis in z
|
||||
void multiply_complex(Complex& z, Complex& c) {
|
||||
double re = z.real*c.real - z.imag*c.imag;
|
||||
double im = z.real*c.imag + z.imag*c.real;
|
||||
z.real = re;
|
||||
z.imag = im;
|
||||
}
|
||||
|
||||
// Betrag einer komplexen Zahl
|
||||
double betrag(Complex z)
|
||||
{
|
||||
return std::sqrt(std::pow(z.real, 2) + std::pow(z.imag, 2));
|
||||
}
|
||||
|
||||
// Generiert die Mandelbrot Menge und speichert sie in canvas mit threshold als Entfernung, ab dem
|
||||
// ein Punkt ,,entkommt'', mit maxIt als maximale Anzahl an Iterationen, die für
|
||||
// die Folge durchgeführt werden soll. Wird als PGM Bild unter filename gespeichert
|
||||
void mandelbrot(Canvas& canvas, double threshold, int maxIt, std::string filename) {
|
||||
for (int i = 0; i < canvas.vertPixels(); i++) {
|
||||
for (int j = 0; j < canvas.horPixels(); j++) {
|
||||
Complex c = canvas.coord(i, j);
|
||||
Complex z;
|
||||
z.real = 0;
|
||||
z.imag = 0;
|
||||
int neededIterations = -1;
|
||||
for (int k = 1; k <= maxIt; k++) {
|
||||
multiply_complex(z, z);
|
||||
add_complex(z, c);
|
||||
if (betrag(z) > threshold) {
|
||||
neededIterations = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (neededIterations == -1) {
|
||||
canvas.writePixel(i, j, 0);
|
||||
} else {
|
||||
canvas.writePixel(i, j, std::log(neededIterations)*100);
|
||||
}
|
||||
}
|
||||
}
|
||||
canvas.write(filename);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Canvas canvas = Canvas(-1, 0, 4, 3, 4000, 3000);
|
||||
mandelbrot(canvas, 1000, 10000, "mandelbrot.pgm");
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
|
||||
void write_pgm(int* pixels, int horPixels, int vertPixels, std::string filename)
|
||||
{
|
||||
if(horPixels == 0 || vertPixels == 0)
|
||||
{
|
||||
std::cerr << "Leeres Pixel Array" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// write file
|
||||
// unfortunately we cannot use C++-11 which would simplify our life in that case
|
||||
std::ofstream outfile;
|
||||
outfile.open(filename.c_str());
|
||||
|
||||
outfile << "P2" << std::endl
|
||||
<< horPixels << " " << vertPixels << std::endl;
|
||||
|
||||
// renormalize if necessary
|
||||
int maxVal = 0;
|
||||
for(int entry=0; entry<horPixels*vertPixels; entry++)
|
||||
maxVal = std::max(pixels[entry],maxVal);
|
||||
|
||||
// renormalizing output
|
||||
if(maxVal > 65535)
|
||||
{
|
||||
outfile << 65535 << std::endl;
|
||||
for(int j=0, entry=0; j<vertPixels; j++)
|
||||
{
|
||||
for(int i=0; i<horPixels; i++, entry++)
|
||||
{
|
||||
if(pixels[entry] < 0)
|
||||
{
|
||||
std::cerr << "Negativer Eintrag bei (" << i << ", " << j << ")" << std::endl;
|
||||
return;
|
||||
}
|
||||
outfile << std::floor(pixels[entry] * (65535./maxVal)) << " ";
|
||||
}
|
||||
outfile << std::endl;
|
||||
}
|
||||
}
|
||||
// normal output
|
||||
else
|
||||
{
|
||||
outfile << maxVal << std::endl;
|
||||
for(int j=0; j<vertPixels; j++)
|
||||
{
|
||||
for(int i=0; i<horPixels; i++)
|
||||
{
|
||||
int entry = i + horPixels*(vertPixels-1-j);
|
||||
if(pixels[entry] < 0)
|
||||
{
|
||||
std::cerr << "Negativer Eintrag bei (" << i << ", " << j << ")" << std::endl;
|
||||
return;
|
||||
}
|
||||
outfile << pixels[entry] << " ";
|
||||
}
|
||||
outfile << std::endl;
|
||||
}
|
||||
}
|
||||
outfile.close();
|
||||
}
|
||||
Reference in New Issue
Block a user