Initial commit
authorFrancois Fleuret <francois@fleuret.org>
Sat, 24 Aug 2013 09:16:15 +0000 (11:16 +0200)
committerFrancois Fleuret <francois@fleuret.org>
Sat, 24 Aug 2013 09:16:15 +0000 (11:16 +0200)
Grid.class [new file with mode: 0644]
Square.class [new file with mode: 0644]
Words.class [new file with mode: 0644]
Words.java [new file with mode: 0644]

diff --git a/Grid.class b/Grid.class
new file mode 100644 (file)
index 0000000..d902c49
Binary files /dev/null and b/Grid.class differ
diff --git a/Square.class b/Square.class
new file mode 100644 (file)
index 0000000..ffcb46f
Binary files /dev/null and b/Square.class differ
diff --git a/Words.class b/Words.class
new file mode 100644 (file)
index 0000000..2f6ab99
Binary files /dev/null and b/Words.class differ
diff --git a/Words.java b/Words.java
new file mode 100644 (file)
index 0000000..8b3c0ef
--- /dev/null
@@ -0,0 +1,611 @@
+/******************************************************************************
+
+ Cross-Words applet v1.5 (c) Francois FLEURET
+
+ This small applet is an interactive crosswords grid for web
+ pages. Mail <francois.fleuret@inria.fr> for bug reports and
+ questions.
+
+ In the past, I put his applet under a pure GPL licence. So, what was
+ expected to happen happened : commercial sites used it and I saw
+ people earning money with my work without giving me a single
+ buck. This is bad. So, now this software is distributed under the FFL
+ (Francois Fleuret Licence) which is the same as GPL version 2, plus
+ the following paragraph:
+
+ *
+ * RESTRICTION OF USE FOR APPLET SOFTWARES
+ *
+ * 13 The site the applet is used on must be a NON-PROFIT site, which
+ * implies it does not contain banners or any other mean to make money
+ * (including indirectly, for example as an ISP portal). The name of
+ * all the authors of the software and a link to the URL they provide
+ * in the source code must appear on any web page that uses the
+ * applet. If the source code was modified, the modified source must
+ * be downloadable from the site the applet is used on.
+ *
+
+ So, if you use this applet on a non-profit site, please add a link to
+ http://www-rocq.inria.fr/~fleuret and a short note indicating my name
+ as the author of the applet. For any other usage, please contact
+ me. Be sure we can make a deal for a reasonnable price.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+                                       Sept 11th 2000, François Fleuret
+
+******************************************************************************/
+
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+import java.lang.Object;
+
+class Square {
+    char solution;
+    char found;
+    boolean ajour;
+    boolean holdCursor;
+    boolean locked;
+    Color color;
+
+    Square(char c) {
+       solution = c;
+       found = ' ';
+       ajour = false;
+       locked = false;
+       color = Color.black;
+    }
+
+    void setFound(char c) { if(c != found) { found = c; ajour = false; } }
+
+    void putCursor() { if(!holdCursor) ajour = false; holdCursor = true; }
+
+    void remCursor() { if(holdCursor) ajour = false; holdCursor = false; }
+    
+    void lock(Color c) {
+       if(!locked) {
+           ajour = false;
+           locked = true;
+           color = c;
+       }
+    }
+}
+
+class Grid extends Panel implements KeyListener, MouseListener {
+    int gridWidth, gridHeight;
+    int xCursor, yCursor;
+    int nbLetters, nbFound;
+    boolean cursorHorizontal;
+
+    int xMargin, yMargin;
+    Square grid[][];
+    Font font, smallFont;
+    FontMetrics fontMetrics, smallFontMetrics;
+    int squareSize;
+
+    TextArea definitionArea;
+    String[][][] definitions;
+
+    Grid(Font f, Font sf,
+        FontMetrics fm, FontMetrics sfm,
+        int w, int h,
+        String content,
+        TextArea ta, String def) {
+
+       int x, y, xx, yy, k;
+
+       font = f; fontMetrics = fm;
+       smallFont = sf; smallFontMetrics = sfm;
+       squareSize = fontMetrics.getHeight();
+
+       gridWidth = w;
+       gridHeight = h;
+       grid = new Square[gridWidth][gridHeight];
+
+       yMargin = smallFontMetrics.getHeight();
+       xMargin = yMargin;
+
+       nbLetters = 0; nbFound = 0;
+       k = 0;
+       for(y = 0; y<gridHeight; y++) for(x = 0; x<gridWidth; x++) {
+           if(k<content.length())
+               grid[x][y] = new Square(content.charAt(k++));
+           else
+               grid[x][y] = new Square('.');
+           if(grid[x][y].solution != '.') nbLetters++;
+       }
+
+       xCursor = 0; yCursor = 0;
+       cursorHorizontal = true;
+       grid[xCursor][yCursor].putCursor();
+      
+       if(ta != null) {
+           definitionArea = ta;
+           definitions = new String[gridWidth][gridHeight][2];
+
+           String direction, sd;
+           int i, j;
+
+           direction="h";
+
+           for(y=0; y<gridHeight; y++) for(x=0; x<gridWidth; x++) {
+               definitions[x][y][0] = "";
+               definitions[x][y][1] = "";
+           }
+
+           j = 0;
+           while(j < def.length()-1) {
+
+               i = j; j = def.indexOf('/', i);
+               if((j > 0) && ((def.indexOf(':', i) > j) || (def.indexOf(':', i) < 0))) {
+                   direction = def.substring(i, j).toLowerCase();
+                   j++;
+               } else j = i;
+               
+
+               i = j;
+               y = 0;
+               while((def.charAt(i) >= 'a') && (def.charAt(i) <= 'z'))
+                   y = y*26 + ((int) def.charAt(i++)) - 'a';
+
+               x = 0;
+               while((def.charAt(i) >= '0') && (def.charAt(i) <= '9'))
+                   x = x*10 + ((int) def.charAt(i++)) - '0';
+               x--;
+               i++;
+
+               j = def.indexOf('/', i);
+               if(j < 0) j = def.length();
+               sd = def.substring(i, j);
+               j++;
+
+               if(direction.equals("horizontal")) {
+                   for(xx = x; (xx>=0) && (grid[xx][y].solution != '.'); xx--)
+                       definitions[xx][y][0] = sd;
+                   for(xx = x; (xx<gridWidth) && (grid[xx][y].solution != '.'); xx++) 
+                       definitions[xx][y][0] = sd;
+               } else if(direction.equals("vertical")) {
+                   for(yy = y; (yy>=0) && (grid[x][yy].solution != '.'); yy--)
+                       definitions[x][yy][1] = sd;
+                   for(yy = y; (yy<gridHeight) && (grid[x][yy].solution != '.'); yy++)
+                       definitions[x][yy][1] = sd;
+               } else System.out.println("Unknown orientation '" + direction + "'");
+           }
+       }
+
+       addKeyListener(this);
+       addMouseListener(this);
+    }
+
+    public void giveWord() {
+       int xx, yy;
+
+       int x = xCursor;
+       int y = yCursor;
+
+       if(cursorHorizontal) {
+           for(xx = x; (xx>=0) && (grid[xx][y].solution != '.'); xx--) {
+               grid[xx][y].setFound(grid[xx][y].solution);
+               grid[xx][y].lock(Color.red);
+           }
+         
+           for(xx = x; (xx<gridWidth) && (grid[xx][y].solution != '.'); xx++) {
+               grid[xx][y].setFound(grid[xx][y].solution);
+               grid[xx][y].lock(Color.red);
+           }
+       } else {
+           for(yy = y; (yy>=0) && (grid[x][yy].solution != '.'); yy--) {
+               grid[x][yy].setFound(grid[x][yy].solution);
+               grid[x][yy].lock(Color.red);
+           }
+
+           for(yy = y; (yy<gridHeight) && (grid[x][yy].solution != '.'); yy++) {
+               grid[x][yy].setFound(grid[x][yy].solution);
+               grid[x][yy].lock(Color.red);
+           }
+       }
+
+       nbFound = 0;
+       for(y = 0; y<gridHeight; y++) for(x = 0; x<gridWidth; x++)
+           if(grid[x][y].solution == grid[x][y].found) nbFound++;
+      
+       if(nbFound == nbLetters) {
+           for(y = 0; y<gridHeight; y++) for(x = 0; x<gridWidth; x++)
+               grid[x][y].lock(Color.blue);
+       }
+
+       repaint();
+    }
+
+    public void checkWord() {
+       boolean ok;
+       int xmin, xmax, xx;
+       int ymin, ymax, yy;
+
+       int x = xCursor;
+       int y = yCursor;
+
+       if(cursorHorizontal) {
+           ok = true;
+           for(xmin = x; ok && (xmin>=0) && (grid[xmin][y].solution != '.'); xmin--)
+               ok &= (grid[xmin][y].solution == grid[xmin][y].found);
+         
+           for(xmax = x; ok && (xmax<gridWidth) && (grid[xmax][y].solution != '.'); xmax++)
+               ok &= (grid[xmax][y].solution == grid[xmax][y].found);
+         
+           xmin++; xmax--;
+         
+           if(ok) for(xx = xmin; xx<=xmax; xx++) grid[xx][y].lock(Color.green);
+
+       } else {
+           ok = true;
+           for(ymin = y; ok && (ymin>=0) && (grid[x][ymin].solution != '.'); ymin--)
+               ok &= (grid[x][ymin].solution == grid[x][ymin].found);
+         
+           for(ymax = y; ok && (ymax<gridHeight) && (grid[x][ymax].solution != '.'); ymax++)
+               ok &= (grid[x][ymax].solution == grid[x][ymax].found);
+         
+           ymin++; ymax--;
+         
+           if(ok) for(yy = ymin; yy<=ymax; yy++) grid[x][yy].lock(Color.green);
+       }
+
+       repaint();
+    }
+
+    public synchronized void drawSquare(Graphics g, int x, int y) {
+       int arrowMargin = 2;
+       int xe, ye, deltaX;
+       int xf[], yf[];
+       char tmp[];
+       tmp = new char[1];
+       xe = x*squareSize+xMargin; ye = y*squareSize+yMargin;
+       g.setFont(font);
+
+       if(grid[x][y].solution != '.') {
+           g.setColor(Color.white);
+           g.fillRect(xe, ye, squareSize, squareSize);
+
+           if(grid[x][y].holdCursor) {
+               xf = new int[5]; yf = new int[5];
+               g.setColor(Color.gray);
+               if(cursorHorizontal) {
+                   xf[0] = xe + 1 + arrowMargin;
+                   yf[0] = ye + 1 + arrowMargin;
+                   xf[1] = xe + squareSize/2;
+                   yf[1] = ye + 1 + arrowMargin;
+                   xf[2] = xe + squareSize - 1 - arrowMargin;
+                   yf[2] = ye + squareSize/2;
+                   xf[3] = xe + squareSize/2;
+                   yf[3] = ye + squareSize - arrowMargin;
+                   xf[4] = xe + 1 + arrowMargin;
+                   yf[4] = ye + squareSize - arrowMargin;
+                   g.fillPolygon(xf, yf, 5);
+               }
+               else
+                   {
+                       xf[0] = xe + squareSize - arrowMargin;
+                       yf[0] = ye + 1 + arrowMargin;
+                       xf[1] = xe + squareSize - arrowMargin;
+                       yf[1] = ye + squareSize/2;
+                       xf[2] = xe + squareSize/2;  
+                       yf[2] = ye + squareSize - 1 - arrowMargin;
+                       xf[3] = xe + 1 + arrowMargin;
+                       yf[3] = ye + squareSize/2;
+                       xf[4] = xe + 1 + arrowMargin;
+                       yf[4] = ye + 1 + arrowMargin;
+                       g.fillPolygon(xf, yf, 5);
+                   }
+           }
+
+           g.setColor(Color.black);
+           g.drawRect(xe, ye, squareSize, squareSize);
+           tmp[0] = grid[x][y].found;
+           deltaX = (squareSize - fontMetrics.charWidth(tmp[0]))/2;
+
+           if(grid[x][y].locked) g.setColor(grid[x][y].color);
+           g.drawChars(tmp, 0, 1, xe + deltaX, ye+fontMetrics.getAscent());
+
+       } else {
+           g.setColor(Color.black);
+           g.fillRect(xe, ye, squareSize+1, squareSize+1);
+       }
+       grid[x][y].ajour = true;
+    }
+
+    public synchronized void update(Graphics g) {
+       int x, y;
+       for(y = 0; y<gridHeight; y++) for(x = 0; x<gridWidth; x++)
+           if(!grid[x][y].ajour) drawSquare(g, x, y);
+    }
+
+    public synchronized void paint(Graphics g) {
+       int x, y;
+       char tmp[];
+
+       g.setFont(smallFont);
+       g.setColor(Color.black);
+
+       tmp = new char[1];
+       for(y = 0; y<gridHeight; y++) {
+           tmp[0] = (char) (y + (int) 'a');
+           g.drawChars(tmp, 0, 1,
+                       xMargin - smallFontMetrics.charWidth(tmp[0]) - 3,
+                       y*squareSize + yMargin + smallFontMetrics.getAscent());
+       }
+
+       for(x = 0; x<gridWidth; x++)
+           g.drawString("" + (x+1),
+                        xMargin + x*squareSize + 3,
+                        yMargin - smallFontMetrics.getDescent() - 1);
+      
+       for(y = 0; y<gridHeight; y++) for(x = 0; x<gridWidth; x++)
+           drawSquare(g, x, y);
+    }
+
+    public void keyTyped(KeyEvent keyEvent) {}
+    public void keyReleased(KeyEvent keyEvent) {}
+
+    public void keyPressed(KeyEvent keyEvent) {
+       int x, y;
+       int code = keyEvent.getKeyCode();
+       char key = keyEvent.getKeyChar();
+
+       if(code == KeyEvent.VK_UP) {
+           y = yCursor-1;
+           while((y > 0) && (grid[xCursor][y].solution == '.')) y--;
+           if((y >= 0) && (grid[xCursor][y].solution != '.')) {
+               grid[xCursor][yCursor].remCursor();
+               yCursor = y;
+               grid[xCursor][yCursor].putCursor();
+           }
+       }
+       else if(code == KeyEvent.VK_DOWN) {
+           y = yCursor+1;
+           while((y < gridHeight-1) && (grid[xCursor][y].solution == '.')) y++;
+           if((y < gridHeight) && (grid[xCursor][y].solution != '.')) {
+               grid[xCursor][yCursor].remCursor();
+               yCursor = y;
+               grid[xCursor][yCursor].putCursor();
+           }
+       }
+       else if(code == KeyEvent.VK_LEFT) {
+           x = xCursor-1;
+           while((x > 0) && (grid[x][yCursor].solution == '.')) x--;
+           if((x >= 0) && (grid[x][yCursor].solution != '.')) {
+               grid[xCursor][yCursor].remCursor();
+               xCursor = x;
+               grid[xCursor][yCursor].putCursor();
+           }
+       }
+       else if(code == KeyEvent.VK_RIGHT) {
+           x = xCursor+1;
+           while((x < gridWidth-1) && (grid[x][yCursor].solution == '.')) x++;
+           if((x < gridWidth) && (grid[x][yCursor].solution != '.')) {
+               grid[xCursor][yCursor].remCursor();
+               xCursor = x;
+               grid[xCursor][yCursor].putCursor();
+           }
+       }
+       else if(code == Event.ENTER) {
+           cursorHorizontal = !cursorHorizontal;
+           grid[xCursor][yCursor].ajour = false;
+       }
+       else if(code == Event.BACK_SPACE) {
+           if((grid[xCursor][yCursor].found == ' ') || grid[xCursor][yCursor].locked) {
+               if(cursorHorizontal) {
+                   if(xCursor > 0)
+                       if(grid[xCursor - 1][yCursor].solution != '.') {
+                           grid[xCursor][yCursor].remCursor();
+                           xCursor--;
+                           grid[xCursor][yCursor].putCursor();
+                       }
+               } else {
+                   if(yCursor > 0)
+                       if(grid[xCursor][yCursor - 1].solution != '.') {
+                           grid[xCursor][yCursor].remCursor();
+                           yCursor--;
+                           grid[xCursor][yCursor].putCursor();
+                       }
+               }
+           }
+
+           if(!grid[xCursor][yCursor].locked) {
+               if(grid[xCursor][yCursor].found == grid[xCursor][yCursor].solution)
+                   nbFound--;
+               grid[xCursor][yCursor].setFound(' ');
+           }
+       } else if(key == ' ') {
+           if(definitionArea != null) {
+               if(cursorHorizontal) definitionArea.setText(definitions[xCursor][yCursor][0]);
+               else                 definitionArea.setText(definitions[xCursor][yCursor][1]);
+           }
+       } else if((key >= 'a') && (key <= 'z')) {
+           if(!grid[xCursor][yCursor].locked) {
+               if(grid[xCursor][yCursor].found == grid[xCursor][yCursor].solution)
+                   nbFound--;
+               grid[xCursor][yCursor].setFound((char) key);
+               if(grid[xCursor][yCursor].found == grid[xCursor][yCursor].solution)
+                   nbFound++;
+           }
+
+           if(cursorHorizontal) {
+               if(xCursor < gridWidth-1)
+                   if(grid[xCursor + 1][yCursor].solution != '.') {
+                       grid[xCursor][yCursor].remCursor();
+                       xCursor++;
+                       grid[xCursor][yCursor].putCursor();
+                   }
+           } else {
+               if(yCursor < gridHeight-1)
+                   if(grid[xCursor][yCursor + 1].solution != '.') {
+                       grid[xCursor][yCursor].remCursor();
+                       yCursor++;
+                       grid[xCursor][yCursor].putCursor();
+                   }
+           }
+
+           if(nbFound == nbLetters) {
+               for(y = 0; y<gridHeight; y++) for(x = 0; x<gridWidth; x++)
+                   grid[x][y].lock(Color.blue);
+           }
+       }
+
+       repaint();
+    }
+
+    public void mousePressed(MouseEvent mouseEvent) {
+       int xc, yc;
+       xc = (mouseEvent.getX()-xMargin)/squareSize;
+       if(xc < 0) xc = 0;
+       if(xc >= gridWidth) xc = gridWidth-1;
+       yc = (mouseEvent.getY()-yMargin)/squareSize;
+       if(yc < 0) yc = 0;
+       if(yc >= gridHeight) yc = gridHeight-1;
+    
+       if(grid[xc][yc].solution != '.') {
+           grid[xCursor][yCursor].remCursor();
+           xCursor = xc; yCursor = yc;
+           grid[xCursor][yCursor].putCursor();
+       }
+    
+       repaint();
+    }
+
+    public void mouseClicked(MouseEvent mouseEvent) {}
+    public void mouseReleased(MouseEvent e) {}
+    public void mouseEntered(MouseEvent e) {}
+    public void mouseExited(MouseEvent e) {}
+
+    public Dimension getPreferredSize() {
+       return new Dimension(xMargin + gridWidth*squareSize + 1,
+                            yMargin + gridHeight*squareSize + 1);
+    }
+
+}
+
+public class Words extends Applet implements ActionListener {
+    Grid grid;
+    Button checkButton, giveButton;
+    TextArea definitionArea;
+
+    public void init() {
+       String fontName, s, definitionString;
+       int fontSize;
+
+       Font f, sf;
+       FontMetrics fm, sfm;
+       int w, h, wd, hd;
+
+       s = getParameter("bgcolor");
+       if(s != null)
+           setBackground(new Color(Integer.parseInt(s)));
+
+       fontName = getParameter("font");
+       if(fontName == null) fontName = "Courier";
+
+       s = getParameter("fontsize");
+       if(s == null) fontSize = 48; else fontSize = Integer.parseInt(s);
+
+       f = new Font(fontName, Font.PLAIN, fontSize);
+
+       fm = getGraphics().getFontMetrics(f);
+
+       fontName = getParameter("smallfont");
+       if(fontName == null) fontName = "Courier";
+
+       s = getParameter("smallfontsize");
+       if(s == null) fontSize = 20; else fontSize = Integer.parseInt(s);
+
+       sf = new Font(fontName, Font.ITALIC, fontSize);
+       sfm = getGraphics().getFontMetrics(sf);
+
+       s = getParameter("gridwidth");
+       if(s == null) w = 1; else w = Integer.parseInt(s);
+
+       s = getParameter("gridheight");
+       if(s == null) h = 1; else h = Integer.parseInt(s);
+
+       definitionString = null;
+
+       s = getParameter("definitions");
+
+       if(s != null) {
+           int i, j;
+           wd = -1; hd = -1;
+
+           // Find the width and the height
+           i = 0; j = s.indexOf('x', i);
+           wd = Integer.parseInt(s.substring(i, j));
+           i = j+1; j = s.indexOf('/', i);
+           hd = Integer.parseInt(s.substring(i, j));
+
+           i = j+1; definitionString = s.substring(i, s.length());
+
+           if((wd > 0) && (hd > 0)) {
+               definitionArea = new TextArea("", hd, wd, TextArea.SCROLLBARS_NONE);
+               definitionArea.setEditable(false);
+           }
+       }
+
+       s = getParameter("content"); if(s == null) s = ".";
+       grid = new Grid(f, sf, fm, sfm, w, h, s, definitionArea, definitionString);
+       add("north", grid);
+
+       s = getParameter("checkwordlabel");
+       if(s != null) {
+           checkButton = new Button(s);
+           checkButton.addActionListener(this);
+       }
+
+       s = getParameter("givewordlabel");
+       if(s != null) {
+           giveButton = new Button(s);
+           giveButton.addActionListener(this);
+       }
+
+       if((checkButton != null) || (giveButton != null)) {
+           Panel buttonPanel;
+           buttonPanel = new Panel();
+           if(checkButton != null) buttonPanel.add(checkButton);
+           if(giveButton != null) buttonPanel.add(giveButton);
+           if(definitionArea != null) add("south", definitionArea);
+           add("south", buttonPanel);
+       }
+    }
+
+    public void actionPerformed(ActionEvent event) {
+       Object source = event.getSource();
+       if(source == checkButton) grid.checkWord();
+       else if(source == giveButton) grid.giveWord();
+    }
+
+    public String getAppletInfo() {
+       return "Word applet v1.5\n" +
+           "Written and (c) Francois Fleuret, mail to <francois.fleuret@inria.fr>\n" + 
+           "Check http://www-rocq.inria.fr/~fleuret\n";
+    }
+    
+    public String[][] getParameterInfo() {
+       String chose[][] = {
+           { "bgcolor", "integer", "Background Color (optional)" },
+           { "font", "font name", "Grid character font name (optional)" },
+           { "fontsize", "integer", "Grid character font size (optional)" },
+           { "smallfont", "font name", "Row and column index font name (optional)" },
+           { "smallfontsize", "integer", "Row and column index font size (optional)" },
+           { "gridwidth", "integer", "Grid width" },
+           { "gridheight", "integer", "Grid height" },
+           { "content", "string", "Grid content" },
+           { "definitions", "string", "Definitions (optional)" },
+           { "checkwordlabel", "string", "Label for the 'check word' button (optional)" },
+           { "givewordlabel", "string", "Label for the 'give word' button (optional)" }
+       };
+
+       return chose;
+    }
+}
+