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.

Mastermind-robot

Diskussion: Mastermind-robot im Forum Programmieraufgaben, in der Kategorie Code Kitchen; Anzeige Eine Aufgabe von Chris: Zitat: Schreibe ein Computerprogramm, das Mastermind spielt. Es soll nach einem Code fragen und diesen ...

Antwort
Alt 10.09.06, 18:10   #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 Mastermind-robot

Anzeige

Eine Aufgabe von Chris:

Zitat:
Schreibe ein Computerprogramm, das Mastermind spielt. Es soll nach einem Code fragen und diesen dann versuchen zu knacken. (Das Programm spielt beide Spieler, also der Anwender soll nicht die lästigen Bewertungen eingeben müssen, aber natürlich darf der "lösende Teil" des Programms nicht direkt auf den Code zugreifen!)
Es muss jede mögliche Kombination knacken können!
Das Programm soll die einzelnen Zeilen und die jeweilige Bewertung auch anzeigen.

Spielregeln: Es werden keine 'Löcher' und keine doppelten Farben benutzt. Es gibt acht Farben und vier Positionen. Das Brett hat 10 Zeilen. Die Bewertung der Versuche gibt nur die Zahl der schwarzen und weißen Pins an, nicht, auf welche Position sie sich beziehen.
Viel Spass ;)
__________________
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 11.09.06, 19:59   #2 (permalink)
 
Registriert seit: 05.02.05
Chrisiaut Leistung: Facit NTK
Chrisiaut eine Nachricht über ICQ schicken
Likes: 0
Standard

für alle dies ned kennen: http://de.wikipedia.org/wiki/Mastermind
Chrisiaut ist offline   Mit Zitat antworten
   
HaBOT
 
- Anzeige -

Werbung ist gerade online    
Alt 12.09.06, 23:52   #3 (permalink)
 
Registriert seit: 01.11.03
lagalopex Leistung: Facit NTK
Likes: 0
Standard RE: Mastermind-robot

Zitat:
Original von CDW
Spielregeln: Es werden keine 'Löcher' und keine doppelten Farben benutzt. Es gibt acht Farben und vier Positionen. Das Brett hat 10 Zeilen. Die Bewertung der Versuche gibt nur die Zahl der schwarzen und weißen Pins an, nicht, auf welche Position sie sich beziehen.
Dürfen Löcher bzw doppelte Farben beim Lösen benutzt werden?
Wäre es sinnvoll, acht Farben vorher festzulegen? (normalerweise gibts ja nur 6...) Der Einfachheit halber kann man ja auch Zeichen oder Ziffern benutzen...
lagalopex ist offline   Mit Zitat antworten
Alt 14.09.06, 01:01   #4 (permalink)
 
Registriert seit: 16.08.06
merker Leistung: Facit NTK
Likes: 0
Standard

Hallo,

im obigen "wiki"-Link steht, dass zur Strategie "logisches Denkvermögen" und "Kombinationsgabe" gehören. Allerdings sehe ich keinen Unterschied zwischen "Kombinationsgabe" und "Raten mit rel. hoher Trefferquote".

Deshalb als Anhang dabei eine Lösung die auf einer Bruteforce-Methode beruht.

Möglich ist das weil die Spielregeln von "Mastemind" cracker-technisch gesehen zwei schwere Bugs enthalten :

MindBug I   

Bei 8 Farben mit Wiederholung gibt es nur 8 ^ 4 = 4096 Kombinationen. Schon die Eingabe einer beliebigen Zahl reduziert die Kombinationen um 75 %.

MindBug II   

Beispiel :

code : 3712 (Zahlen repräsentieren die Farben ( 1..8 ))
1. eingabe : 2761
Das Spiel gibt zurück : sw-- (schwarz,weiss,leer,leer)

Nun umgekehrt :

code : 2761
1. eingabe : 3712
Das Spiel gibt zurück : sw--

"vorwärts" und "rückwärts" bringt das gleiche Ergebnis (sw--).

Viel Spass mit dem Anhang. Diesmal ist es eine "echte C++ -State-Of-The-Art- Konsole" :

Output   



eingeben code : 4567
--------------------
1. versuch : 1234 w--- 0976
2. versuch : 6178 ww-- 0228
3. versuch : 5851 w--- 0055
4. versuch : 7562 ssw- 0005
5. versuch : 7365 sww- 0002
6. versuch : 7546 swww 0001
7. versuch : 4567 ssss 0001

nochmal (0:ja,1:nein) ?

merker ist offline   Mit Zitat antworten
Alt 14.09.06, 01:39   #5 (permalink)
Senior Member
 
