28
/
7/2013

Schlag den REPL

Sind deine Rechenkünste auf der letzten Party auch beschämend missachtet worden? Dann hast du hier das perfekte Trainingsprogramm für nächstes Mal gefunden! Nach einem Duell mit dem REPL bist du sicher bestens vorbereitet.

Das Spiel ist simpel, aber wird mit steigender Rundenzahl immer komplizierter. Nehmen wir beispielsweise die Ziffern 4 und 7 und beginnen bei 1. Reihum muss nun die jeweils nächste Zahl genannt werden, die weder ein Vielfaches von 4 und 7 ist noch die Ziffern 4 und 7 enthält. Jetzt sollten also die Glieder der Folge 1, 2, 3, 5, 6, 9, 10, ... ertönen. Greift einer der Spieler daneben, beginnt er die Folge von vorne.

Zur Beschäftigung des REPLs wird im Trainingsspiel nicht erneut von vorne begonnen, das lässt sich durch das Starten eines neuen Spiels sowieso erzwingen. Der REPL ist mit übermenschlichen Rechenfähigkeiten ausgestattet, was ihn geradezu unbesiegbar (ohne die unrechtmäße Anwendung von Tricks) macht. REPL steht für Read-Evaluate-Print Loop und ist eine interaktive Konsole, die Kommandos entgegennimmt und deren Ergebnisse sofort ausgibt.
Zum Spielen brauchst du also nur die nächste Zahl eingeben und erfährst sofort, ob sie stimmt (siehe unten).

Geschrieben ist das Spiel in der Multiparadigmasprache Scala, die sowohl als funktionale als auch objektorientierte Programmiersprache gilt. Anlass zur Benutzung von Scala hat mir allerdings die bald anstehende Klausur gegeben ;-)
Als echt cool an Scala stellt sich heraus, dass die Sprache eine umfangreiche API besitzt, die einem auch noch durch schlichtes Einfügen des Schlüsselworts par Parallelität geradezu schenkt. Dadurch, dass man die Auswertung von Ausdrücken wirklich bis zum Gebrauch verzögern kann, lassen sich unendliche Datenstrukturen erschaffen. Zum Beispiel ein unendlicher Strom von Zahlen, die nicht durch 4 und 7 teilbar sind und diese beiden Ziffern nicht enthalten.

/* Return an iterator over the infinite stream of valid numbers */
def startMatch: List[Int] => Iterator[Long] = dangerousDigits => {

	/* Create an infinite stream containing only numbers
	** which are not multiples of given dangerousDigits
	** and do not contain these very digits */
	def mathGameStream: List[Int] => Stream[Long] = dangerousDigits => {
	  		
		def streamHelper: Long => List[Int] => Stream[Long] = 
			n => dangerousDigits => {
	  			val next = getNextValidNumber(n)(dangerousDigits)
	  			next #:: streamHelper(next+1)(dangerousDigits)
	  	}

	  	/* Get the next greatest number >= n which meets the constraints */
	  	def getNextValidNumber: Long => List[Int] => Long = 
	  		n => dangerousDigits => {
	  			if (!isDivisible(n)(dangerousDigits) &&
					!containsDigit(n)(dangerousDigits))
						n
	  			else
						getNextValidNumber(n+1)(dangerousDigits)
	  	}
	  
	  	def isDivisible: Long => List[Int] => Boolean = n => divisors => {
	  		(for (divisor <- divisors.par if (n % divisor == 0))
				yield divisor).length != 0
	  	}
	
	  	def containsDigit: Long => List[Int] => Boolean = number => digits => {
	  		(for (d <- digits.par if (number.toString().contains(d.toString())
				)) yield d).length != 0
	  	}
	  
	  	streamHelper(1)(dangerousDigits)
	  }

	  val stream = mathGameStream(dangerousDigits)
	  stream.iterator
}
	
def guessNext: (Iterator[Long], Long) => Boolean = (iterator, guess) => {
	val next = iterator.next()
	if (next == guess)
		true
	else {
		println("Wrong! It was " + next)
		false
	}
}

Ein Spiel mit den Ziffern 4 und 7 lässt sich wie folgt starten:

scala> val iter = startMatch(List[Int](4, 7))
iter: Iterator[Long] = non-empty iterator
scala> guessNext(iter, 1)
res0: Boolean = true
scala> guessNext(iter, 2)
...

Nachdem wir uns einen Iterator über den Stream in iter abgelegt haben, lässt sich die nächste Zahl auch mit iter.next() ausgeben. Allerdings ist dabei zu beachten, dass beim nächsten Rateversuch wiederum die nächste Zahl verlangt ist.

Solltest es dir trotz des unendlichen Stroms an gültigen Zahlen gelingen, den REPL auf diese Weise in die Knie zu zwingen, dann darfst du dich gerne mit einem Kommentar in die Bestenliste eintragen :-P

+

Einen Kommentar hinzufügen

Name: 
eMail*: 
Wie viel ist 1 + 3? 
 

*) Die eMail-Adresse wird nicht veröffentlicht.