20 Commits

Author SHA1 Message Date
fddec0d82c . 2020-05-30 09:42:19 +01:00
e7e69263c7 tweaks 2020-05-29 15:16:34 +01:00
d6cb2c15d7 portable database location 2020-05-29 14:10:58 +01:00
4043fbd1e6 dump database 2020-05-29 13:50:59 +01:00
f2264d03c3 set property for db location 2020-05-29 13:50:51 +01:00
de4ab195ab Save input and grids to a database 2020-05-29 13:50:41 +01:00
ff53d97775 twiddle with classpath 2020-05-29 13:49:59 +01:00
5afcd67470 Increase maxtries to 5000 2020-05-29 11:12:20 +01:00
eb7a8d2801 add url footer 2020-05-29 11:00:00 +01:00
bca2d9b867 minor css tweak 2020-05-29 10:59:12 +01:00
4761199617 Improve formatting 2020-04-05 13:26:37 +01:00
cb87f5cbd5 More ignorance 2020-04-05 13:26:08 +01:00
f92d4df210 Add extra starter method 2020-04-05 13:25:51 +01:00
ce1e7a2fe5 fix makefile 2020-04-05 13:25:37 +01:00
87577944fb makefile 2020-04-05 12:25:43 +01:00
3fdd9c33ba removed C code as moved to another repo 2018-08-18 15:50:12 +01:00
55029b8b6f stash 2018-08-18 15:49:51 +01:00
2dece494e4 stash 2018-08-18 15:49:51 +01:00
foo
c10693ed17 new test case 2018-08-18 15:49:51 +01:00
911ab0006d Create LICENSE 2018-03-18 16:14:17 +00:00
25 changed files with 297 additions and 278 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.DS_Store
._.DS_Store
*.class
wordsearch.war
wordsearch.jar

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Matthew Slowe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

34
Makefile Normal file
View File