Registriert seit: 27.01.02
Chris Leistung: Facit NTK
Likes: 1
Standard

Habe ganz vergessen meine Lösung mit anzugeben. Hab mal ein Programm geschrieben, daß einfach nach Brute-Force-Manier vorgeht und den Code knackt und dann noch eins, das beweist, daß alle Kombinationen mit dem Algorithmus lösbar sind (indem es einfach alle Kombinationen als Startwert vorgibt und dann ne Schleife laufen lääst).
Das Programm beginnt mit einer Kombination (0-1-2-3), lässt sie bewerten und "zählt" dann durch: Erhöht zuerst mal die letzte Ziffer um 1 und checkt dann, ob das Ergebnis mit der Bewertung der Vorhergehenden konsistent ist, indem es die vorhergehenden nach dem neuen Versuch bewertet und diese Bewertung mit der ursprünglichen vergleicht. Wenn diese gleich sind, ist neue Kombination konsistent und er macht sie dann. Sind sie nicht gleich, "zählt" es weiter...
Geschrieben habe ich das ganze mit ziemlich elementaren Befehlen in Pascal.

Zitat:
Dürfen Löcher bzw doppelte Farben beim Lösen benutzt werden?
Wäre es sinnvoll, acht Farben vorher festzulegen? (normalerweise gibts ja nur 6...) Der Einfachheit halber kann man ja auch Zeichen oder Ziffern benutzen...
Klar kannst du auch eine "erweiterte" Version schreiben... Das Originalspiel geht meines Wissens mit acht Farben; natürlich ist es sinnvoll, diese mit Zahlen durchzunummerieren. (Hoffe ich habe die Frage richtig verstanden!)

(Wo kann man eigentlich dieses "Hide" im Post eingügen?)
durch [ SPOILER ="titel"] hidecode [ /SPOILER] (editiert von CDW)
Code   

Code:
program Mastermind;
uses crt;
var code:array[0..3] of byte; { Der versteckte Code }
allesSchwarz:array[0..1] of byte; { Referenz für 4 Schwarze und 0 weiße }
brett:array[0..9,0..3] of byte; { Das Brett }
antworten:array[0..9,0..1] of byte; { Platz für Bewertungen }
i,line,m,below,p,q:byte;
gefunden,voll,raus,firstright,gleiche:boolean;


