Hackerboard Wiki HaboBlog
Hackerboard bei Facebook Hackerboard bei Google+ Hackerboard bei Twitter

[HaBo]

 
Programmieraufgaben Hier wird regelmäßig eine neue Programmieraufgabe gestellt, die dann gelöst werden soll und in Zusammenarbeit mit den Moderatoren auch besprochen werden kann.

Sokoban Cheater

Diskussion: Sokoban Cheater im Forum Programmieraufgaben, in der Kategorie Code Kitchen; Anzeige Das berühmte Spiel mit den Kisten/Diamanten/Kugeln. (wer er nicht kennt: ab in die Ecke und schämt euch!) http://en.wikipedia.org/wiki/Sokoban Die ...

Antwort
Alt 31.08.08, 14:05   #1 (permalink)
CDW
Moderator
 
Benutzerbild von CDW
 
Registriert seit: 20.07.05
CDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: Opteron
Likes: 202
Standard Sokoban Cheater

Anzeige

Das berühmte Spiel mit den Kisten/Diamanten/Kugeln.
(wer er nicht kennt: ab in die Ecke und schämt euch!)
http://en.wikipedia.org/wiki/Sokoban

Die Levels liegen üblicherweise in diesem Format vor:
http://www.sokobano.de/wiki/index.ph...e=Level_format

Schreibe ein Programm, welches ein Level lösen kann.
Idealerweise kann das Programm ein Level in dem Format einlesen und die Lösung als Schrittabfolge (up,right,down oder ^ > v usw. ) der Figur präsentieren.

Als Testlevels können die Beispiele aus
http://www.sokobano.de/wiki/index.ph...o_play_Sokoban
genommen werden. Richtig "schöne" Levels sollten z.B im Nabokosmos
http://www.sokobano.de/de/levels.php Packet enthalten sein ;)

__________________
Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
Selig, wer nichts zu sagen hat und trotzdem schweigt.
CDW ist offline   Mit Zitat antworten
Alt 21.07.09, 11:38   #2 (permalink)
 
Benutzerbild von Eydeet
 
Registriert seit: 14.04.06
Eydeet Leistung: Facit NTK
Likes: 4
Standard

Eine recht simple Implementierung habe ich mal geschrieben. Da sie total unoptimiert ist kann sie m.E. noch nicht als vollwertige Lösung angesehen werden. Wer will kann gerne auf meinem Source-Code aufbauen.
Algorithmus   
Das Programm sucht in jedem Schritt die Positionen, bei denen es sich lohnt, sie zu besuchen, also die, von denen aus man einen Stein verschieben kann. Dann geht es per A*-Algorithmus an die entsprechende Position und verschiebt den Stein. Die ganzen Möglichkeiten werden dann per Breitensuche durchkämmt. Es wird also immer die optimale Lösung gefunden.
Da ich noch keine Optimierungen (Heuristiken) eingebaut habe kann man nur sehr kleine Level lösen, da es sonst einfach zu lange dauert. Bei einem Level mit drei Steinen, das mehr als 40 Schritte braucht, kann man das Programm quasi nicht mehr benutzen.

Python-Programm   
Code:
#!/usr/bin/python
import time
import sys
sokofield = []
f = open(sys.argv[1])
for line in f:
    l = []
    for c in line[:-1]:
        l.append(c)
    sokofield.append(l)
f.close()

def printField(field):
    for line in field:
        for cell in line:
            print(cell, sep="", end="")
        print()

'''def isWalkable(field, x, y):
    if y < len(field) and x < len(field[0]) and field[y][x] != '#':
        return True
    else:
        return False'''
    
def isFree(field, x, y):
    if y < len(field) and x < len(field[0]) and (field[y][x] == ' ' or field[y][x] == '.' or field[y][x] == '@'):
        return True
    else:
        return False

def isWallFree(field, x, y):
    if y < len(field) and x < len(field[0]) and (field[y][x] == ' ' or field[y][x] == '.' or field[y][x] == '@' or field[y][x] == '$'):
        return True
    else:
        return False

def isTarget(field, x, y):
    if y < len(field) and x < len(field[0]) and field[y][x] == '.':
        return True
    else:
        return False
        
def getValidPos(field, lastPos):
    validPos = []
    for y in range(len(field)):
        for x in range(len(field[y])):
            cell = field[y][x]
            if cell == '$':
                if isFree(field, x, y-1) and isFree(field, x, y+1):
                    if isTarget(field, x, y+1) or not isBlocked(field, x, y+1):
                        validPos.append(((x, y-1), (x, y)))
                    if isTarget(field, x, y-1) or not isBlocked(field, x, y-1):
                        validPos.append(((x, y+1), (x, y)))
                if isFree(field, x-1, y) and isFree(field, x+1, y):
                    if isTarget(field, x+1, y) or not isBlocked(field, x+1, y):
                        validPos.append(((x-1, y), (x, y)))
                    if isTarget(field, x-1, y) or not isBlocked(field, x-1, y):
                        validPos.append(((x+1, y), (x, y)))
    return validPos

def isBlocked(field, x, y):
    return False
    if ((isWallFree(field, x-1, y) and isWallFree(field, x+1, y)) or
        (isWallFree(field, x, y-1) and isWallFree(field, x, y+1))):
        print(x, y, "free")
        return False
    else:
        print(x, y, "not free")
        return True