@ -0,0 +1,34 @@
JAVA = /usr/bin/java
LIBS = .:war/WEB-INF/lib/commons-lang.jar:war/WEB-INF/lib/sqlite-jdbc.jar
JAVAC = /usr/bin/javac
JFLAGS = -g -classpath $(LIBS)
SRCS = uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java \
uk/org/mafoo/wordsearch/Bounds.java \
uk/org/mafoo/wordsearch/GridFactory.java \
uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java \
uk/org/mafoo/wordsearch/Direction.java
JSPS = $(wildcard war/*.jsp war/*.css war/WEB-INF/jspf/*.jspf)
OBJS = ${SRCS:.java=.class}
.SUFFIXES: .java .class
.PHONY: default clean
default: wordsearch.war
clean:
rm -f $(OBJS) wordsearch.jar wordsearch.war
.java.class:
$(JAVAC) $(JFLAGS) $<
wordsearch.jar: $(OBJS)
jar cf $@ $(OBJS)
war/WEB-INF/lib/wordsearch.jar: wordsearch.jar
cp $< $@
wordsearch.war: war/WEB-INF/lib/wordsearch.jar $(JSPS)
jar -cvf $@ -C war .

View File

@ -12,15 +12,4 @@ A simple ```Makefile``` is provided:
$ make
```
Once built, you need to make a "war" file to deploy to your J2EE container (tested on Tomcat)
```
$ cd war && jar cfv ../wordsearch.war .
```
Then deploy your war file :-)
Alternatively you can test-run the engine...
```
$ make run <wordlist.txt
```

View File

@ -1,91 +0,0 @@
Aberdeenshire
Anglesey
Angus
Antrim
Argyll
Armagh
Ayrshire
Banffshire
Bedfordshire
Berkshire
Berwickshire
Brecknockshire
Buckinghamshire
Buteshire
Caernarfonshire
Caithness
Cambridgeshire
Cardiganshire
Carmarthenshire
Cheshire
Clackmannanshire
Cornwall
Cromartyshire
Cumberland
Denbighshire
Derbyshire
Devon
Dorset
Down
Dumbartonshire
Dumfriesshire
Durham
East Lothian
Essex
Fermanagh
Fife
Flintshire
Glamorgan
Gloucestershire
Hampshire
Herefordshire
Hertfordshire
Huntingdonshire
Invernessshire
Kent
Kincardineshire
Kirkcudbrightshire
Lanarkshire
Lancashire
Leicestershire
Lincolnshire
Londonderry
Merionethshire
Middlesex
Midlothian
Monmouthshire
Montgomeryshire
Morayshire
Nairnshire
Norfolk
Northamptonshire
Northumberland
Nottinghamshire
Orkney
Oxfordshire
Peeblesshire
Pembrokeshire
Perthshire
Radnorshire
Renfrewshire
Rossshire
Roxburghshire
Rutland
Selkirkshire
Shetland
Shropshire
Somerset
Staffordshire
Stirlingshire
Suffolk
Surrey
Sussex
Sutherland
Tyrone
Warwickshire
West Lothian
Westmorland
Wigtownshire
Wiltshire
Worcestershire
Yorkshire

1
schema.sql Normal file
View File

@ -0,0 +1 @@
CREATE TABLE grids (id integer primary key, ts timestamp default current_timestamp, remotehost varchar, input, size_x int, size_y int, simple tinyint, result varchar);

52
tags
View File

@ -1,52 +0,0 @@
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
Bounds uk/org/mafoo/wordsearch/Bounds.java /^ protected Bounds(int min_y, int max_y, int min_x, int max_x) {$/;" m class:Bounds
Bounds uk/org/mafoo/wordsearch/Bounds.java /^class Bounds {$/;" c
CouldNotPlaceWordException uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java /^ protected CouldNotPlaceWordException() {$/;" m class:CouldNotPlaceWordException
CouldNotPlaceWordException uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java /^class CouldNotPlaceWordException extends Exception {$/;" c
Direction uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" g
DistributedRandomNumberGenerator uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java /^ public DistributedRandomNumberGenerator() {$/;" m class:DistributedRandomNumberGenerator
DistributedRandomNumberGenerator uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java /^public class DistributedRandomNumberGenerator {$/;" c
E uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" e enum:Direction file:
GridFactory uk/org/mafoo/wordsearch/GridFactory.java /^public class GridFactory {$/;" c
MAX_TRIES uk/org/mafoo/wordsearch/GridFactory.java /^ static final int MAX_TRIES = 500;$/;" f class:GridFactory
N uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" e enum:Direction file:
NE uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" e enum:Direction file:
NW uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" e enum:Direction file:
S uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" e enum:Direction file:
SE uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" e enum:Direction file:
SW uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" e enum:Direction file:
W uk/org/mafoo/wordsearch/Direction.java /^enum Direction { N, NE, E, SE, S, SW, W, NW; };$/;" e enum:Direction file:
addNumber uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java /^ public void addNumber(int value, double distribution) {$/;" m class:DistributedRandomNumberGenerator
chars uk/org/mafoo/wordsearch/GridFactory.java /^ private static char[] chars = new char[] {$/;" f class:GridFactory file:
clone2d uk/org/mafoo/wordsearch/GridFactory.java /^ private static char[][] clone2d(char[][] source) {$/;" m class:GridFactory file:
directions uk/org/mafoo/wordsearch/GridFactory.java /^ private static Direction[] directions = new Direction[] { Direction.N, Direction.NE, Direction.E, Direction.SE, Direction.S, Direction.SW, Direction.W, Direction.NW };$/;" f class:GridFactory file:
distSum uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java /^ private double distSum;$/;" f class:DistributedRandomNumberGenerator file:
distribution uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java /^ private HashMap<Integer, Double> distribution;$/;" f class:DistributedRandomNumberGenerator file:
drng uk/org/mafoo/wordsearch/GridFactory.java /^ static DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();$/;" f class:GridFactory
dump2d uk/org/mafoo/wordsearch/GridFactory.java /^ private static void dump2d(char[][] g) {$/;" m class:GridFactory file:
getBounds uk/org/mafoo/wordsearch/GridFactory.java /^ private static Bounds getBounds(int height, int width, Direction direction, int length) {$/;" m class:GridFactory file:
getDirection uk/org/mafoo/wordsearch/GridFactory.java /^ private static Direction getDirection(boolean simple) {$/;" m class:GridFactory file:
getDistributedRandomNumber uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java /^ public int getDistributedRandomNumber() {$/;" m class:DistributedRandomNumberGenerator
getRandomChar uk/org/mafoo/wordsearch/GridFactory.java /^ private static char getRandomChar() {$/;" m class:GridFactory file:
main uk/org/mafoo/wordsearch/GridFactory.java /^ public static void main(String[] args) throws IOException {$/;" m class:GridFactory
makeGrid uk/org/mafoo/wordsearch/GridFactory.java /^ public static char[][] makeGrid(List<String> words, int height, int width) {$/;" m class:GridFactory
makeGrid uk/org/mafoo/wordsearch/GridFactory.java /^ public static char[][] makeGrid(List<String> words, int height, int width, boolean simple) {$/;" m class:GridFactory
max_x uk/org/mafoo/wordsearch/Bounds.java /^ int max_x;$/;" f class:Bounds
max_y uk/org/mafoo/wordsearch/Bounds.java /^ int max_y;$/;" f class:Bounds
min_x uk/org/mafoo/wordsearch/Bounds.java /^ int min_x;$/;" f class:Bounds
min_y uk/org/mafoo/wordsearch/Bounds.java /^ int min_y;$/;" f class:Bounds
move_x uk/org/mafoo/wordsearch/GridFactory.java /^ private static int move_x(int x, Direction d) {$/;" m class:GridFactory file:
move_y uk/org/mafoo/wordsearch/GridFactory.java /^ private static int move_y(int y, Direction d) {$/;" m class:GridFactory file:
placeWord uk/org/mafoo/wordsearch/GridFactory.java /^ private static char[][] placeWord(String word, char[][] grid, boolean simple) throws CouldNotPlaceWordException {$/;" m class:GridFactory file:
rnd uk/org/mafoo/wordsearch/GridFactory.java /^ static Random rnd = new Random();$/;" f class:GridFactory
toString uk/org/mafoo/wordsearch/Bounds.java /^ public String toString() {$/;" m class:Bounds
uk.org.mafoo.wordsearch uk/org/mafoo/wordsearch/Bounds.java /^package uk.org.mafoo.wordsearch;$/;" p
uk.org.mafoo.wordsearch uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java /^package uk.org.mafoo.wordsearch;$/;" p
uk.org.mafoo.wordsearch uk/org/mafoo/wordsearch/Direction.java /^package uk.org.mafoo.wordsearch;$/;" p
uk.org.mafoo.wordsearch uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java /^package uk.org.mafoo.wordsearch;$/;" p
uk.org.mafoo.wordsearch uk/org/mafoo/wordsearch/GridFactory.java /^package uk.org.mafoo.wordsearch;$/;" p

9
test.txt Executable file
View File

@ -0,0 +1,9 @@
Kitchen
Lounge
Study
Ballroom
Conservatory
Billiard Room
Library
Hall
Dining Room

View File

@ -6,7 +6,7 @@ import java.util.*;
public class GridFactory {
static Random rnd = new Random();
static final int MAX_TRIES = 500;
static final int MAX_TRIES = 5000;
/* https://www.math.cornell.edu/~mec/2003-2004/cryptography/subs/frequencies.html */
static DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
@ -37,7 +37,7 @@ public class GridFactory {
drng.addNumber(23, 0.0017d); // X
drng.addNumber(24, 0.0211d); // Y
drng.addNumber(25, 0.0007d); // Z
}
}
private static char[] chars = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
@ -61,8 +61,8 @@ public class GridFactory {
}
private static Direction[] directions = new Direction[] { Direction.N, Direction.NE, Direction.E, Direction.SE, Direction.S, Direction.SW, Direction.W, Direction.NW };
private static Direction getDirection(Modes mode) {
if(mode == Modes.SIMPLE || mode == Modes.CROSSWORD) {
private static Direction getDirection(boolean simple) {
if(simple) {
return rnd.nextBoolean() ? Direction.E : Direction.S;
} else {
return directions[rnd.nextInt(directions.length-1)];
@ -77,10 +77,10 @@ public class GridFactory {
Bounds b = new Bounds(0, height, 0, width);
length--; // arrays, duh
if(
direction == Direction.N ||
direction == Direction.NE ||
direction == Direction.N ||
direction == Direction.NE ||
direction == Direction.NW
) {
b.min_y = length;
@ -158,6 +158,10 @@ public class GridFactory {
return makeGrid(words, height, width, false, true);
}
public static char[][] makeGrid(List<String> words, int height, int width, boolean simple) {
return makeGrid(words, height, width, simple, true);
}
public static char[][] makeGrid(List<String> words, int height, int width, boolean simple, boolean fill) {
char[][] grid = new char[height][width];
@ -166,7 +170,7 @@ public class GridFactory {
int tries = 0;
while(true) {
try {
grid = placeWord(word, grid, mode);
grid = placeWord(word, grid, simple);
break;
} catch (CouldNotPlaceWordException e) {
if(tries > MAX_TRIES) {
@ -180,11 +184,11 @@ public class GridFactory {
}
}
if(mode != Modes.CROSSWORD) {
// Fill rest of grid
// Fill rest of grid
if(fill) {
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
if (grid[y][x] == Character.UNASSIGNED)
if (grid[y][x] == Character.UNASSIGNED)
// grid[y][x] = '_';
grid[y][x] = getRandomChar();
}
@ -194,18 +198,17 @@ public class GridFactory {
return grid;
}
private static char[][] placeWord(String word, char[][] grid, Modes mode) throws CouldNotPlaceWordException {
Direction direction = getDirection(mode);
private static char[][] placeWord(String word, char[][] grid, boolean simple) throws CouldNotPlaceWordException {
Direction direction = getDirection(simple);
Bounds b = getBounds(grid.length, grid[0].length, direction, word.length());
// System.out.println("[" + word + "] bounds: " + b);
int x = rnd.nextInt(b.max_x - b.min_x) + b.min_x;
int y = rnd.nextInt(b.max_y - b.min_y) + b.min_y;
// System.out.println("[" + word + "] Placing @ " + x + "," + y + " going " + direction);
char[][] tempgrid = clone2d(grid);
for( char c : word.toUpperCase().toCharArray() ) {
if(!Character.isLetter(c)) continue;
if(grid[y][x] != Character.UNASSIGNED) {
if (grid[y][x] != c) {
@ -217,7 +220,7 @@ public class GridFactory {
tempgrid[y][x] = c;
x = move_x(x, direction);
y = move_y(y, direction);
}
return tempgrid;
}

View File

@ -1,7 +0,0 @@
package uk.org.mafoo.wordsearch;
public enum Modes {
NORMAL,
SIMPLE,
CROSSWORD;
}

View File

@ -1,22 +0,0 @@
package uk.org.mafoo.wordsearch;
import java.sql.*;
class Store {
Connection conn = null;
protected Store(String dbfile) {
try {
Class.forName("org.sqlite.JDBC");
conn = DriverManager.getConnection("jdbc:sqlite:" + dbfile);
} catch ( Exception e ) {
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
System.exit(1);
}
}
protected storeInstance()
}

View File

@ -1,28 +0,0 @@
Letter Frequency
E 12.02
T 9.10
A 8.12
O 7.68
I 7.31
N 6.95
S 6.28
R 6.02
H 5.92
D 4.32
L 3.98
U 2.88
C 2.71
M 2.61
F 2.30
Y 2.11
W 2.09
G 2.03
P 1.82
B 1.49
V 1.11
K 0.69
X 0.17
Q 0.11
J 0.10
Z 0.07

19
war/WEB-INF/jspf/footer.jspf Executable file → Normal file
View File

@ -1,16 +1,3 @@
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
// tracker methods like "setCustomDimension" should be called before "trackPageView"
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//mafoo.org.uk/piwik/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', '3']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="//mafoo.org.uk/piwik/piwik.php?idsite=3&rec=1" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
<div id="footer">
Generated at: https://bombadil.mafoo.org.uk/wordsearch/
</div>

Binary file not shown.

Binary file not shown.

View File

@ -10,4 +10,20 @@
Wordsearch building app
</description>
</web-app>
<context-param>
<param-name>sqlite_db</param-name>
<param-value>/tmp/wordsearch.db</param-value>
</context-param>
<security-constraint>
<web-resource-collection>
<web-resource-name>dump</web-resource-name>
<url-pattern>/dump.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
</web-app>

View File

@ -3,6 +3,7 @@
<head>
<title>Wordsearch Builder: About</title>
<link rel="stylesheet" type="text/css" href="base.css" />
<link href="https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500&family=Roboto:wght@500&display=swap" rel="stylesheet">
</head>
<body>

View File

@ -1,5 +1,5 @@
body {
font-family: sans-serif;
body {
font-family: 'Roboto', sans-serif;
}
.tooltip {
@ -14,17 +14,16 @@ table, th, td {
}
table#grid td {
font-family: monospace;
font-size: 22px;
font-family: 'Fira Mono', monospace;
font-size: 14pt;
}
#wrapper {
width: 80%;
margin: 0 auto 60px auto;
align-content: center;
}
#wordsearch {
float: left;
margin-bottom: 24px;
}
#words {
@ -35,8 +34,11 @@ table#grid td {
#footer {
position:absolute;
bottom:0;
width:100%;
height:60px; /* Height of the footer */
}
textarea#textarea_words {
font-family: 'Fira Mono', monospace;
font-size: 10pt;
}
@media only print {

View File

@ -3,21 +3,21 @@
<head>
<title>Wordsearch builder</title>
<link rel="stylesheet" type="text/css" href="base.css" />
<link href="https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500&family=Roboto:wght@500&display=swap" rel="stylesheet">
</head>
<%@ page import="uk.org.mafoo.wordsearch.*" %>
<%@ page import="java.util.*" %>
<%@ page import="org.apache.commons.lang.StringUtils" %>
<%@ page import="org.apache.commons.lang.StringEscapeUtils" %>
<%@ page import="java.sql.*" %>
<%@ page import="org.sqlite.*" %>
<%@ page errorPage="error.jsp" %>
<%
int height = Integer.parseInt(request.getParameter("height"));
int width = Integer.parseInt(request.getParameter("width"));
Modes mode = Modes.NORMAL;
if(request.getParameter("mode") != null) {
if(request.getParameter("mode").equals("SIMPLE")) mode = Modes.SIMPLE;
if(request.getParameter("mode").equals("CROSSWORD")) mode = Modes.CROSSWORD;
}
boolean simple = request.getParameter("simple") != null;
String name = StringEscapeUtils.escapeHtml(request.getParameter("name"));
if (request.getParameter("words").length() > 2048) { throw new Exception("Input too large"); }
@ -25,25 +25,55 @@
List<String> words = new ArrayList<String>();
for ( String line : request.getParameter("words").split("\r\n")) {
words.add(line.trim());
words.add(line.trim().toLowerCase());
}
Collections.sort(words);
Collections.sort(words);
char[][] grid = GridFactory.makeGrid(words, height, width, mode);
Connection conn = DriverManager.getConnection(
"jdbc:sqlite:" + getServletContext().getRealPath("/WEB-INF/files/database.sqlite"));
PreparedStatement stmt = conn.prepareStatement(
"INSERT INTO grids (remotehost, input, size_x, size_y, simple) VALUES (?, ?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS);
// PreparedStatement getlastid = conn.prepareStatement("select last_insert_rowid();");
PreparedStatement stmt2 = conn.prepareStatement("UPDATE grids SET result=? WHERE id=?");
String csv = "";
stmt.setString(1, request.getRemoteHost());
stmt.setString(2, words.toString());
stmt.setInt(3, height);
stmt.setInt(4, width);
stmt.setBoolean(5, simple);
stmt.executeUpdate();
ResultSet record_id_rs = stmt.getGeneratedKeys();
int record_id = -1;
if(record_id_rs.next()){
record_id = record_id_rs.getInt(1);
}
// Actually generate the grid
char[][] grid = GridFactory.makeGrid(words, height, width, simple);
StringBuilder _csv = new StringBuilder();
for (char[] cs : grid) {
for(char c : cs) {
_csv.append(c);
_csv.append(",");
}
_csv.append("\r\n");
}
String csv = _csv.toString();
stmt2.setString(1, csv);
stmt2.setInt(2, record_id);
stmt2.executeUpdate();
conn.close();
%>
<body>
<h1><%= name %></h1>
<div class="noprint">
[ <a href="index.jsp">Start again</a> | <a id='csvdownload'>Download CSV</a> ]
[ <a href="index.jsp">Start again</a> | <a id='csvdownload' href="data:text/csv;base64,<%= Base64.getEncoder().encodeToString(csv.getBytes()) %>">Download CSV</a> ]
</div>
<script>
var csv = '<%= csv %>';
var csvdownload = document.getElementById('csvdownload');
csvdownload.href='data:text/csv;base64,' + btoa(csv);
</script>
</div>
<div id="wrapper">
@ -52,18 +82,18 @@
<table id="grid">
<% for(char[] row : grid) { %>
<tr>
<% for(char c : row) {
<% for(char c : row) {
csv += "" + c + ',';
%>
<td class="cell"><%= c != Character.UNASSIGNED ? c : "&nbsp" %></td>
<td class="cell"><%= c %></td>
<% } %>
</tr>
<%
<%
csv += "\\n";
}
%>
</table>
</div> <!-- end wordsearch -->
</div> <!-- end wordsearch -->
<div id="words">
<h2>Words</h2>
@ -73,7 +103,7 @@
<% } %>
</ul>
</div> <!-- end words -->
</div> <!-- end wrapper -->
</div> <!-- end wrapper -->
<br />
<br />
<%@include file="/WEB-INF/jspf/footer.jspf" %>

53
war/db.jsp Normal file
View File

@ -0,0 +1,53 @@
<%@ page contentType="text/html" %>
<%@ page import="java.sql.*" %>
<%@ page import="org.sqlite.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Database dump</title>
</head>
<body>
<h1>Database stats</h1>
<%
Connection conn =
DriverManager.getConnection("jdbc:sqlite:" + getServletContext().getRealPath("/WEB-INF/files/database.sqlite"));
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from sqlite_master where type='table' and name='grids';");
if(rs.next()) {
// we have a row and are probably ok
} else {
// Initialise the schema
PreparedStatement pstmt = conn.prepareStatement("CREATE TABLE grids (id integer primary key, ts timestamp default current_timestamp, remotehost varchar, input, size_x int, size_y int, simple tinyint, result varchar);");
pstmt.execute();
}
rs.close();
PreparedStatement ps_count = conn.prepareStatement("SELECT COUNT(*) FROM grids");
PreparedStatement ps_last = conn.prepareStatement("SELECT max(ts) FROM grids;");
ResultSet rs_count = ps_count.executeQuery();
ResultSet rs_last = ps_last.executeQuery();
int count = -1;
String last = "unknown";
if(rs_count.next()) {
count = rs_count.getInt(1);
}
if(rs_last.next()) {
last = rs_last.getString(1);
}
rs_count.close();
rs_last.close();
%>
<ul>
<li>Number of grids generated: <%= count %></li>
<li>Last grid generated at: <%= last %></li>
<li>Path to db: <pre><%= getServletContext().getRealPath("/WEB-INF/files/database.sqlite") %></pre></li>
</ul>
</body>
<%
conn.close();
%>
</html>

50
war/dump.jsp Normal file
View File

@ -0,0 +1,50 @@
<%@ page contentType="text/html" %>
<%@ page import="java.sql.*" %>
<%@ page import="org.sqlite.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Database dump</title>
</head>
<body>
<table border="1">
<thead>
<th>id</th>
<th>timestamp</th>
<th>remotehost</th>
<th>input</th>
<th>size_x</th>
<th>size_y</th>
<th>simple</th>
<th>result</th>
</thead>
<tbody>
<%
Connection conn =
DriverManager.getConnection("jdbc:sqlite:" + getServletContext().getInitParameter("sqlite_db"));
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select * from grids;");
while (rs.next()) {
out.println("<tr>");
out.println("<td>" + rs.getString("id") + "</td>");
out.println("<td>" + rs.getString("ts") + "</td>");
out.println("<td>" + rs.getString("remotehost") + "</td>");
out.println("<td><pre>" + rs.getString("input") + "</pre></td>");
out.println("<td>" + rs.getInt("size_x") + "</td>");
out.println("<td>" + rs.getInt("size_y") + "</td>");
out.println("<td>" + rs.getInt("simple") + "</td>");
out.println("<td><pre>" + rs.getString("result") + "</pre></td>");
out.println("</tr>");
}
rs.close();
conn.close();
%>
</tbody>
</table>
</body>
</html>

22
war/env.jsp Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Environment</h1>
<ul>
<li>You are connecting from: <%= request.getRemoteHost() %> (<%= request.getRemoteAddr() %>)</li>
<li>If present your X-Forwarded-For header is: <%= request.getHeader("X-Forwarded-For") %></li>
</ul>
<h2>Header dump</h2>
<pre>
<%
for (java.util.Enumeration<String> headers = request.getHeaderNames(); headers.hasMoreElements(); ) {
String h = headers.nextElement();
%>
<%= h %>=<%= request.getHeader(h) %>
<%
}
%>
</pre>
</body>

View File

@ -3,6 +3,7 @@
<head>
<title>Wordsearch Builder</title>
<link rel="stylesheet" type="text/css" href="base.css" />
<link href="https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500&family=Roboto:wght@500&display=swap" rel="stylesheet">
</head>
<body>
<h1>Wordsearch Builder</h1>
@ -11,7 +12,7 @@
<h2>Words</h2>
<form action="build.jsp" method="post">
Name: <input type="text" size="25" name="name" value="Wordsearch"><br />
<textarea name="words" rows="10">
<textarea id="textarea_words" name="words" rows="10">
Kitchen
Lounge
Study
@ -25,9 +26,7 @@ Dining Room
<br />
<input type="number" name="height" min="3" max="50" value="15" />
<input type="number" name="width" min="3" max="50" value="15" />
<input type="radio" name="mode" value="NORMAL" checked />Normal
<input type="radio" name="mode" value="SIMPLE" />Simple[<span class="tooltip" title="In simple mode, words are only placed Left-to-Right or Top-to-Bottom">?</span>]
<input type="radio" name="mode" value="CROSSWORD" />Crossword
<input type="checkbox" name="simple" value="yes">Simple [<span class="tooltip" title="In simple mode, words are only placed Left-to-Right or Top-to-Bottom">?</span>]</span>
<input type="submit" value="Build!" />
</form>

Binary file not shown.

Binary file not shown.