procedure Einlesen; { Begrüßung // Einlesen des versteckten Codes }
var eingabeok:boolean;
istzahl:boolean;
j:integer;
begin
writeln('-------------------------------------------------');
writeln('| Mastermind v0.2 |');
writeln('| author: Chris |');
writeln('| Published under GNU/GPL in current version |');
writeln('-------------------------------------------------');

repeat
writeln('Enter your hidden code (4 separate values');
writeln('from 0 to 7, no equal values!):');
write('#0: '); readln(code[0]);
write('#1: '); readln(code[1]);
write('#2: '); readln(code[2]);
write('#3: '); readln(code[3]);

eingabeok:=true;

{ Checke, ob alle Zahlen korrekt sind }
for i:=0 to 3 do
begin
istzahl:=false;
if code[i]=0 then istzahl:=true;
if code[i]=1 then istzahl:=true;
if code[i]=2 then istzahl:=true;
if code[i]=3 then istzahl:=true;
if code[i]=4 then istzahl:=true;
if code[i]=5 then istzahl:=true;
if code[i]=6 then istzahl:=true;
if code[i]=7 then istzahl:=true;
if istzahl=false then eingabeok:=false;
end;

{ Checke, dass keine gleichen dabei sind }
for i:=0 to 3 do for j:=0 to 3 do
if (code[i]=code[j]) and (i<>j) then eingabeok:=false;

until eingabeok=true;
end;


procedure AntwortenNull;
var j:integer;
begin
for i:=0 to 9 do
for j:=0 to 1 do
antworten[i,j]:=0;
end;


procedure Schreibe(znr:integer);
begin
writeln(znr,' || ',brett[znr,0],' ',brett[znr,1],' ',brett[znr,2],' ',brett[znr,3],' || white: ',antworten[znr,0],', black: ',antworten[znr,1]);
end;



procedure ErsteZeileSchreiben;
begin
for i:=0 to 4 do
brett[0,i]:=i;
end;


procedure bewerte(znr:integer);
var j:integer;
begin
for i:=0 to 3 do
begin

for j:=0 to 3 do
if (brett[znr,i]=code[j]) and (i<>j) then inc(antworten[znr,0]); { weiße setzen }

if brett[znr,i]=code[i] then inc(antworten[znr,1]); { schwarze setzen }

end;
end;


function konsistent(znr:integer):boolean;
var testantwort:array[0..1] of integer;
j,k,r,znrbelow:integer;
begin
konsistent:=true;
znrbelow:=znr-1;

for k:=0 to znrbelow do
begin

for r:=0 to 1 do testantwort[r]:=0;

{ Vergleiche kte Zeile mit dem in znr übergebenen Vorschlag }
for i:=0 to 3 do
begin
for j:=0 to 3 do
if (brett[k,i]=brett[znr,j]) and (i<>j) then inc(testantwort[0]); { weiße setzen }

if brett[k,i]=brett[znr,i] then inc(testantwort[1]); { schwarze setzen }
end;


for i:=0 to 1 do
if testantwort[i]<>antworten[k,i] then konsistent:=false; { Vergleiche }


end;
end;


{ Hauptprogramm }
begin
Einlesen; { Liest 'code' ein }
AntwortenNull; { Setzt alle Elemente der Antwortmatrix auf 0 }
ErsteZeileSchreiben; { Schreibt 0 1 2 3 in die erste Zeile }
allesSchwarz[0]:=0; { Setzt die Referenz für die Lösung }
allesSchwarz[1]:=4;

bewerte(0);
Schreibe(0);

{ Checke, ob schon die erste richtig war }
firstright:=true;
for i:=0 to 1 do
if antworten[0,i]<>allesSchwarz[i] then firstright:=false;


if firstright=false then
begin


line:=0;


repeat

inc(line);
below:=line-1;

{ Vorherige Zeile übernehmen }
for m:=0 to 3 do brett[line,m]:=brett[below,m];

raus:=false;
gefunden:=false;
voll:=false;

repeat

repeat
{ Durchlaufen }
inc(brett[line,3]);

{ Überträge }
if brett[line,3]=8 then
begin
brett[line,3]:=0;
inc(brett[line,2]);
end;
if brett[line,2]=8 then
begin
brett[line,2]:=0;
inc(brett[line,1]);
end;
if brett[line,1]=8 then
begin
brett[line,1]:=0;
inc(brett[line,0]);
end;
if brett[line,0]=8 then
begin
brett[line,0]:=0;
end;

{ Checken ob welche gleich sind }
gleiche:=false;
for p:=0 to 3 do for q:=0 to 3 do
if (brett[line,p]=brett[line,q]) and (p<>q) then gleiche:=true;

until gleiche=false;

until konsistent(line)=true;

bewerte(line);
Schreibe(line);


{ Gucken, obs schon die Lösung ist }
gefunden:=true;
for i:=0 to 1 do
if antworten[line,i]<>allesSchwarz[i] then gefunden:=false;

{ ...oder ob das Brett voll ist }
if line=9 then voll:=true;

if voll=true then raus:=true;
if gefunden=true then raus:=true;

until raus=true;

if voll=true then writeln('Das Brett ist voll.');
if gefunden=true then writeln('Got it in line ',line,'! :)')
else writeln('Didnt get it. :(');

end

else writeln('Got it in the first line! ;)');


end.


Output:
Code:
-------------------------------------------------
| Mastermind v0.2                               |
| author: Chris       |
| Published under GNU/GPL in current version    |
-------------------------------------------------
Enter your hidden code (4 separate values
from 0 to 7, no equal values!):
#0: 6
#1: 4
#2: 3
#3: 2
0 || 0   1   2   3 || white: 2, black: 0
1 || 1   0   4   5 || white: 1, black: 0
2 || 2   3   5   6 || white: 3, black: 0
3 || 3   2   6   4 || white: 4, black: 0
4 || 4   6   3   2 || white: 2, black: 2
5 || 6   4   3   2 || white: 0, black: 4
Got it in line 5! :)
Chris ist offline   Mit Zitat antworten
Alt 27.12.08, 02:04   #6 (permalink)
 
Registriert seit: 21.04.08
Ook! Leistung: Facit NTK
Likes: 0
Standard

Nicht perfekt... aber hat Spaß gemacht

Code:
from random import choice
from itertools import count

def initialCombs():
   def hasNoDoubles(comb):
      return not any(map(lambda i: comb.count(i) > 1, range(8)))
   return [ "%s%s%s%s" % (a,b,c,d) for a in range(8) for b in range(8) for c in range(8) for d in range(8) if hasNoDoubles([a,b,c,d]) ]

def rateComb(comb, number):
   black, white = 0, 0
   for i in range(4):
      if comb[i] == number[i]: 
         black += 1
      elif comb[i] in number:
         white += 1
   return (black, white)

