import vector import association import WFClasses import stringplus import io import random type Iterator= { reset->Void hasNext->Boolean get->T next->T} type Vector = { size->Number isEmpty->Boolean clear->Void contains(_:T)->Boolean addFirst(_:T)->Void addLast(_:T)->Void firstElement->T lastElement->T removeFirst->T removeLast->T removeValue(_:T)->T indexOf(_:T)->Number at(_:Number)->T setValue(_:T)at(_:Number)->T add(_:T)at(_:Number)->Void removeFromIndex(_:Number)->T iterator->Iterator asString->String forEachDo(_:Block)->Void map(_:Block)->Vector ensureCapacity(_:Number)->Void capacity->Number copyInto(_)->Void indexOf(_:T)startingFrom(_:Number)->Number setSize(_:Number)->Void trimToSize->Void} type Association = { ==(_:Association)->Boolean hashcode->Number getValue->V getKey->K setValue(_:V)->V asString->String} type StringPair = { getFirst->String getSecond->String hashcode->Number ==(_:StringPair)->Boolean asString->String} type WordStream = { addLexItems(_:String)->Void nextToken->String hasMoreTokens->Boolean resetTo(_:Number)->Void currentIndex->Number} type FreqList = { add(_:String)->Void get(_:Number)->String asString->String} type TextGenerator ={ enter(_:String, _:String, _:String)->Void getNextWord(_:String, _:String)->String asString->String} //================================================================== class TextGeneratorClass.new{ // List of Associations of letter pairs and frequency lists var letPairList:Vector is readable := vector.withSize(50) var gen := random.generator //Random number generator // @param first, second: strings to be first and second parts of key // @param third word to be inserted in freq list associated with // // @post: update frequency of third word following the first two by // adding 1. If not yet in table, add with frequency 1. method enter(first:String, second:String, third:String)->Void is public{ var freq:FreqList := WFClasses.newFreqList var assoc:Association := association.withKey(WFClasses.newPair(first, second))value(freq) var itemNum := letPairList.indexOf(assoc) if(itemNum == -1) then{ freq := WFClasses.newFreqList assoc.setValue(freq) letPairList.addLast(assoc)} else{ var element:Association := letPairList.at(itemNum) freq := element.getValue} freq.add(third) } // @param first, second: last two words generated in output text // @return new word chosen from those in association list // associated with . method getNextWord(first:String, second:String)->String is public{ var assoc:Association := association.withKey(WFClasses.newPair(first, second)) value(WFClasses.newFreqList) var nextString:String var itemNum:Number := letPairList.indexOf(assoc) if(itemNum == -1) then {return ""} else{ var element:Association := letPairList.at(itemNum) var freq:FreqList := element.getValue nextString := freq.get(gen.next(100)/100) return nextString} } // @return string representing table in readable form method asString->String is public{ "The table size is {letPairList.size}\n{letPairList}"} } //================================================================= // Main section of program: User opens a text file, program builds // TextGenerator table from input and then generates words. The first // two words are the first two of the inpur. Subsequent words are // chosen according to the frequency list associated with the two // previous words. var word1:String var word2:String var table:TextGenerator := TextGeneratorClass.new var ws:WordStream := WFClasses.newWordStream // User chooses file by entering name in terminal // Opens file and reads content in to a string var ostream := io.output var istream := io.input ostream.write("Enter source file name (including .txt)\n") var fname := "" var chr := istream.next while{chr != "\n"} do { fname := fname ++ chr chr := istream.next } var source := io.open(fname, "r") var line:String := "" while{!source.eof} do {line := source.read} ws.addLexItems(line) word1 := ws.nextToken word2 := ws.nextToken var origFirst:String := word1 var origSecond:String := word2 while{ws.hasMoreTokens} do{ var word3:String := ws.nextToken table.enter(word1, word2, word3) word1 := word2 word2 := word3} word1 := origFirst word2 := origSecond var newText:String := "{origFirst} {origSecond}" for (2..199) do {wordNo-> var word3 := table.getNextWord(word1, word2) if(word3 == "") then { word2 := origFirst word3 := origSecond newText := newText ++ " {word2}"} newText := newText ++ " {word3}" if((wordNo % 20) == 0) then{ newText := newText ++ "\n"} word1 := word2 word2 := word3} print("Table contains:\n" ++ table) print("Generated data is:\n" ++ newText)