Analoger Computer für Kinder: Turing Tumble

Heutige Computer verbringen ja teilweise wirklich Wunderwerke. Sie rendern Filme, wie der neue Film König der Löwen , lassen uns in realistische 3D Spielewelten eintauchen, lenken Autos, erkennen Krankheiten und ermöglichen uns globale Kommunikation. Doch hinter all dem steckt jeweils immer eine CPU, also eine zentrale datenverarbeitende Steuerelektronik.

Trotz der Komplexität, die diese beherrschen, basieren alle Operationen der CPU lediglich auf simple Manipulationen von Registern in Abhängigkeit von dem aktuellen Zustand. Erst die intelligente Aneinandereihung dieser simplen Operationen gibt dem Ganzen die nötige Komplexität. Diese Operationen müssen nicht zwingend elektrisch realisiert werden, wie in einer CPU. Sie können durchaus auch in anderer Form analog realisiert werden. Zum Beispiel gibt es die mechanische Form der Turing Maschine.


Beim Stöbern im Internet nach mechanischen Turing Maschinen, bin ich auf das Kickstarter Projekt Turing Tumble gestossen. Es bietet einen analogen Computer als Kugelbahn an. Da die Kinder sowieso viel vor ihren Tablets sitzen, Mobilgeräte ja prinzipiell böse sind und wir als Eltern auch nicht gerade mit gutem Beispiel vorran gehen, habe ich uns diese Maschine gekauft, in der Hoffnung den Kindern ein wenig die Grundlage von Computern anhand dieser Kugelbahnmaschine visuell näher bringen zu können.

Die Maschine besteht dabei aus einem Brett mit elf herausragenden Stäbchen in einer Reihe und davon gibt es wiederrum elf Reihen untereinander. An jedes zweite Stäbchen kann eines der folgenden Operatoren gesteckt werden und bilden damit die Worte des analogen Computers. Von oben können jeweils von links oder von rechts eine Kugel in das Brett fallen und je nach Operatorenanordnung das Brett bis zum unteren Ende passieren. Dort gelangen sie je nach der auftreffenden Seite auf einen Hebel. Dieser Hebel lässt beim Betätigen wieder eine Kugel abhängig von seiner Seite von oben herabkullern. Dies geht so lange, bis keine neue Kugel mehr von oben einen der zwei Hebel betätigt oder es keine Kugel mehr oben gibt. Die Kugel kann man mit einem Stromfluss vergleichen.

Der einfachste Operator ist die Rampe. Fällt eine Kugel von oben hinein, so wird sie je nach Einbaurichtung nach links oder rechts weitergeleitet. Dies kann man analog mit einem Stromleiter, wie einen Drahtleitung vergleichen

Dieser Operator ist eine Kreuzung. So könne zwei Leitungen gekreuzt werden. Fällt eine Kugel von links oben hinein, so verlässt sie diese wieder nach rechts unten. Kommt sie von rechts oben, so verlässt die Kugel nach links unten die Kreuzung.

Das Bit ist ein Operator, der eine Ausrichtung hat. Diese wird mit einem Pfeil, je nach Ausrichtung nach links oder nach rechts angezeigt.Zeigt der Pfeil nach links, so läuft die nächste vorbeirollende Kugel unabhängig, von wo sie von oben herkommt nach rechts unten weiter. Ist der Pfeil nach rechts ausgerichtet, so läuft die nächste Kugel nach links unten weiter. Nach jedem Kugeldruchlauf ändert der Bit Operator seine Pfeilrichtung. Die Pfeilrichtung des Bits nennt man auch Zustand.

Damit ein ablaufendes Programm gestoppt werden kann, gibt es den Stopper. Dieser fängt ganz einfach die herabrollende Kugel auf und es kann keine weitere mehr mit den Hebeln aktiviert werden.

Ähnlich dem Bit Operator gibt es diesen noch in der Form mit einem Zahnrad darauf, das Zanradbit. Die Funktionalität  entspricht genu der des Bit Operators. Zusätzlich kann aber ein Zahnrad damit angetrieben (siehe unten) werden. Über das Zahnrad kann wieder ein weiteres Zahnradbit angesteuert werden. Damit ist es möglich den Zustand eines Zahnradbits an einer anderen Stellen, wo die Kugel gerade nicht vorbeirollt zu verändern. Mit dieser Konstruktion können sogenannte „Wenn … Dann…“-Operationen (Fallunterscheidungen) realisierte werden, die im Computer Bereich sehr wichtig sind.

