PRACTICA 2 SOPA DE LETRAS OBJETIVO: Desarrollar un programa donde se haga uso de cadenas en Java por medio de una sopa de letras a la que se le asignen 5 palabras las cuales acomodara aleatoriamente en la sopa de letras, tomando la palabra mas grande como punto de inicio colocada en diagonal y que los espacios que queden vacios sean llenadas con diferentes letras. MARCO TEÓRICO: Java posee gran capacidad para el manejo de cadenas dentro de sus clases String y StringBuffer. Un objeto String representa una cadena alfanumérica de un valor constante que no puede ser cambiada después de haber sido creada. Un objeto StringBuffer representa una cadena cuyo tamaño puede variar. Los Strings son objetos constantes y por lo tanto muy baratos para el sistema. La mayoría de las funciones relacionadas con cadenas esperan valores String como argumentos y devuelven valores String. Hay que tener en cuenta que las funciones estáticas no consumen memoria del objeto, con lo cual es más conveniente usar Character que char. No obstante, char se usa, por ejemplo, para leer ficheros que están escritos desde otro lenguaje. Existen muchos constructores para crear nuevas cadenas: String(); String( String str ); String( char val[] ); String( char val[],int offset,int count ); String( byte val[],int hibyte ); String( byte val[],int hibyte,int offset,int count ); Tal como uno puede imaginarse, las cadenas pueden ser muy complejas, existiendo muchas funciones muy útiles para trabajar con ellas y, afortunadamente, la mayoría están codificadas en la clase String. Funciones Básicas La primera devuelve la longitud de la cadena y la segunda devuelve el carácter que se encuentra en la posición que se indica en indice: int length(); char charAt( int indice ); Funciones de Comparación de Strings boolean equals( Object obj ); boolean equalsIgnoreCase( Object obj ); Lo mismo que equals() pero no tiene en cuenta mayúsculas o minúsculas. int compareTo( String str2 ); Devuelve un entero menor que cero si la cadena es léxicamente menor que str2. Devuelve cero si las dos cadenas son léxicamente iguales y un entero mayor que cero si la cadena es léxicamente mayor que str2. Funciones de Comparación de Subcadenas boolean regionMatch( int thisoffset,String s2,int s2offset,int len ); boolean regionMatch( boolean ignoreCase,int thisoffset,String s2, int s2offset,int 1 ); Comprueba si una región de esta cadena es igual a una región de otra cadena. boolean startsWith( String prefix ); boolean startsWith( String prefix,int offset ); boolean endsWith( String suffix ); Devuelve si esta cadena comienza o termina con un cierto prefijo o sufijo comenzando en un determinado desplazamiento. int indexOf( int ch ); int indexOf( int ch,int fromindex ); int lastIndexOf( int ch ); int lastIndexOf( int ch,int fromindex ); int indexOf( String str ); int indexOf( String str,int fromindex ); int lastIndexOf( String str ); int lastIndexOf( String str,int fromindex ); Devuelve el primer/último índice de un carácter/cadena empezando la búsqueda a partir de un determinado desplazamiento. String substring( int beginindex ); String substring( int beginindex,int endindex ); String concat( String str ); String replace( char oldchar,char newchar ); String toLowerCase(); String toUpperCase(); String trim(); Ajusta los espacios en blanco al comienzo y al final de la cadena. void getChars( int srcBegin,int srcEnd,char dst[],int dstBegin ); void getBytes( int srcBegin,int srcEnd,byte dst[],int dstBegin ); String toString(); char toCharArray(); int hashCode(); Funciones ValueOf La clase String posee numerosas funciones para transformar valores de otros tipos de datos a su representación como cadena. Todas estas funciones tienen el nombre de valueOf, estando el método sobrecargado para todos los tipos de datos básicos. Veamos un ejemplo de su utilización: String Uno = new String( "Hola Mundo" ); float f = 3.141592; String PI = Uno.valueOf( f ); String PI = String.valueOf( f ); // Mucho más correcto La clase String proporciona cadenas de sólo lectura y soporta operaciones con ellas. Se pueden crear cadenas implícitamente usando una cadena intrecomillada o usando + ó += con dos objetos String. También se pueden crear objetos String explícitamente con el mecanismo new. La clase String soporta los siguientes constructores. • • public String ():construye un nuevo String con el valor " ". public String (String value):construye un String que es copia de value. La forma de llamar a cualquier método de la clase String se realiza de la siguiente forma: nombre_de_variable.nombre_del_método( ). Los métodos básicos de los objetos String son: • length (): devuelve el número de caracteres de la cadena. • charAt (): devuelve el char de la posición especificada. • • • for (int i = 0; i < str.length(); i++) count[str.charAt(i)]++; indexOf (char ch): devuelve el índice de la primera posición de ch. • indexOf (char ch, int start): devuelve el índice de la primera posición de ch >=start. • indexOf (String str): devuelve el índice de la primera posición de str. • indexOf (String str, int start): devuelve el índice de la primera posición de str >= start. • lastIndexOf (char ch): devuelve el índice de la última posición de ch. • lastIndexOf (char ch, int start): devuelve el índice de la última posición de ch <= start. • lastIndexOf (String str): devuelve el índice de la última posición de str. • lastIndexOf (String str, int start): devuelve el índice de la última posición de str <= start. Los métodos indexOf (para métodos que buscan hacia delante) y lastIndexOf (para métodos que buscan hacia atrás) devuelven el índice que han encontrado o –1 si la búsqueda no ha sido satisfactoria. DESARROLLO El programa debera mostrar ua sopa de letras que permita ordenar las palabras aleatoriamente.Se creara una interfaz grafica atractiva para el usuario. Las palabras seran almacenadas previamente en un archivo .txt donde el programa las llamara. Primero se creara una clase principal donde se trate el manejo de la sopa de letras y una segunda clase que contenga los metodos para el "adorno" de la misma. ANALISIS Análisis de los requisitos: • • • • Plataforma java (jdk 6) Editor de código (Text Pad, Blue J, Neat Beans, etc) Conocimientos previos de programación O.O Sistema operativo Windows (XP, Vista, Seven) Analisis operativo: 1. El usuario visualiza una sopa de letras desordenada. 2. A la derecha se encuentran las palabras a buscar. 3.El usuario puede remarcar las palabras arrastrando el raton sobre ellas. 4. Para reiniciar otra serie de busqueda se oprime el boton Recargar. Diseño El programa debera mostrar una ventana similar a : Par empezar a buscar las palabras se clikea cada una de las letras y se marcan automaticamente: Para comenzar otra busqueda se oprime "Recargar" y se limpia la sopa de letras recargando con palabras nuevas: CODIGO Clase Worfind view source print? 001 import java.awt.*; 002 import java.applet.*; 003 import java.util.Vector; 004 import java.util.Hashtable; 005 006 public class Wordfind extends Applet implements java.awt.event.MouseListener,java.awt.event.ActionListener 007 { 008 private Label[] mines = null; 009 010 private final int square = 12; private final int NUM_LABELS = square * square; 011 012 private final int NUM_WORDS_IN_PUZZLE = 4; private Button button = null; 013 014 private Panel minepanel = null; private Vector selectedLabels = new Vector(); 015 016 private String[] solution = null; 017 018 private String wordlist = null; private Hashtable words = null; 019 020 private Hashtable selectedWords = null; //compass type constants 021 022 private final int NORTH = -square; // eg., if square= 12, then -12 private final int SOUTH = square; 023 024 private final int WEST = -1; private final int EAST = 1; 025 026 private final int NE = -square + 1; private final int NW = -square - 1; 027 028 private final int SE = square + 1; private final int SW = square - 1; 029 030 private Label[] captions = null; private Adorn a = null; 031 032 033 034 035 036 public void init() { 037 038 setLayout(new BorderLayout()); 039 040 this.setBackground(Color.pink); //setSize(300,300); 041 042 minepanel = new Panel(new GridLayout(square,square)); 043 044 this.setForeground(Color.blue); this.getLabels(); 045 046 this.getWords(); this.placeWords(); 047 048 this.addFillers(); 049 050 Panel buttonpanel = new Panel(new BorderLayout()); 051 052 button = new Button("Recargar"); button.addActionListener(this); 053 054 buttonpanel.add("South",button); 055 056 Panel labelpanel = new Panel(new GridLayout(0,1)); for (int j = 0;j < getCaptions().length; j++){ 057 058 059 060 labelpanel.add(getCaptions()[j]); } 061 062 063 064 buttonpanel.add("North",labelpanel); 065 066 067 068 this.add("Center", minepanel); 069 070 this.add("South", buttonpanel); 071 072 setLayout(new FlowLayout()); 073 074 setSize(792,396); this.showStatus("Ready"); 075 076 077 078 079 080 } 081 082 public void mouseClicked(java.awt.event.MouseEvent e){ Component c = (Component)e.getSource(); 083 084 if (c instanceof Label){ Label l = (Label)c; 085 086 if (l.getBackground() == Color.lightGray){ l.setBackground(Color.pink); 087 088 }else{ l.setBackground(Color.lightGray); 089 090 } 091 092 this.addSelectedLabel(new Integer(l.getText())); if (checkWin()){ 093 094 showWin(); } 095 096 097 098 } } 099 100 public void mouseEntered(java.awt.event.MouseEvent e){} public void mouseExited(java.awt.event.MouseEvent e){} 101 102 public void mousePressed(java.awt.event.MouseEvent e){} public void mouseReleased(java.awt.event.MouseEvent e){} 104 public void actionPerformed(java.awt.event.ActionEvent e){ 103 105 106 if (e.getSource()==button) { //probably start button restart(); } 107 108 109 110 111 112 113 114 } private boolean checkWin(){ 115 116 //TO DO: return false; 117 118 } private void showWin(){ 119 120 } 121 122 private Label[] getLabels(){ if (mines == null){ 123 124 mines = new Label[NUM_LABELS]; for (int i = 0;i < NUM_LABELS;i++){ 126 mines[i] = new Label("",1); 125 127 128 mines[i].addMouseListener(this); mines[i].setName("" + i); 129 130 minepanel.setBackground(Color.lightGray); minepanel.add(mines[i]); 131 132 } //set up adornment for these labels 133 134 135 136 a = new Adorn(); a.setLabels(mines); 137 138 Thread aThread = new Thread(a); aThread.start(); 139 140 141 142 } 143 144 return mines; } 145 146 147 148 149 150 private Label[] getCaptions(){ if (captions==null){ captions = new Label[NUM_WORDS_IN_PUZZLE]; for (int i = 0;i < captions.length;i++){ 151 152 153 154 155 156 captions[i] = new Label(""); captions[i].setAlignment(Label.RIGHT); } } return captions; } 157 158 //************************** 159 160 private void getWords(){ 161 162 int i = 0; 163 164 //words passed in ...or use default wordlist = this.getParameter("WORDLIST"); 1 6 if (wordlist ==null){ 5 1 wordlist = "loco, 6 tonto,inteligente,trabajado,rico,romantico,holgazan,memory,queue,rational,stere 6 o,tranquil,weaver,zesty,blister,vanish,idiotic,range,scream,smile,spoof"; 167 168 } 169 170 wordlist = wordlist.toUpperCase(); 171 172 173 java.util.StringTokenizer st = new java.util.StringTokenizer(wordlist,","); 174 words = new Hashtable(st.countTokens()); 175 176 while (st.hasMoreElements()){ 177 178 179 180 words.put(new String(String.valueOf(i)), st.nextToken()); i++; } } 181 182 183 //***************************** private void 184 placeWords(){ 185 186 //clear solution solution = new String[NUM_LABELS]; 188 String selectedWord = new String(""); 187 189 190 191 192 //prepare selectedWords selectedWords = new Hashtable(NUM_WORDS_IN_PUZZLE); 193 194 195 196 for (int i = 0; i< NUM_WORDS_IN_PUZZLE;i++){ 197 198 boolean flag = false; 199 200 //don't add it to the selection if it's already there!! while(flag==false){ 201 202 //where to start int pos = (int)(java.lang.Math.random()*words.size()); 203 204 selectedWord = (String)words.get(String.valueOf(pos)); 205 206 if (selectedWords.contains(selectedWord) == false){ flag = true; 207 208 } } 209 210 char[] thisword = selectedWord.toCharArray(); 211 212 System.out.println(selectedWord + " ************************************"); 213 214 int looped = 0; 215 216 //the direction should be randomly selected: int[] directions = {NORTH,SOUTH,EAST,WEST,SW,SE,NE,NW}; 217 218 219 220 while (looped < 50){ //presume unfittable word beyond this... //try to position the word in the solution array 221 222 int startpos = (int)(java.lang.Math.random()* (square*square)); 223 224 int direction = (int)(java.lang.Math.random() * directions.length); 225 226 if (this.tryToFit(directions[direction], thisword, startpos)) { 227 228 //the word was placed!! So announce it captionPuzzle(selectedWord); 229 230 break; //out of while loop } 231 232 looped++; 233 234 235 236 } } } 237 //****************************** 238 private void addFillers(){ 239 240 241 242 243 244 245 //add any old filler text to labels with no text for (int i = 0;i < NUM_LABELS;i++){ if (solution[i]==null){ mines[i].setText(this.getRandomLetter()); 246 //mines[i].setText("-"); //TEST 247 248 249 250 }else{ mines[i].setText(solution[i]); 251 252 253 254 255 256 } } } 257 // *********************** 258 private void clearLabels(){ 259 260 //add any old filler text to labels with no text for (int i = 0;i < NUM_LABELS;i++){ 261 262 mines[i].setText(""); mines[i].setBackground(Color.lightGray); 263 264 } 265 266 //now clear the captions 267 268 for (int j = 0;j< NUM_WORDS_IN_PUZZLE;j++){ getCaptions()[j].setText(""); 269 270 } 271 272 } 273 274 private void addSelectedLabel(Integer i){ selectedLabels.addElement(i); 275 276 } 277 //*********************************** private String 278 getRandomLetter(){ 279 280 String pick = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 281 int spot = (int)(java.lang.Math.random() * 26); 282 283 284 String ret = pick.substring(spot,spot+1); 285 286 return ret; } 287 288 //**************************** 289 290 private synchronized void restart(){ this.getWords(); this.clearLabels(); this.placeWords() 291 292 293 294 ; this.addFillers(); } 295 296 //*************************** 297 298 private boolean tryToFit(int increment, char[] what, int startPos){ int charLength = what.length ; 299 300 int newPos = startPos; 301 302 for (int i = 0; i< charLength; i++){ try{ 303 // at this position if 304 ((solution[newPos]==null)||(solution[newPos].equals(String.valueOf(what[i])))){ 305 306 //solution matrix must be null or same as the character 307 308 //dont worry about boundary on last char... if ((!isBoundaryOK(newPos,increment)) || (i== charLength )){ 309 310 return false; } 311 312 313 314 315 316 //check another position in increment direction newPos = newPos + increment ; 317 318 } else{ // oh oh, roadblock! try another direction... 319 320 321 322 return false; } 323 324 }catch (Exception e){ return false; //end of the road! 325 326 } } 327 328 // if we got this far, we can position the char array in this direction 329 330 int charPos = startPos; for (int q = 0; q< charLength; q++ ){ 331 332 solution[charPos] = String.valueOf(what[q]); charPos = charPos + increment ; 333 334 335 336 } return true ; } 337 338 //*************************************** 339 340 341 342 private void captionPuzzle(String what){ if (selectedWords !=null){ 343 344 345 346 selectedWords.put(what,what); } 347 348 //find an empty spot in the captions labels 349 350 for (int i = 0;i< getCaptions().length; i++){ if (getCaptions()[i].getText().length()==0){ 351 352 353 getCaptions()[i].setText(what); return; } 354 } 355 356 357 358 } 359 360 /* this routine checks to see that a char the boundary of the grid 361 362 doesn't try to write itself in the wrong place ie, xxxh tabx xxxx 363 364 365 366 367 368 *note how the word bath is written if moving EAST 369 370 You can call this routine for all but the LAST char 371 372 373 374 375 376 */ private boolean isBoundaryOK(int newPos,int direction){ 377 378 379 380 381 382 switch (direction){ case NORTH: 383 384 385 386 if (newPos < square){ return false; 387 388 } return true; 389 390 case SOUTH: if (newPos + square >(square * square)){ 391 392 return false; } 393 394 return true; case EAST: 395 396 //System.out.println("East" + newPos + " " + square); if ( java.lang.Math.IEEEremainder(newPos+1,square)== 0){ 397 398 399 400 return false; } case WEST: //System.out.println("West" + newPos + " " + square); 401 402 if ( java.lang.Math.IEEEremainder(newPos,square)== 0){ return false; 403 404 } return true; 405 406 case NE: if (newPos < square){//same as north 407 408 return false; } 409 410 //System.out.println(" NE:" + newPos + " " + square); if ( java.lang.Math.IEEEremainder(newPos+1,square)== 0){ //same rule as East 411 412 } 413 414 //System.out.println("true"); return true; 415 416 417 418 return false; case SE: if (newPos + square >(square * square)){//same as south 419 420 return false; } 421 422 //System.out.println("SE:" + newPos + " " + square); if ( java.lang.Math.IEEEremainder(newPos+1,square)== 0){ //same rule as East 423 424 return false; } 425 //System.out.println("true"); 426 return true; 427 428 case SW: if (newPos + square >(square * square)){ //Same as south 429 430 return false; } 431 432 //System.out.println("SW " + newPos + " " + square); if ( java.lang.Math.IEEEremainder(newPos,square)== 0){//like west 433 434 return false; } 435 436 //System.out.println("true"); return true; 437 438 case NW: if (newPos < square){//same as north 439 440 } 441 442 //System.out.println("NW " + newPos + " " + square); 443 return false; if ( java.lang.Math.IEEEremainder(newPos,square)== 0){ //like west rule 444 return false; 445 446 } //System.out.println("true"); 447 448 return true; 449 450 default: break ; 451 452 } 453 454 return false; 455 } 456 } Aqui la clase responsable del color de los adornos de las letras Clase Adorn view source print? 01 import java.lang.*; 02 import java.awt.Color; 03 04 05 06 07 08 09 public class Adorn extends Object implements Runnable{ private java.awt.Label[] labelArray = null; private Color[] foreColors = {Color.magenta,Color.red,Color.cyan,Color.black}; 10 11 12 public void setLabels(java.awt.Label[] l){ 13 14 15 16 this.labelArray = l; } 17 18 19 20 21 22 public void run(){ while (true){ 23 24 25 26 27 28 try{ int myColor = (int)(java.lang.Math.random() * foreColors.length ); Color thisColor = foreColors[myColor]; int currentLabel = (int)(java.lang.Math.random() * labelArray.length ); 29 30 31 32 labelArray[currentLabel].setForeground(thisColor); 33 34 synchronized(this){ //lock it while doing this.. 35 String text = labelArray[currentLabel].getText(); 36 labelArray[currentLabel].setText(text); 37 38 } 39 40 Thread.currentThread().sleep(1000); 41 42 43 44 45 46 } catch (Exception e){} } } } PRUEBA Y DEPURACION Resultado