def getNeighbors(field, x, y):
    nb = []
    if isFree(field, x-1, y):
        nb.append((x-1, y))
    if isFree(field, x, y-1):
        nb.append((x, y-1))
    if isFree(field, x+1, y):
        nb.append((x+1, y))
    if isFree(field, x, y+1):
        nb.append((x, y+1))
    return nb

def aStar(field, startPos, targetPos):
    openlist = [startPos]
    ratings = {startPos: 0}
    pre = {startPos: None}
    closedlist = []
    while len(openlist) > 0:
        b = dict(map(lambda item: (item[1],item[0]),ratings.items()))
        currentNode = b[min(b.keys())]
        currentRating = ratings[currentNode]
        openlist.remove(currentNode)
        ratings.pop(currentNode)
        if (currentNode == targetPos):
            break
        for nb in getNeighbors(field, currentNode[0], currentNode[1]):
            if nb in closedlist:
                continue
            f = currentRating + abs(currentNode[0] - nb[0]) + abs(currentNode[1] - nb[1])
            if nb in openlist:
                if ratings[nb] <= f:
                    continue
            else:
                openlist.append(nb)
            ratings[nb] = f
            pre[nb] = currentNode
        closedlist.append(currentNode)
        
    currentNode = targetPos
    path = [currentNode]
    try:
        while (currentNode != startPos):
            currentNode = pre[currentNode]
            path.append(currentNode)
        path.reverse()
        return path
    except KeyError:
        return None

def doMove(myField, f, t):
    (x, y) = f
    (nx, ny) = t
    if (sokofield[y][x] != '@' and sokofield[y][x] != '$'):
        myField[y][x] = sokofield[y][x]
    else:
        myField[y][x] = ' '
    if (myField[ny][nx] == '$'):
        myField[ny + (ny - y)][nx + (nx - x)] = '$'
    myField[ny][nx] = '@'
    return myField

def getPlayerPos(field):
    for y in range(len(field)):
        for x in range(len(field[y])):
            cell = field[y][x]
            if (cell == '@'):
                return (x, y)
    return None

def getNumTargets(field):
    numTargets = 0 
    for y in range(len(field)):
        for x in range(len(field[y])):
            cell = field[y][x]
            if (cell == '.'):
                numTargets += 1
            elif (cell == '@' and sokofield[y][x] == '.'):
                numTargets += 1
    return numTargets
    
def positionsToPath(pos):
    path = ''
    for i in range(len(pos)-1):
        (fx, fy) = pos[i]
        (tx, ty) = pos[i+1]
        if (tx < fx): path += 'l'
        elif (tx > fx): path += 'r'
        elif (ty < fy): path += 'u'
        elif (ty > fy): path += 'd'
    return path

def breitensuche(field):
    moves = [(0, getPlayerPos(field), field, [])]
    minMoves = 0
    while (len(moves) > 0):
        minMove = min(moves)
        moves.remove(minMove)
        if minMove[0] > minMoves:
            print("Kein Weg unter %s Schritten" % minMove[0])
            minMoves = minMove[0]
        #print(minMove[0], minMove[3])
        #printField(minMove[2])
        if getNumTargets(minMove[2]) == 0:
            print("Loesung gefunden:")
            printField(minMove[2])
            print("Weg:", positionsToPath(minMove[3]))
            break

        pos = getValidPos(minMove[2], 0)
        for pt in pos:
            (p, t) = pt
            #print(p)
            path = aStar(minMove[2], minMove[1], p)
            if (path == None): continue
            path.append(t)
            myField = [[a for a in b] for b in minMove[2]]
            for pid in range(len(path)-1):
                myField = doMove(myField, path[pid], path[pid+1])
            newMove = (minMove[0] + len(path), t, myField, minMove[3] + path)
            #print(newMove)
            #printField(myField)
            #printField(minMove[2])
            moves.append(newMove)
        #time.sleep(1)
            
print("Ausgangslage:")
printField(sokofield)
print("Suche Loesung...")
breitensuche(sokofield)

Beispiel-Ablauf   

Code:
Ausgangslage:
########
#  #.  #
# $#   #
#  # @##
#  # $##
#    .##
########
Suche Loesung...
Kein Weg unter 2 Schritten
Kein Weg unter 6 Schritten
Kein Weg unter 8 Schritten
Kein Weg unter 9 Schritten
[...]
Kein Weg unter 40 Schritten
Loesung gefunden:
########
#  #$@ #
#  #   #
#  #  ##
#  #  ##
#    $##
########
Weg: lddrudllluuluurdddldrrruruurul
Eydeet ist offline   Mit Zitat antworten
Antwort
   
- Anzeige -

Werbung ist gerade online    

[HaBo] » Software Home » Code Kitchen » Programmieraufgaben » Sokoban Cheater
Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind aus
Pingbacks sind aus
Refbacks sind aus


Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Cs-Cheater... Snippy Fun Section 16 06.01.06 23:41
Cheater (eure Meinung) TSperz Games 46 27.12.05 22:54
Cheater.mp3 Wizo Fun Section 6 02.10.04 01:16
NFSU Cheater Tool Nicky20wx Games 5 18.02.04 21:36
cheater-interview -= pillepalle =- Fun Section 4 17.03.03 22:24


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61