Mit dem Zahnrad Operator können weitere Zahnräder oder Zahnradbits verbunden werden. Somit können Zustände über weite Entfernungen auf dem Brett verändert werden.

Einige Beispiele, wie man nun damit Funktionen einer CPU beschreiben kann sind in einem Educator Guide beschrieben. Um mit diesem System etwas spielen zu können, ist es nicht notwendig sich eines anzuschaffen. Im Internet findet man zahlreiche Simulatoren dafür, die auch im Browser laufen. Unten haben ich einen eigenen simplen Turing Tumble Simulator in Python geschrieben, damit ich etwas in diese Skriptsprache hineinkomme.

#!/usr/bin/python3
#------------------------------------------------------------------------------
# Python 3.4.3
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# includes
#------------------------------------------------------------------------------
import os
import sys 
#------------------------------------------------------------------------------
# definitions
#------------------------------------------------------------------------------
lineLength       = 11
lineCnt          = 11
sign_non         = '.'
sign_space       = 'o'
sign_rampL       = 'L'
sign_rampR       = 'R'
sign_crossover   = 'X'
sign_bitL        = '<' sign_bitR = '>'
sign_interceptor = '-'
sign_gear        = '*'
sign_gearBitL    = '('
sign_gearBitR    = ')'
#------------------------------------------------------------------------------
# classes
#------------------------------------------------------------------------------
class Ball :
  ballOldPosX = 0
  ballOldPosY = 0
  ballActPosX = 0
  ballActPosY = 0
  ballColor = 'b'
  def __init__(self,x,y,comesFrom = 'r',ballColor = 'b') :
    self.setNewPos(x,y)
    self.ballColor = ballColor
    if comesFrom == 'r' :
      self.ballOldPosX = lineLength
  def setNewPos(self,x,y) :
    self.ballOldPosX = self.ballActPosX
    self.ballOldPosY = self.ballActPosY
    self.ballActPosX = x
    self.ballActPosY = y
  def nextD(self) :
    self.setNewPos(self.ballActPosX,self.ballActPosY+1)
  def nextLD(self) :
    self.setNewPos(self.ballActPosX-1,self.ballActPosY+1)
  def nextRD(self) :
    self.setNewPos(self.ballActPosX+1,self.ballActPosY+1)
  def wasL(self) :
    if self.ballOldPosX < self.ballActPosX : return True else : return False def isSame(self,ballPos) : if self.ballActPosX == ballPos.ballActPosX : if self.ballActPosY == ballPos.ballActPosY : return True return False def printIt(self) : print("X:",self.ballActPosX," Y:",self.ballActPosY) def printItAll(self) : print("Xa:",self.ballActPosX," Ya:",self.ballActPosY) print("Xo:",self.ballOldPosX," Yo:",self.ballOldPosY) if True == self.wasL() : print("from left") else : print("from right") print("color ",self.ballColor) def getX(self) : return self.ballActPosX def getY(self) : return self.ballActPosY def getColor(self) : return self.ballColor #------------------------------------------------------------------------------ class ConnectedGears : gearList = [] def __init__(self,gearList) : self.gearList = gearList def getGearList(self) : return self.gearList #------------------------------------------------------------------------------ # functions #------------------------------------------------------------------------------ def getFilenameParameter() : datName = "" numBalls = 1 if len(sys.argv) > 1 :
    datName = sys.argv[1]
  if len(sys.argv) > 2 :
    numBalls = int(sys.argv[2])
  if len(sys.argv) == 1 :
    print("Usage:", sys.argv[0], " <PlayGround Filename> [<number Balls>]");
    printPlayground()
    print()
    print("Non\t\t",sign_non)
    print("Space\t\t",sign_space)
    print("Ramp Left\t",sign_rampL)
    print("Ramp Right\t",sign_rampR)
    print("Crossover\t",sign_crossover)
    print("Bit Left\t",sign_bitL)
    print("Bit Right\t",sign_bitR)
    print("Interceptor\t",sign_interceptor)
    print("Gear\t\t",sign_gear)
    print("Gear Bit Left\t",sign_gearBitL)
    print("Gear Bit Right\t",sign_gearBitR)
    exit()
  return (datName,numBalls)