def solve(answer, combs):
   def statistics(idx, comb, black, white):
      print "%i >> %s: %s%s%s" % (idx+1, " ".join(comb), black*'s', white*'w', (4-(black+white))*'-')
   for idx in count():
      comb = list(choice(combs))
      black, white = rateComb(comb, answer)
      combs = removeByRating(combs, comb, black, white)
      statistics(idx, comb, black, white)
      if black == 4:
         return "=> Loesung gefunden!"

def removeByRating(combs, number, black, white):
   return filter(lambda c: rateComb(c, number) == (black, white), combs)

if __name__ == "__main__":
   print solve(raw_input("Geheime Kombination: "), initialCombs())
Code:
Geheime Kombination: 4567
1 >> 7 3 2 5: ww--
2 >> 1 2 3 6: w---
3 >> 0 7 4 2: ww--
4 >> 5 6 7 0: www-
5 >> 4 5 6 7: ssss
=> Loesung gefunden!
Blöde Einrückung, hehe...

EDIT:
Danke für den Hinweis - habe den Code angepasst, sollte nun passen :]

Geändert von Ook! (19.04.10 um 20:08 Uhr)
Ook! ist offline   Mit Zitat antworten
Alt 27.12.08, 17:05   #7 (permalink)
Senior Member
 
Registriert seit: 03.09.05
Lesco Leistung: Facit NTK
Likes: 0
Standard

Zitat:
Original von Ook!
[..]
Wenn ich deinen Code richtig verstanden habe, machst du es dir zu einfach, da man nur die Anzahl der schwarzen/weißen Pins erhält, und nicht die Positionen dazu.

Hier meine Lösung in Haskell(funktioniert in dieser Fassung nur ohne doppelte Farben, benötigt sonst 2 kleine Änderungen):
code   

Code:
import Control.Monad
import Data.Char
import Data.Map as M
import Data.List as L
import System.Random

checkAnswer :: Map Int Int -> Map Int Int -> (Int,Int)
checkAnswer code answer = let correctPos = filterWithKey (\k a -> code ! k == a) answer
                              remainingAnswer = answer M.\\ correctPos
                              remainingCode = code M.\\ correctPos
                              correctCols = filterWithKey (\k a -> not . M.null $ M.filter (==a) remainingCode) remainingAnswer
                          in (size correctPos,size correctCols)

initialCombs :: [Map Int Int]
initialCombs = [fromList $ zip [0..] [a,b,c,d] | a <- [0..7], b <- [0..7], c <- [0..7], d <- [0..7],
                                                 a /= b, a /= c, a /= d, b /= c, b /= d, c /= d]

--returns the number of exact matches in m and n
exactMatches m n = size $ filterWithKey (\k v -> m ! k == v) n
--returns the number of value matches on different positions in m and n
valMatches m n = size $ filterWithKey (\k v -> not . M.null $ filterWithKey (\k' v' -> k' /= k && v == v') m) n

--correct code is passed along as a parameter but is accessed only by the checking function
tryComb :: Map Int Int -> Map Int Int -> [Map Int Int] -> IO ()
tryComb a code combs =  do
  let res@(b,w) = checkAnswer code a
  putStrLn $ "Trying answer: " ++ show (toList a) ++ " - " ++ show res
  case b of
    4 -> putStrLn $ "Solution found "++show (toList a)
    otherwise -> do
      let newcombs = L.filter (\c -> exactMatches a c == b && valMatches a c == w) combs
      putStrLn $ "Remaining combinations: "++show (length newcombs)
      n <- randomRIO (0,length newcombs - 1)
      tryComb (newcombs !! n) code newcombs 
  
main :: IO ()
main = do
  putStrLn "Enter code"
  code <- L.map digitToInt `liftM` getLine
  ind <- randomRIO (0,length initialCombs - 1)
  tryComb (initialCombs !! ind) (fromList $ zip [0..] code) initialCombs


Beispiel:
Code:
Enter code
1703
Trying answer: [(0,3),(1,2),(2,6),(3,7)] - (0,2)
Remaining combinations: 504
Trying answer: [(0,7),(1,5),(2,3),(3,0)] - (0,3)
Remaining combinations: 44
Trying answer: [(0,5),(1,3),(2,7),(3,1)] - (0,3)
Remaining combinations: 3
Trying answer: [(0,4),(1,7),(2,5),(3,3)] - (2,0)
Remaining combinations: 2
Trying answer: [(0,1),(1,7),(2,0),(3,3)] - (4,0)
Solution found [(0,1),(1,7),(2,0),(3,3)]
Lesco ist offline   Mit Zitat antworten
Alt 28.12.08, 16:16   #8 (permalink)
CDW
Moderator
Themenstarter
 
