C :: Aufgabe #150

1 Lösung Lösung öffentlich

Der Leidensweg eines Betrunkenen durch einen Tunnel

Anfänger - C von hollst - 07.03.2017 um 09:40 Uhr
Ein leicht angetrunkener Mann muss für seinen Nachhauseweg durch einen Tunnel der Länge L (z. B. = 10 m)
und der Breite B (z. B. = 5.5 m). Zum Glück ist der Tunnel mit quadratischen Terrazzoplatten ausgelegt, nach denen
er sich zu richten versucht. Die Platten haben eine Gräße von 0.5 x 0.5 m². Somit besteht der Weg aus hier z. B. 20 Reihen a 11 Platten.

Der Mann startet in der ersten Reihe auf der Mittelplatte. Er möchte durch den Tunnel gehen, indem er bei jedem
Schritt auf eine benachbarte Platte tritt. Leider hat er in seinem Zustand völlig die Richtungsorientierung verloren,
so dass sein Schritt rein zufällig in eine der acht möglichen Richtungen verläuf, unabhängig davon,
dass zwei Wände links und rechts den Weg versperren. Wenn der Mann gegen eine der Wände läuft, gilt sein Versuch
den Tunnes zu durchlaufen als gescheitert, da er bewußtlos zu Boden stürzt und liegen bleibt. Als gescheiterter Versuch gilt auch,
wenn sein Weg ihn nicht zum Tunnelausgang, sondern nach einigen Schritten oder schon bereits beim ersten zurück vor den Eingang führt.

Die Frage lautet: Wie groß ist die Wahrscheinlichkeit dafür, dass er den Tunnel mit einem einzigen Versuch schadlos durchquert?
Die Wahrscheinlichkeit (Erwartungswert) soll anhand genügend vielen Simulationen abgeschätzt werden.

Lösungen:

vote_ok
von devnull (8870 Punkte) - 10.03.2017 um 09:16 Uhr

Konsolenausgabe:

Anzahl gesamt : 100000000
Fehlversuche : 99857883
Erfolgsfälle : 142117
Erfolgsrate : 0.1421%

Quellcode ausblenden C-Code
/*****************************************
 * random_tunnel.c   Zufallsweg im Tunnel
 *****************************************/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <limits.h>
#include <stdbool.h>

#define	MAX_TRIALS	    UINT_MAX
#define PRINT_LOOP		10000000

#define BORDER_WEST     0
#define BORDER_NORTH    0
#define BORDER_EAST    19
#define BORDER_SOUTH   10
#define START_X			0
#define START_Y			5


/* random seed generator */
int init_random_seed(void) {
  return open("/dev/urandom", O_RDONLY);
}

void get_random_seed(int urandom_fd, unsigned int *seed) {
  struct timespec tsp;

  if (urandom_fd > 0) {
	/* get seed from the urandom device */
	read(urandom_fd, seed, sizeof(unsigned int));
  }
  else {
	/* get seed from the RTC */
	clock_gettime(CLOCK_MONOTONIC, &tsp);
	tsp.tv_nsec >>= (sizeof(long) - sizeof(unsigned int))*CHAR_BIT;
	*seed = (unsigned int)tsp.tv_nsec;
  }
}

/* main */
int main(int argc, char **argv) {
	unsigned int total, total_fail, total_succ;
	unsigned int t, tmax, seed_val;
	int direction, seed_rc;
	int x, y;
	bool fail, success;

	tmax = MAX_TRIALS;
	if (argc > 1)
		tmax = (unsigned)atoi(argv[1]);

	printf("Anzahl Versuche: %u\n", tmax);
	total_succ=total_fail=total=0;

	seed_rc = init_random_seed();

	for (t=1; t<=tmax; t++) {
		success=fail=false;

		get_random_seed(seed_rc, &seed_val);
		srand(seed_val);

		x = START_X;
		y = START_Y;
		total++;
		do {
			direction = (int)(8L*rand()/RAND_MAX);
			switch (direction) {
			case 0:	++x;      break;   /* E  */
			case 1:	++x; --y; break;   /* NE */
			case 2: --y;      break;   /* N  */
			case 3: --x; --y; break;   /* NW */
			case 4:	--x;      break;   /* W  */
			case 5: --x; ++y; break;   /* SW */
			case 6: ++y;      break;   /* S  */
			case 7: ++x; ++y; break;   /* SE */
			}
			if (x <= BORDER_WEST || y < BORDER_NORTH || y > BORDER_SOUTH)
				fail = true;
			else if (x > BORDER_EAST)
				success = true;
		} while (!(fail || success));
		if (fail)
			total_fail++;
		if (success)
			total_succ++;
		if (t%PRINT_LOOP == 0)
			fprintf(stderr, "%u\n", t);
	}
	printf("Anzahl gesamt : %u\n", total);
	printf("Fehlversuche  : %u\n", total_fail);
	printf("Erfolgsfälle  : %u\n", total_succ);
	printf("Erfolgsrate   : %6.4f%%\n", 100.*total_succ/total);
	return 0;
}