#------------------------------------------------------------------------------
def loadPlayGround(playgroundName) :
  if os.path.isfile(playgroundName) == False :
    print("File:", playgroundName, " doesnt exist");
    exit() 
  fnDatei = open(playgroundName,"r")
  playliste = []
  for line in fnDatei :
    line = line.strip()
    if line[0] != '#' :      
      playliste.append(line)
  fnDatei.close()
  return playliste
#------------------------------------------------------------------------------
def checkSignPosition(actSign,posX,posY) :
  countPos = posY * lineLength + posX
  # gears could have all positions
  if actSign != sign_gear :
    if actSign == sign_non :
      if countPos % 2 == 1 :
        return False   
  return True
#------------------------------------------------------------------------------
def printPlayground() :
  for y in range(lineCnt) :
    for x in range(lineLength) :
      countPos = y * lineLength + x
      if countPos % 2 == 0 :
        print(sign_non, end = '')
      else :
        print(sign_space, end = '')
    print()
#------------------------------------------------------------------------------
def checkPlayGround(playliste) :
  signs = [ sign_non, 
            sign_space, 
            sign_rampL, 
            sign_rampR, 
            sign_crossover,
            sign_bitL,
            sign_bitR,
            sign_interceptor,
            sign_gear,
            sign_gearBitL,
            sign_gearBitR]
  for y in range(len(playliste)) :
    actLine = playliste[y]
    if lineLength != len(actLine) :
      print(y," len", len(actLine), "doesnt equal ",lineLength)
      exit()
    for x in range(len(actLine)) :
      actSign = actLine[x]
      if actSign not in signs :
        print("sign",actSign,"not in signs")
        exit()
      if checkSignPosition(actSign,x,y) == False:
        print("Wrong Sign Position x",x," y",y)
        exit()
#------------------------------------------------------------------------------
def printPlayGround(playliste) :
  for x in range(len(playliste)) :
    print(x,":\t", end = '')
    for sign in playliste[x] :
      print(sign, end = '')
    print()
#------------------------------------------------------------------------------
def printPlayGroundWithBall(playliste,playball) :
  for x in range(len(playliste)) :
    if x == playball.ballActPosY :
      print(x,":\t", end = '')
      for y in range(len(playliste[x])) :
        if y == playball.ballActPosX :
          if playball.getColor() == 'b' :
            print("b", end = '')
          else :
            print("r", end = '')
        else :
          print(" ", end = '')
      print()
    print(x,":\t", end = '')
    for sign in playliste[x] :
      print(sign, end = '')
    print()
#------------------------------------------------------------------------------
def printPlayGroundWithBallInside(playliste,playball, lineNr = False) :
  for y in range(len(playliste)) :
    if lineNr :
      print(y,":\t", end = '')
    line = playliste[y]
    for x in range(len(line)) :
      if y == playball.ballActPosY and \
         x == playball.ballActPosX :
        if playball.getColor() == 'b' :
          print("b", end = '')
        else :
          print("r", end = '')
      else :  
        print(line[x], end = '')
    print()
#------------------------------------------------------------------------------
def getSign(playliste,playball) :
  actSign = ""
  if playball.ballActPosY < len(playliste)  and 0 <= playball.ballActPosY :
    line = playliste[playball.ballActPosY]
    if playball.ballActPosX < len(line) and 0 <= playball.ballActPosX :
      actSign = line[playball.ballActPosX]
  return actSign
#------------------------------------------------------------------------------
def setSign(playliste,playball, sign) :
  if playball.ballActPosY < len(playliste) and 0 <= playball.ballActPosY :
    line = playliste[playball.ballActPosY]
    if playball.ballActPosX < len(line) and 0 <= playball.ballActPosX :
      posX = 0
      newLine = []
      for i in line :
        if posX == playball.ballActPosX :
          newLine.append(sign)
        else :
          newLine.append(line[posX])
        posX = posX + 1
    playliste[playball.ballActPosY] = newLine