Benutzerbild von CDW
 
Registriert seit: 20.07.05
CDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: Opteron
Likes: 202
Standard

SWI/SICStus prolog   

Code:
:-use_module(library(lists)).
:-use_module(library(sets)).  %SWI: auskommentieren/ignorieren.
:-use_module(library(clpfd)).

combo(C):-C=[_,_,_,_],domain(C,1,8)/*%SWI: C ins 1..8*/,all_different(C),labeling([ff],C).

cmp(X,Y,Z):- X=:=Y -> Z=1 ; Z=0.
check(Org,ToCheck,W,B):-intersection(Org,ToCheck,Ws),
        length(Ws,WTmp),maplist(cmp,Org,ToCheck,BList),!,sumlist(BList,B),W is WTmp-B.

solve(Sol,Sol,_,[Sol]):- write('Loesung: '),write(Sol),nl.
solve(Sol,Try,SolSet,[Try|Path]):-check(Sol,Try,W,B),   
        findall(Combo,(member(Combo,SolSet),check(Try,Combo,W,B),Combo\=Try),
		[NTry|NewSolSet]),
        statistic([NTry|NewSolSet],Try,W,B),solve(Sol,NTry,NewSolSet,Path),!.

statistic(Set,Try,W,B):- length(Set,L),
	format('Versuch: ~q,w:~k,b:~k verbl. Moeglichkeiten: ~d\n', [Try,W,B,L]).

bot(Solution,Path):-
        findall(Combo,combo(Combo),[Try|SolSet]),solve(Solution,Try,SolSet,Path),!.

10 Zeilen Begrenzung wurde allerdings nicht eingebaut, da der Bot perfekt spielt und alles unter 10 Zeilen löst.
Beweis:    

es gibt insgesamt 1680 Kombinationen (8!/(8-4)!) bzw:
Code:
| ?- findall(C,combo(C),Cs),length(Cs,Gesamt).
Cs = [[1,2,3,4],[1,2,3,5],[1,2,3,6],[1,2,3,7],[1,2,3,8],[1,2,4,3],[1,2,4,5],[1,2,4|...],[1,2|...],[1|...]|...],
Gesamt = 1680 ?
Anzahl der Lösungen/längste Lösung:
Code:
  time2(findall((Len),(combo(C),bot(C,Sol),length(Sol,Len)),Sols)),length(Sols,AnzLoes),sort(Sols,Sorted),last(Sorted,Laengste),sumlist(Sols,Sum),AverageNum is Sum/AnzLoes.
 65.813 sec.

Sorted = [1,2,3,4,5,6,7],
Laengste = 7,
AnzLoes = 1680,
AverageNum = 4.90297619047619 ?
D.h Anzahl der Lösungen==Anzahl der Kombinationen, wobei die längste Lösung 7 Schritte beinhaltet.

Beispiel:   

Code:
 | ?- bot([8,1,7,2],Loesung).
Versuch: [1,2,3,4],w:2,b:0 verbl. Moeglichkeiten: 504
Versuch: [2,1,5,6],w:1,b:1 verbl. Moeglichkeiten: 84
Versuch: [2,3,6,7],w:2,b:0 verbl. Moeglichkeiten: 18
Versuch: [3,1,7,5],w:0,b:2 verbl. Moeglichkeiten: 1
Loesung: [8,1,7,2]
Loesung = [[1,2,3,4],[2,1,5,6],[2,3,6,7],[3,1,7,5],[8,1,7,2]] ? 
yes
% 3
| ?- bot([4,5,6,7],Loesung).
Versuch: [1,2,3,4],w:1,b:0 verbl. Moeglichkeiten: 288
Versuch: [2,5,6,7],w:0,b:3 verbl. Moeglichkeiten: 5
Versuch: [2,5,6,8],w:0,b:2 verbl. Moeglichkeiten: 2
Versuch: [3,5,6,7],w:0,b:3 verbl. Moeglichkeiten: 1
Loesung: [4,5,6,7]
Loesung = [[1,2,3,4],[2,5,6,7],[2,5,6,8],[3,5,6,7],[4,5,6,7]] ? 
yes
__________________
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
Antwort
   
- Anzeige -

Werbung ist gerade online    

[HaBo] » Software Home » Code Kitchen » Programmieraufgaben » Mastermind-robot
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
Asus und Drive Robot, Frechheit? .:L Hardware Probleme 6 09.08.09 13:50
PC-Robot umprogrammieren SunTzu_2007 Code Kitchen 4 18.09.07 08:40


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