#------------------------------------------------------------------------------
def singleStep(playliste,playball,ConnectedGearsList) :
  actSign = getSign(playliste,playball)
  if   actSign == sign_non :
    playball.nextD()
  elif actSign == sign_space :
    playball.nextD()
  elif actSign == sign_rampL :
    playball.nextLD()
  elif actSign == sign_rampR :
    playball.nextRD()
  elif actSign == sign_crossover :
    if playball.wasL() :
      playball.nextRD()
    else :
      playball.nextLD()
  elif actSign == sign_bitL :
    setSign(playliste,playball,sign_bitR)
    playball.nextRD()
  elif actSign == sign_bitR :
    setSign(playliste,playball,sign_bitL)
    playball.nextLD()
  elif actSign == sign_interceptor :
    return False
  elif actSign == sign_gear :
    playball.nextD()
  elif actSign == sign_gearBitL :
    gearList = getConnectedGearListInBall(ConnectedGearsList,playball)
    changePlaylistGears(playliste,gearList)
    playball.nextRD()
  elif actSign == sign_gearBitR :
    gearList = getConnectedGearListInBall(ConnectedGearsList,playball)
    changePlaylistGears(playliste,gearList)
    playball.nextLD()
  else :
    playball.nextD()
  return True
#------------------------------------------------------------------------------
# gears and gearBits
#------------------------------------------------------------------------------
def printBallList(ballList) :
  for x in range(len(ballList)) :
    ballList[x].printIt()
#------------------------------------------------------------------------------
def isBallInTheList(ballList,ball) :
  for elemBall in ballList :
    if elemBall.isSame(ball) : 
      return True
  return False
#------------------------------------------------------------------------------
def connectLists(listeA,ListeB) :
  nextList = listeA
  for elemBall in ListeB :    
    nextList.append(elemBall)
  return nextList
#------------------------------------------------------------------------------
def getConnectedGears(playliste,actBallPos,connectedList) :
  actConnection = []
  actSign = getSign(playliste,actBallPos)

  if False == isBallInTheList(connectedList,actBallPos) :
    actConnection.append(actBallPos)

  if sign_gearBitL == actSign or \
     sign_gearBitR == actSign or \
     sign_gear == actSign :
    upPos = Ball(actBallPos.getX(),actBallPos.getY()-1)
    upSign = getSign(playliste,upPos)
    if sign_gearBitL == upSign or \
       sign_gearBitR == upSign or \
       sign_gear == upSign :
      if False == isBallInTheList(connectedList,upPos) :
        actConnection.append(upPos)

    downPos = Ball(actBallPos.getX(),actBallPos.getY()+1)
    downSign = getSign(playliste,downPos)
    if sign_gearBitL == downSign or \
       sign_gearBitR == downSign or \
       sign_gear == downSign :
      if False == isBallInTheList(connectedList,downPos) :
        actConnection.append(downPos)

    leftPos = Ball(actBallPos.getX()-1,actBallPos.getY())
    leftSign = getSign(playliste,leftPos)
    if sign_gearBitL == leftSign or \
       sign_gearBitR == leftSign or \
       sign_gear == leftSign :
      if False == isBallInTheList(connectedList,leftPos) :
        actConnection.append(leftPos)

    rightPos = Ball(actBallPos.getX()+1,actBallPos.getY())
    rightSign = getSign(playliste,rightPos)
    if sign_gearBitL == rightSign or \
       sign_gearBitR == rightSign or \
       sign_gear == rightSign :
      if False == isBallInTheList(connectedList,rightPos) :
        actConnection.append(rightPos)

  return actConnection
#------------------------------------------------------------------------------
def getConnectedGearList(playliste,actBallPos,connectedList) :
  actConnected = getConnectedGears(playliste,actBallPos,connectedList)
  connectedList = connectLists(connectedList,actConnected)
  for elemBall in actConnected :
    getConnectedGearList(playliste,elemBall,connectedList)
  return connectedList
#------------------------------------------------------------------------------
def isInConnectedGearsList(ConnectedGearsList,playball) :
  for connGears in ConnectedGearsList :
    actGearList = connGears.getGearList()
    if True == isBallInTheList(actGearList,playball) :
      return True    
  return False
#------------------------------------------------------------------------------
def getConnectedGearsList(playliste) :
  ConnectedGearsList = []
  for y in range(len(playliste)) :
    actLine = playliste[y]
    for x in range(len(actLine)) :
      actSign = actLine[x]
      if sign_gearBitL == actSign or \
         sign_gearBitR == actSign or \
         sign_gear == actSign :
        playball = Ball(x,y)
        if False == isInConnectedGearsList(ConnectedGearsList,playball) :
          connectedList = getConnectedGearList(playliste,playball,[])
          ConnectedGearsList.append(ConnectedGears(connectedList))
  return ConnectedGearsList
#------------------------------------------------------------------------------
def getConnectedGearListInBall(ConnectedGearsList,playball) :
  actGearList = []
  for connGears in ConnectedGearsList :
    actGearList = connGears.getGearList()
    if True == isBallInTheList(actGearList,playball) :
      return actGearList
  return actGearList
#------------------------------------------------------------------------------
def printGearLists(ConnectedGearsList) :
  for connGears in ConnectedGearsList :
    printBallList(connGears.getGearList())
    print()
#------------------------------------------------------------------------------
def changePlaylistGears(playliste,gearList) :
  for actBall in gearList :
    actSign = getSign(playliste,actBall)
    if actSign == sign_gearBitL :
      setSign(playliste,actBall,sign_gearBitR)
    elif actSign == sign_gearBitR :
      setSign(playliste,actBall,sign_gearBitL)
#------------------------------------------------------------------------------
def getLeftBlueBall() :
  return Ball(3,0,'l','b')
#------------------------------------------------------------------------------
def getRightRedBall() :
  return Ball(7,0,'r','r')
#------------------------------------------------------------------------------
def printBallResultList(playBallResults) :
  for playBall in playBallResults :
    print(playBall.getColor(),end = '')
  print()
#------------------------------------------------------------------------------
# main
#------------------------------------------------------------------------------
def main() :
  (datName,numBalls) = getFilenameParameter()
  playliste = loadPlayGround(datName)
  checkPlayGround(playliste)

  ConnectedGearsList = getConnectedGearsList(playliste)

  playBall = getLeftBlueBall()
  playBallResults = []

  for i in range(numBalls) :
    storeBall = False
    while playBall.getY() < lineCnt :
      printPlayGroundWithBallInside(playliste,playBall)
      if False == singleStep(playliste,playBall,ConnectedGearsList) :
        print("Stopp",playBall.getColor())
        exit() 
      else :
        storeBall = True
      print()
    if storeBall :
      playBallResults.append(playBall)
      if playBall.getX() < lineLength/2 :
        playBall = getLeftBlueBall()
      else :
        playBall = getRightRedBall()
      printBallResultList(playBallResults)
      print()
#------------------------------------------------------------------------------
# start
#------------------------------------------------------------------------------
main()
#------------------------------------------------------------------------------

Adder 4Bit

Dieses Programm bildet einen 4Bit Addierer. Die vier Bit Pfeile geben die Zahl an, auf die addiert werden soll. Richtung lenks ist null und rechts eins. Die Anzahl der durchlaufenden Kugeln von links oben wird darauf addiert. Anschließend zeigen die Bit Pfeile das Ergebnis an.

.o.<.o.o.o.
o.R.R.o.o.o
.o.<.L.o.o.
o.R.R.o.o.o
.o.<.L.o.o.
o.R.R.o.o.o
.o.<.L.o.o.
o.R.R.o.o.o
.o.R.L.o.o.
o.o.L.o.o.o
.o.R.o.o.o.

Mit python playground.py adder.txt 3 wird das Program ausgeführt und am Ende Ergeben die Bit Pfeile eine drei.

Links:
https://github.com/sky4walk/turingTumbleSim
https://www.turingtumble.com/
https://jessecrossen.github.io/ttsim

Klicke, um auf Turing%20Tumble%20Educator%20Guide%201_0.pdf zuzugreifen


https://youtu.be/Iw_ecEETPws

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.