Load "guilib.ring"

/*
 +--------------------------------------------------------------------------
 +        Program Name : ScreenDrawOnReSize.ring
 +        Date         : 2016.06.16
 +        Author       : Bert Mariani
 +        Purpose      : Re-Draw Chart after ReSize or move
 +--------------------------------------------------------------------------
*/

###-------------------------------
### DRAW CHART  size 1000 x 1000
###

###------------------------------

### Window Size
    WinLeft   = 80                  ### 80    Window position on screen
    WinTop    = 80                  ### 80    Window position on screen
    WinWidth  = 1000                ### 1000  Window Size - Horizontal-X WinWidth
    WinHeight = 750                 ### 750   Window Size - Vertical-Y WinHeight
    WinRight  = WinLeft + WinWidth  ### 1080
    WinBottom = WinTop  + WinHeight ### 830

### Label Box Size
    BoxLeft   = 40                  ###  Start corner   Label1 Box Start Position inside WIN1
    BoxTop    = 40                  ###  Start corner
    BoxWidth  = WinWidth  -80       ###  End   corner   Label1 Box Size
    BoxHeight = WinHeight -80       ###  End   corner

###----------------------------

New qapp {
        win1 = new qwidget() {

                ### Position and Size of WINDOW on the Screen
                setwindowtitle("DrawChart using QPainter")
                setgeometry( WinLeft, WinTop, WinWidth, WinHeight)

                win1{ setwindowtitle("Initial Window Position: " +" L " + WinLeft +" T " + WinTop +" Width" + width() +" Height " +  height() ) }

                ### ReSizeEvent ... Call WhereAreWe function
                myfilter = new qallevents(win1)
                myfilter.setResizeEvent("WhereAreWe()")
                installeventfilter(myfilter)

                ### Draw within this BOX
                label1 = new qlabel(win1) {
                        setgeometry(BoxLeft, BoxTop, BoxWidth, BoxHeight)
                        settext("We are Here")
                }

                ### Button Position and Size ... Call DRAW function
                new qpushbutton(win1) {
                        setgeometry( 30, 30, 80, 20)
                        settext("Draw")
                        setclickevent("Draw()")
                }

                ###---------------

                show()
        }

    exec()
}

###-----------------
### FUNCTION Draw
###-----------------

Func WhereAreWe
        Rec = win1.framegeometry()

        WinWidth  = win1.width()            ### 1000 Current Values
        WinHeight = win1.height()           ### 750

        WinLeft   = Rec.left() +8           ### <<< QT FIX because of Win Title
        WinTop    = Rec.top()  +30          ### <<< QT FIX because of Win Title
        WinRight  = Rec.right()
        WinBottom = Rec.bottom()

        BoxWidth  = WinWidth  -80           ### 950
        BoxHeight = WinHeight -80           ### 700

        win1{ setwindowtitle("Window ReSize: Win " +  WinWidth + "x" + WinHeight + " --- Box " + BoxWidth  + "x" + BoxHeight  +
                              " --- LT " +  WinLeft + "-"   + WinTop  + " --- RB " + WinRight + "-" + WinBottom      ) }

        See "We Are Here - setResizeEvent - "
        See " Win "  + WinWidth  + "x" + WinHeight + " --- Box  "  + BoxWidth + "x" + BoxHeight
        See " --- LT " + Winleft   + "-"   + WinTop    + " --- RB " + WinRight + "-"   + WinBottom +nl

          win1.setgeometry( WinLeft, WinTop, WinWidth, WinHeight )
        label1.setgeometry( BoxLeft, BoxTop, BoxWidth, BoxHeight )

return

Func Draw

        win1{ setwindowtitle("Draw Position: Win " +  WinWidth + "x" + WinHeight + " --- Box " + BoxWidth  + "x" + BoxHeight  +
                              " --- LT " +  WinLeft + "-"   + WinTop  + " --- RB " + WinRight + "-" + WinBottom      ) }

        See "Draw Position: " +  WinWidth + "x" + WinHeight + " --- Box " + BoxWidth  + "x" + BoxHeight  +
                              " --- LT " +  WinLeft + "-"   + WinTop  + " --- RB " + WinRight + "-" + WinBottom  + nl

  #     ##-----------------------------
        ### PEN Colors

        p1 = new qpicture()

            colorBlue = new qcolor() { setrgb(0,    0,255,255) }
            penBlue   = new qpen() { setcolor(colorBlue)  setwidth(1) }

        ###-----------------------
        ### PAINT the Chart

        new qpainter() {
                begin(p1)
                setpen(penBlue)

                ###---------------------
                ### Draw Line Chart

                drawline(        1 ,         1 , BoxWidth ,         1 )     ### WinTop line horizonal
                drawline(        1 ,         1 ,        1 , BoxHeight )     ### WinLeft Line vetical

                drawline(        1 , BoxHeight , BoxWidth , BoxHeight )     ### Bottom Line horizontal
                drawline( BoxWidth ,         1 , BoxWidth , BoxHeight )     ### WinRight Line vertical

                drawline( BoxWidth / 2 ,             1 , BoxWidth / 2 ,   BoxHeight     )    ### Central vertical
                drawline(            1 , BoxHeight / 2 , BoxWidth     ,   BoxHeight / 2 )    ### Central horizontal

                ###--------------------------------------------------

                endpaint()
        }

        label1 { setpicture(p1) show() }

return
###--------------------------------------------


package require Tk

# How to open a window
proc openWin {} {
    global win
    if {[info exists win] && [winfo exists $win]} {
        # Already existing; just reset
        wm deiconify $win
        wm state $win normal
        return
    }
    catch {destroy $win} ;# Squelch the old one
    set win [toplevel .t]
    pack [label $win.label -text "This is the window being manipulated"] \
        -fill both -expand 1
}
# How to close a window
proc closeWin {} {
    global win
    if {[info exists win] && [winfo exists $win]} {
        destroy $win
    }
}
# How to minimize a window
proc minimizeWin {} {
    global win
    if {[info exists win] && [winfo exists $win]} {
        wm state $win iconic
    }
}
# How to maximize a window
proc maximizeWin {} {
    global win
    if {[info exists win] && [winfo exists $win]} {
        wm state $win zoomed
        catch {wm attribute $win -zoomed 1} ;# Hack for X11
    }
}
# How to move a window
proc moveWin {} {
    global win
    if {[info exists win] && [winfo exists $win]} {
        scan [wm geometry $win] "%dx%d+%d+%d" width height x y
        wm geometry $win +[incr x 10]+[incr y 10]
    }
}
# How to resize a window
proc resizeWin {} {
    global win
    if {[info exists win] && [winfo exists $win]} {
        scan [wm geometry $win] "%dx%d+%d+%d" width height x y
        wm geometry $win [incr width 10]x[incr height 10]
    }
}

grid [label .l   -text "Window handle:"] [label .l2 -textvariable win]
grid [button .b1 -text "Open/Reset" -command openWin] -
grid [button .b2 -text "Close"      -command closeWin] -
grid [button .b3 -text "Minimize"   -command minimizeWin] -
grid [button .b4 -text "Maximize"   -command maximizeWin] -
grid [button .b5 -text "Move"       -command moveWin] -
grid [button .b6 -text "Resize"     -command resizeWin] -


/* window_management.wren */

var GTK_WINDOW_TOPLEVEL = 0
var GTK_ORIENTATION_VERTICAL = 1
var GTK_BUTTONBOX_CENTER = 5

foreign class GtkWindow {
    construct new(type) {}

    foreign title=(title)
    foreign setDefaultSize(width, height)

    foreign add(widget)
    foreign connectDestroy()

    foreign showAll()
    foreign iconify()
    foreign deiconify()
    foreign maximize()
    foreign unmaximize()
    foreign move(x, y)
    foreign resize(width, height)
    foreign hide()
    foreign destroy()
}

foreign class GtkButtonBox {
    construct new(orientation) {}

    foreign spacing=(interval)
    foreign layout=(layoutStyle)

    foreign add(button)
}

foreign class GtkButton {
    construct newWithLabel(label) {}

    foreign connectClicked()
}

class Gdk {
    foreign static flush()
}

class C {
    foreign static sleep(secs)
}

var Window = GtkWindow.new(GTK_WINDOW_TOPLEVEL)
Window.title = "Window management"
Window.setDefaultSize(400, 400)
Window.connectDestroy()

class GtkCallbacks {
    static btnClicked(label) {
        if (label == "Minimize") {
            Window.iconify()
        } else if (label == "Unminimize") {
            Window.deiconify()
        } else if (label == "Maximize") {
            Window.maximize()
        } else if (label == "Unmaximize") {
            Window.unmaximize()
        } else if (label == "Move") {
            Window.move(0, 0) // move to top left hand corner of display
        } else if (label == "Resize") {
            Window.resize(600, 600)
        } else if (label == "Hide") {
            Window.hide()
            Gdk.flush()
            C.sleep(5) // wait 5 seconds
            Window.showAll()
        } else if (label == "Close") {
            Window.destroy()
        }
    }
}

var buttonBox = GtkButtonBox.new(GTK_ORIENTATION_VERTICAL)
buttonBox.spacing = 20
buttonBox.layout = GTK_BUTTONBOX_CENTER
Window.add(buttonBox)

var btnMin = GtkButton.newWithLabel("Minimize")
btnMin.connectClicked()
buttonBox.add(btnMin)

var btnUnmin = GtkButton.newWithLabel("Unminimize")
btnUnmin.connectClicked()
buttonBox.add(btnUnmin)

var btnMax = GtkButton.newWithLabel("Maximize")
btnMax.connectClicked()
buttonBox.add(btnMax)

var btnUnmax = GtkButton.newWithLabel("Unmaximize")
btnUnmax.connectClicked()
buttonBox.add(btnUnmax)

var btnMove = GtkButton.newWithLabel("Move")
btnMove.connectClicked()
buttonBox.add(btnMove)

var btnResize = GtkButton.newWithLabel("Resize")
btnResize.connectClicked()
buttonBox.add(btnResize)

var btnHide = GtkButton.newWithLabel("Hide")
btnHide.connectClicked()
buttonBox.add(btnHide)

var btnClose = GtkButton.newWithLabel("Close")
btnClose.connectClicked()
buttonBox.add(btnClose)

Window.showAll()


;;; Single-file/interactive setup; large applications should define an ASDF system instead

(let* ((display (open-default-display))
       (screen (display-default-screen display))
       (root-window (screen-root screen))
       (black-pixel (screen-black-pixel screen))
       (white-pixel (screen-white-pixel screen))
       (window (create-window :parent root-window
                              :x 10 :y 10
                              :width 100 :height 100
                              :background white-pixel
                              :event-mask '(:exposure :key-press)))
       (gc (create-gcontext :drawable window
                            :foreground black-pixel
                            :background white-pixel)))
  (map-window window)
  (unwind-protect
       (event-case (display :discard-p t)
         (exposure ()
                   (draw-rectangle window gc 20 20 10 10 t)
                   (draw-glyphs window gc 10 50 "Hello, World!")
                   nil #| continue receiving events |#)
         (key-press ()
                    t #| non-nil result signals event-case to exit |#))
    (when window
      (destroy-window window))
    (when gc
      (free-gcontext gc))
    (close-display display)))


warnings off
require xlib.fs

0 value 	X11-D                 \ Display
0 value		X11-S                 \ Screen
0 value 	X11-root
0 value 	X11-GC
0 value 	X11-W                 \ Window
0 value 	X11-Black
0 value         X11-White
9 value 	X11-Top
0 value 	X11-Left
create 		X11-ev 96 allot

variable 	wm_delete

: X11-D-S 	X11-D X11-S ;
: X11-D-G       X11-D X11-GC ;
: X11-D-W 	X11-D X11-W ;
: X11-D-W-G     X11-D-W X11-GC ;

: open-X11 ( -- )
	X11-D 0= if 0 XOpendisplay to X11-D
		    X11-D    0= abort" can't connect to X server"
		    X11-D    XDefaultscreen to X11-S
		    X11-D-S  XRootwindow to X11-root
		    X11-D-S  XDefaultGC to X11-GC
		    X11-D-S  XBlackPixel to X11-Black
		    X11-D-S  XWhitePixel to X11-White
		then
	X11-W 0= if X11-D    X11-root X11-top X11-left 400 220  0 0 $808080 XCreateSimplewindow to X11-W
		    X11-W    0= abort" failed to create X11-window"
		    X11-D-W  $28043 XSelectInput drop
		    X11-D    s" WM_DELETE_WEINDOW" 1 XInternAtom wm_delete !
	            X11-D-W  wm_delete 1 XSetWMProtocols drop
		    X11-D-W  XMapwindow drop
		    X11-D    XFlush drop
		then ;

: close-graphics ( -- )
	X11-W if X11-D-W   XDestroywindow drop  0 to X11-W
	      then
        X11-D if X11-D     XClosedisplay  0 to X11-D
	      then ;

: foreground  	>r X11-D-G r> XSetForeground drop ;
: background  	>r X11-D-G r> XSetBackground drop ;
: keysym      	X11-ev     0 XLookupKeysym ;

: ev-loop
        begin X11-D X11-ev XNextEvent throw
	      X11-White    foreground
	      X11-Black    background
	      X11-D-W-G    100 100   s" Hello World" XDrawString drop
	      X11-D-W-G    100 120 150 25 XDrawRectangle drop
	      X11-D-W-G    110 135   s" Press ESC to exit ..." XDrawString drop
	      case X11-ev  @ $ffffffff and
	           3 of keysym XK_Escape = if exit then endof
	      endcase
	again ;
\ #### Test #####
0  open-X11
ev-loop
close-graphics
bye


package main

// Copyright (c) 2013 Alex Kesling
//
// 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 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.

import (
    "log"
    "github.com/jezek/xgb"
    "github.com/jezek/xgb/xproto"
)

func main() {
    // Open the connection to the X server
    X, err := xgb.NewConn()
    if err != nil {
        log.Fatal(err)
    }

    // geometric objects
    points := []xproto.Point{
        {10, 10},
        {10, 20},
        {20, 10},
        {20, 20}};

    polyline := []xproto.Point{
        {50, 10},
        { 5, 20},     // rest of points are relative
        {25,-20},
        {10, 10}};

    segments := []xproto.Segment{
        {100, 10, 140, 30},
        {110, 25, 130, 60}};

    rectangles := []xproto.Rectangle{
        { 10, 50, 40, 20},
        { 80, 50, 10, 40}};

    arcs := []xproto.Arc{
        {10, 100, 60, 40, 0, 90 << 6},
        {90, 100, 55, 40, 0, 270 << 6}};

    setup := xproto.Setup(X)
    // Get the first screen
    screen := setup.DefaultScreen(X)

    // Create black (foreground) graphic context
    foreground, _ := xproto.NewGcontextId(X)
    mask := uint32(xproto.GcForeground | xproto.GcGraphicsExposures)
    values := []uint32{screen.BlackPixel, 0}
    xproto.CreateGC(X, foreground, xproto.Drawable(screen.Root), mask, values)

    // Ask for our window's Id
    win, _ := xproto.NewWindowId(X)
    winDrawable := xproto.Drawable(win)

    // Create the window
    mask = uint32(xproto.CwBackPixel | xproto.CwEventMask)
    values = []uint32{screen.WhitePixel, xproto.EventMaskExposure}
    xproto.CreateWindow(X,                  // Connection
            screen.RootDepth,               // Depth
            win,                            // Window Id
            screen.Root,                    // Parent Window
            0, 0,                           // x, y
            150, 150,                       // width, height
            10,                             // border_width
            xproto.WindowClassInputOutput,  // class
            screen.RootVisual,              // visual
            mask, values)                   // masks

    // Map the window on the screen
    xproto.MapWindow(X, win)

    for {
        evt, err := X.WaitForEvent()
        switch evt.(type) {
            case xproto.ExposeEvent:
                /* We draw the points */
                xproto.PolyPoint(X, xproto.CoordModeOrigin, winDrawable, foreground, points)

                /* We draw the polygonal line */
                xproto.PolyLine(X, xproto.CoordModePrevious, winDrawable, foreground, polyline)

                /* We draw the segments */
                xproto.PolySegment(X, winDrawable, foreground, segments)

                /* We draw the rectangles */
                xproto.PolyRectangle(X, winDrawable, foreground, rectangles)

                /* We draw the arcs */
                xproto.PolyArc(X, winDrawable, foreground, arcs)

            default:
                /* Unknown event type, ignore it */
        }

        if err != nil {
            log.Fatal(err)
        }
    }
    return
}


import Graphics.X11.Xlib
import Control.Concurrent (threadDelay)

main = do
  display <- openDisplay ""
  let defScr = defaultScreen display
  rw <- rootWindow display defScr

  xwin <- createSimpleWindow display rw
      0 0 400 200 1
      (blackPixel display defScr)
      (whitePixel display defScr)

  setTextProperty display xwin "Rosetta Code: X11 simple window" wM_NAME

  mapWindow display xwin

  sync display False
  threadDelay (5000000)

  destroyWindow display xwin
  closeDisplay display


procedure main()
   W1 := open("X-Window","g","size=250,250","bg=black","fg=red") | stop("unable to open window")
   FillRectangle(W1,50,50,150,150)
   WDone(W1)
end

link graphics


using Xlib

function x11demo()
    # Open connection to the server.
    dpy = XOpenDisplay(C_NULL)
    dpy == C_NULL && error("unable to open display")
    scr = DefaultScreen(dpy)

    # Create a window.
    win = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 10, 10, 300, 100, 1,
                              BlackPixel(dpy, scr), WhitePixel(dpy, scr))

    # Select the kind of events we are interested in.
    XSelectInput(dpy, win, ExposureMask | KeyPressMask)

    # Show or in x11 terms map window.
    XMapWindow(dpy, win)

    # Run event loop.
    evt = Ref(XEvent())
    while true
        XNextEvent(dpy, evt)

        # Draw or redraw the window.
        if EventType(evt) == Expose
            XFillRectangle(dpy, win, DefaultGC(dpy, scr), 24, 24, 16, 16)
            XDrawString(dpy, win, DefaultGC(dpy, scr), 50, 50, "Hello, World! Press any key to exit.")
        end

        # Exit whenever a key is pressed.
        if EventType(evt) == KeyPress
            break
        end
    end

    # Shutdown server connection
    XCloseDisplay(dpy)
end

x11demo()


// Kotlin Native v0.3

import kotlinx.cinterop.*
import Xlib.*

fun main(args: Array<String>) {
    val msg = "Hello, World!"
    val d = XOpenDisplay(null)
    if (d == null) {
        println("Cannot open display")
        return
    }

    val s = XDefaultScreen(d)
    val w = XCreateSimpleWindow(d, XRootWindow(d, s), 10, 10, 160, 160, 1,
                                XBlackPixel(d, s), XWhitePixel(d, s))
    XSelectInput(d, w, ExposureMask or KeyPressMask)
    XMapWindow(d, w)
    val e = nativeHeap.alloc<XEvent>()

    while (true) {
        XNextEvent(d, e.ptr)
        if (e.type == Expose) {
            XFillRectangle(d, w, XDefaultGC(d, s), 55, 40, 50, 50)
            XDrawString(d, w, XDefaultGC(d, s), 45, 120, msg, msg.length)
        }
        else if (e.type == KeyPress) break
    }

    XCloseDisplay(d)
    nativeHeap.free(e)
}


\\ M2000 froms (windows) based on a flat, empty with no title bar, vb6 window and a user control.
\\ title bar is a user control in M2000 form
\\ On linux, wine application run M2000 interpreter traslating vb6 calls to window system.
Module SquareAndText2Window {
	Const black=0, white=15
	Declare form1 form
	\\ defaultwindow  title is the name of variable,here is: form1
	Rem With form1, "Title",  "A title for this window"
	Method form1,"move", 2000,3000,10000,8000  ' in twips
	layer form1 {
		Cls white
		Font "Verdana"
		Rem Window 12 , 10000,8000;  ' hide modr 13 using a REM before
		Rem
		Mode 12    ' 12 in pt
		Cls white,  2      ' fill white, set third raw for top of scrolling frame
		Pen  black
		Move 1000,2000  ' absolute coordinated in twips - use Step for relative coordinates
		\\ polygon use relative coordinates in twips
		polygon white, 1000,0,0,-1000,-1000,0,0,-1000
		\\ write text using graphic coordinates
		Move 1000, 3000 : Legend "Hello World", "Arial", 12
		\\ write text using layer as console (font Verdana)
		Print @(15,5),"Goodbye Wolrd"
		\\ 9120  7920 if we use window 12,10000, 8000 (cut exactly for console use)
		\\ 10000 8000 if we use Mode 12
		\\ scale.y include window height (including header)
		\\ the layer extend bellow
		Print scale.x, scale.y
	}
	\\ show form1 modal (continue to next line when we close the window)
	Method form1,"Show", 1
	\\ closing meand hide in M2000
	wait 1000  ' in msec
	Method form1,"move", random(2000, 10000),random(3000, 8000)
	\\ now show again
	Method form1,"Show", 1
	\\ now we close the form, releasing resources
	Declare form1 Nothing
}
SquareAndText2Window


Needs["GUIKit`"]
 ref = GUIRun[Widget["Panel", {
    Widget[
     "ImageLabel", {"data" ->
       Script[ExportString[Graphics[Rectangle[{0, 0}, {1, 1}]],
         "GIF"]]}],
    Widget["Label", { "text" -> "Hello World!"}]}
   ]]


import x11/[xlib,xutil,x]

const
  windowWidth = 1000
  windowHeight = 600
  borderWidth = 5
  eventMask = ButtonPressMask or KeyPressMask or ExposureMask

var
  display: PDisplay
  window: Window
  deleteMessage: Atom
  graphicsContext: GC

proc init() =
  display = XOpenDisplay(nil)
  if display == nil:
    quit "Failed to open display"

  let
    screen = XDefaultScreen(display)
    rootWindow = XRootWindow(display, screen)
    foregroundColor = XBlackPixel(display, screen)
    backgroundColor = XWhitePixel(display, screen)

  window = XCreateSimpleWindow(display, rootWindow, -1, -1, windowWidth,
      windowHeight, borderWidth, foregroundColor, backgroundColor)

  discard XSetStandardProperties(display, window, "X11 Example", "window", 0,
      nil, 0, nil)

  discard XSelectInput(display, window, eventMask)
  discard XMapWindow(display, window)

  deleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", false.XBool)
  discard XSetWMProtocols(display, window, deleteMessage.addr, 1)

  graphicsContext = XDefaultGC(display, screen)

proc drawWindow() =
  const text = "Hello, Nim programmers."
  discard XDrawString(display, window, graphicsContext, 10, 50, text, text.len)
  discard XFillRectangle(display, window, graphicsContext, 20, 20, 10, 10)

proc mainLoop() =
  ## Process events until the quit event is received
  var event: XEvent
  while true:
    discard XNextEvent(display, event.addr)
    case event.theType
    of Expose:
      drawWindow()
    of ClientMessage:
      if cast[Atom](event.xclient.data.l[0]) == deleteMessage:
        break
    of KeyPress:
      let key = XLookupKeysym(cast[PXKeyEvent](event.addr), 0)
      if key != 0:
        echo "Key ", key, " pressed"
    of ButtonPressMask:
      echo "Mouse button ", event.xbutton.button, " pressed at ",
          event.xbutton.x, ",", event.xbutton.y
    else:
      discard

proc main() =
  init()
  mainLoop()
  discard XDestroyWindow(display, window)
  discard XCloseDisplay(display)

main()


program xshowwindow;
{$mode objfpc}{$H+}

uses
  xlib, x, ctypes;

procedure ModalShowX11Window(AMsg: string);
var
  d: PDisplay;
  w: TWindow;
  e: TXEvent;
  msg: PChar;
  s: cint;
begin
  msg := PChar(AMsg);

  { open connection with the server }
  d := XOpenDisplay(nil);
  if (d = nil) then
  begin
    WriteLn('[ModalShowX11Window] Cannot open display');
    exit;
  end;
  s := DefaultScreen(d);

  { create window }
  w := XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 50, 1,
                           BlackPixel(d, s), WhitePixel(d, s));

  { select kind of events we are interested in }
  XSelectInput(d, w, ExposureMask or KeyPressMask);

  { map (show) the window }
  XMapWindow(d, w);

  { event loop }
  while (True) do
  begin
    XNextEvent(d, @e);
    { draw or redraw the window }
    if (e._type = Expose) then
    begin
      XFillRectangle(d, w, DefaultGC(d, s), 0, 10, 100, 3);
      XFillRectangle(d, w, DefaultGC(d, s), 0, 30, 100, 3);
      XDrawString   (d, w, DefaultGC(d, s), 5, 25, msg, strlen(msg));
    end;
    { exit on key press }
    if (e._type = KeyPress) then Break;
  end;

  { close connection to server }
  XCloseDisplay(d);
end;

begin
  ModalShowX11Window('Hello, World!');
end.


#!/usr/bin/perl -w
use strict;
use X11::Protocol;

my $X = X11::Protocol->new;

my $window = $X->new_rsrc;
$X->CreateWindow ($window,
                  $X->root,         # parent window
                  'InputOutput',    # class
                  0,                # depth, copy from parent
                  0,                # visual, copy from parent
                  0,0,              # X,Y (window manager will override)
                  300,100,          # width,height
                  0,                # border width
                  background_pixel => $X->black_pixel,
                  event_mask       => $X->pack_event_mask('Exposure',
                                                          'ButtonPress'),
                 );

my $gc = $X->new_rsrc;
$X->CreateGC ($gc, $window,
              foreground => $X->white_pixel);

$X->{'event_handler'} = sub {
  my %event = @_;
  my $event_name = $event{'name'};

  if ($event_name eq 'Expose') {
    $X->PolyRectangle ($window, $gc, [ 10,10,     # x,y top-left corner
                                       30,20 ]);  # width,height
    $X->PolyText8 ($window, $gc,
                   10, 55,    # X,Y of text baseline
                   [ 0,  # delta X
                     'Hello ... click mouse button to exit.' ]);

  } elsif ($event_name eq 'ButtonPress') {
    exit 0;
  }
};

$X->MapWindow ($window);
for (;;) {
  $X->handle_input;
}


#!/usr/bin/picolisp /usr/lib/picolisp/lib.l

(load "@lib/misc.l" "@lib/gcc.l")

(gcc "x11" '("-lX11") 'simpleWin)

#include <X11/Xlib.h>

any simpleWin(any ex) {
   any x = cdr(ex);
   int dx, dy;
   Display *disp;
   int scrn;
   Window win;
   XEvent ev;

   x = cdr(ex),  dx = (int)evCnt(ex,x);
   x = cdr(x),  dy = (int)evCnt(ex,x);
   x = evSym(cdr(x));
   if (disp = XOpenDisplay(NULL)) {
      char msg[bufSize(x)];

      bufString(x, msg);
      scrn = DefaultScreen(disp);
      win = XCreateSimpleWindow(disp, RootWindow(disp,scrn), 0, 0, dx, dy,
                           1, BlackPixel(disp,scrn), WhitePixel(disp,scrn) );
      XSelectInput(disp, win, ExposureMask | KeyPressMask | ButtonPressMask);
      XMapWindow(disp, win);
      for (;;) {
         XNextEvent(disp, &ev);
         switch (ev.type) {
         case Expose:
            XDrawRectangle(disp, win, DefaultGC(disp, scrn), 10, 10, dx-20, dy-20);
            XDrawString(disp, win, DefaultGC(disp, scrn), 30, 40, msg, strlen(msg));
            break;
         case KeyPress:
         case ButtonPress:
            XCloseDisplay(disp);
            return Nil;
         }
      }
   }
   return mkStr("Can't open Display");
}
/**/

(simpleWin 300 200 "Hello World")
(bye)


from Xlib import X, display

class Window:
    def __init__(self, display, msg):
        self.display = display
        self.msg = msg

        self.screen = self.display.screen()
        self.window = self.screen.root.create_window(
            10, 10, 100, 100, 1,
            self.screen.root_depth,
            background_pixel=self.screen.white_pixel,
            event_mask=X.ExposureMask | X.KeyPressMask,
            )
        self.gc = self.window.create_gc(
            foreground = self.screen.black_pixel,
            background = self.screen.white_pixel,
            )

        self.window.map()

    def loop(self):
        while True:
            e = self.display.next_event()

            if e.type == X.Expose:
                self.window.fill_rectangle(self.gc, 20, 20, 10, 10)
                self.window.draw_text(self.gc, 10, 50, self.msg)
            elif e.type == X.KeyPress:
                raise SystemExit

if __name__ == "__main__":
    Window(display.Display(), "Hello, World!").loop()


#lang racket/gui

(define frame (new frame%
                   [label "Example"]
                   [width 300]
                   [height 300]))
(new canvas% [parent frame]
             [paint-callback
              (lambda (canvas dc)
                (send dc set-scale 3 3)
                (send dc set-text-foreground "blue")
                (send dc draw-text "Don't Panic!" 0 0))])
(send frame show #t)


use NativeCall;

class Display is repr('CStruct') {
    has int32 $!screen;
    has int32 $!window;
 }
class GC      is repr('CStruct') {
    has int32 $!context;
}
class XEvent  is repr('CStruct') {
    has int32 $.type;
    method init { $!type = 0 }
}

sub XOpenDisplay(Str $name = ':0') returns Display is native('X11') { * }
sub XDefaultScreen(Display $) returns int32 is native('X11') { * }
sub XRootWindow(Display $, int32 $screen_number) returns int32 is native('X11') { * }
sub XBlackPixel(Display $, int32 $screen_number) returns int32 is native('X11') { * }
sub XWhitePixel(Display $, int32 $screen_number) returns int32 is native('X11') { * }
sub XCreateSimpleWindow(
    Display $, int32 $parent_window, int32 $x, int32 $y,
    int32 $width, int32 $height, int32 $border_width,
    int32 $border, int32 $background
) returns int32 is native('X11') { * }
sub XMapWindow(Display $, int32 $window) is native('X11') { * }
sub XSelectInput(Display $, int32 $window, int32 $mask) is native('X11') { * }
sub XFillRectangle(
    Display $, int32 $window, GC $, int32 $x, int32 $y, int32 $width, int32 $height
) is native('X11') { * }
sub XDrawString(
    Display $, int32 $window, GC $, int32 $x, int32 $y, Str $, int32 $str_length
) is native('X11') { * }
sub XDefaultGC(Display $, int32 $screen) returns GC is native('X11') { * }
sub XNextEvent(Display $, XEvent $e)              is native('X11') { * }
sub XCloseDisplay(Display $)                      is native('X11') { * }

my Display $display = XOpenDisplay()
    or die "Can not open display";

my int $screen = XDefaultScreen($display);
my int $window = XCreateSimpleWindow(
    $display,
    XRootWindow($display, $screen),
    10, 10, 100, 100, 1,
    XBlackPixel($display, $screen), XWhitePixel($display, $screen)
);
XSelectInput($display, $window, 1 +< 15 +| 1);
XMapWindow($display, $window);

my Str $msg = 'Hello, World!';
my XEvent $e .= new; $e.init;
loop {
    XNextEvent($display, $e);
    if $e.type == 12 {
	    XFillRectangle($display, $window, XDefaultGC($display, $screen), 20, 20, 10, 10);
	    XDrawString($display, $window, XDefaultGC($display, $screen), 10, 50, $msg, my int $ = $msg.chars);
    }
    elsif $e.type == 2 {
	    last;
    }
}
XCloseDisplay($display);


import scala.swing.{ MainFrame, SimpleSwingApplication }
import scala.swing.Swing.pair2Dimension

object WindowExample extends SimpleSwingApplication {
  def top = new MainFrame {
    title = "Hello!"
    centerOnScreen
    preferredSize = ((200, 150))
  }
}


open XWindows ;
val dp =  XOpenDisplay "" ;
val w = XCreateSimpleWindow (RootWindow dp) origin (Area {x=0,y=0,w=400,h=300}) 3 0 0xffffff ;
XMapWindow w;
XFlush dp ;
XDrawString w (DefaultGC dp) (XPoint {x=10,y=50})  "Hello World!" ;
XFlush dp ;


package provide xlib 1
package require critcl

critcl::clibraries -L/usr/X11/lib -lX11
critcl::ccode {
    #include <X11/Xlib.h>
    static Display *d;
    static GC gc;
}

# Display connection functions
critcl::cproc XOpenDisplay {Tcl_Interp* interp char* name} ok {
    d = XOpenDisplay(name[0] ? name : NULL);
    if (d == NULL) {
	Tcl_AppendResult(interp, "cannot open display", NULL);
	return TCL_ERROR;
    }
    gc = DefaultGC(d, DefaultScreen(d));
    return TCL_OK;
}
critcl::cproc XCloseDisplay {} void {
    XCloseDisplay(d);
}

# Basic window functions
critcl::cproc XCreateSimpleWindow {
    int x  int y  int width  int height  int events
} int {
    int s = DefaultScreen(d);
    Window w = XCreateSimpleWindow(d, RootWindow(d,s), x, y, width, height, 0,
	    BlackPixel(d,s), WhitePixel(d,s));
    XSelectInput(d, w, ExposureMask | events);
    return (int) w;
}
critcl::cproc XDestroyWindow {int w} void {
    XDestroyWindow(d, (Window) w);
}
critcl::cproc XMapWindow {int w} void {
    XMapWindow(d, (Window) w);
}
critcl::cproc XUnmapWindow {int w} void {
    XUnmapWindow(d, (Window) w);
}

# Event receiver
critcl::cproc XNextEvent {Tcl_Interp* interp} char* {
    XEvent e;
    XNextEvent(d, &e);
    switch (e.type) {
	case Expose:	return "type expose";
	case KeyPress:	return "type key";
	/* etc. This is a cheap hack version. */
	default:	return "type ?";
    }
}

# Painting functions
critcl::cproc XFillRectangle {int w int x int y int width int height} void {
    XFillRectangle(d, (Window)w, gc, x, y, width, height);
}
critcl::cproc XDrawString {int w int x int y Tcl_Obj* msg} void {
    int len;
    const char *str = Tcl_GetStringFromObj(msg, &len);
    XDrawString(d, (Window)w, gc, x, y, str, len);
}


/* window_creation_x11.wren */

var KeyPressMask = 1 << 0
var ExposureMask = 1 << 15
var KeyPress     = 2
var Expose       = 12

foreign class XGC {
    construct default(display, screenNumber) {}
}

foreign class XEvent {
    construct new() {}

    foreign eventType
}

foreign class XDisplay {
    construct openDisplay(displayName) {}

    foreign defaultScreen()

    foreign rootWindow(screenNumber)

    foreign blackPixel(screenNumber)

    foreign whitePixel(screenNumber)

    foreign selectInput(w, eventMask)

    foreign mapWindow(w)

    foreign closeDisplay()

    foreign nextEvent(eventReturn)

    foreign createSimpleWindow(parent, x, y, width, height, borderWidth, border, background)

    foreign fillRectangle(d, gc, x, y, width, height)

    foreign drawString(d, gc, x, y, string, length)
}

var xd = XDisplay.openDisplay("")
if (xd == 0) {
    System.print("Cannot open display.")
    return
}
var s = xd.defaultScreen()
var w = xd.createSimpleWindow(xd.rootWindow(s), 10, 10, 100, 100, 1, xd.blackPixel(s), xd.whitePixel(s))
xd.selectInput(w, ExposureMask | KeyPressMask)
xd.mapWindow(w)
var msg = "Hello, World!"
var e = XEvent.new()
while (true) {
    xd.nextEvent(e)
    var gc = XGC.default(xd, s)
    if (e.eventType == Expose) {
        xd.fillRectangle(w, gc, 20, 20, 10, 10)
        xd.drawString(w, gc, 10, 50, msg, msg.count)
    }
    if (e.eventType == KeyPress) break
}
xd.closeDisplay()


-V
   dirs = [[1,  0], [ 0,  1], [ 1, 1],
           [1, -1],           [-1, 0],
           [0, -1], [-1, -1], [-1, 1]]
   n_rows = 10
   n_cols = 10
   grid_size = n_rows * n_cols
   min_words = 25

T Grid
   num_attempts = 0
   [[String]] cells = [[‘’] * :n_cols] * :n_rows
   [String] solutions

F read_words(filename)
   [String] words
   L(line) File(filename).read_lines()
      V s = line.lowercase()
      I re:‘^[a-z]{3,10}’.match(s)
         words.append(s)
   R words

F place_message(Grid &grid; =msg)
   msg = msg.uppercase().replace(re:‘[^A-Z]’, ‘’)
   V message_len = msg.len
   I message_len C 0 <.< :grid_size
      V gap_size = :grid_size I/ message_len

      L(i) 0 .< message_len
         V pos = i * gap_size + random:(0 .. gap_size)
         grid.cells[pos I/ :n_cols][pos % :n_cols] = msg[i]

      R message_len
   R 0

F try_location(Grid &grid; word, direction, pos)
   V r = pos I/ :n_cols
   V c = pos % :n_cols
   V length = word.len

   I (:dirs[direction][0] ==  1 & (length + c) > :n_cols) |
     (:dirs[direction][0] == -1 & (length - 1) > c) |
     (:dirs[direction][1] ==  1 & (length + r) > :n_rows) |
     (:dirs[direction][1] == -1 & (length - 1) > r)
      R 0

   V rr = r
   V cc = c
   V i = 0
   V overlaps = 0

   L i < length
      I grid.cells[rr][cc] != ‘’ & grid.cells[rr][cc] != word[i]
         R 0
      cc += :dirs[direction][0]
      rr += :dirs[direction][1]
      i++

   rr = r
   cc = c
   i = 0

   L i < length
      I grid.cells[rr][cc] == word[i]
         overlaps++
      E
         grid.cells[rr][cc] = word[i]

      I i < length - 1
         cc += :dirs[direction][0]
         rr += :dirs[direction][1]
      i++

   V letters_placed = length - overlaps
   I letters_placed > 0
      grid.solutions.append(‘#<10 (#.,#.)(#.,#.)’.format(word, c, r, cc, rr))

   R letters_placed

F try_place_word(Grid &grid; word)
   V rand_dir = random:(0 .. :dirs.len)
   V rand_pos = random:(0 .. :grid_size)

   L(=direction) 0 .< :dirs.len
      direction = (direction + rand_dir) % :dirs.len

      L(=pos) 0 .< :grid_size
         pos = (pos + rand_pos) % :grid_size
         V letters_placed = try_location(&grid, word, direction, pos)
         I letters_placed > 0
            R letters_placed
   R 0

F create_word_search(&words)
   V grid = Grid()
   V num_attempts = 0

   L num_attempts < 100
      num_attempts++
      random:shuffle(&words)
      grid = Grid()
      V message_len = place_message(&grid, ‘Rosetta Code’)
      V target = :grid_size - message_len
      V cells_filled = 0
      L(word) words
         cells_filled += try_place_word(&grid, word)
         I cells_filled == target
            I grid.solutions.len >= :min_words
               grid.num_attempts = num_attempts
               R grid
            E
               L.break
   R grid

F print_result(grid)
   I grid.num_attempts == 0
      print(‘No grid to display’)
      R

   V size = grid.solutions.len

   print(‘Attempts: #.’.format(grid.num_attempts))
   print(‘Number of words: #.’.format(size))

   print("\n     0  1  2  3  4  5  6  7  8  9\n")
   L(r) 0 .< :n_rows
      print(‘#.   ’.format(r), end' ‘’)
      L(c) 0 .< :n_cols
         print(‘ #. ’.format(grid.cells[r][c]), end' ‘’)
      print()
   print()

   L(i) (0 .< size - 1).step(2)
      print(‘#.   #.’.format(grid.solutions[i], grid.solutions[i + 1]))

   I size % 2 == 1
      print(grid.solutions[size - 1])

print_result(create_word_search(&read_words(‘unixdict.txt’)))


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Wordseach
{
    static class Program
    {
        readonly static int[,] dirs = {{1, 0}, {0, 1}, {1, 1}, {1, -1}, {-1, 0},
            {0, -1}, {-1, -1}, {-1, 1}};

        class Grid
        {
            public char[,] Cells = new char[nRows, nCols];
            public List<string> Solutions = new List<string>();
            public int NumAttempts;
        }

        readonly static int nRows = 10;
        readonly static int nCols = 10;
        readonly static int gridSize = nRows * nCols;
        readonly static int minWords = 25;

        readonly static Random rand = new Random();

        static void Main(string[] args)
        {
            PrintResult(CreateWordSearch(ReadWords("unixdict.txt")));
        }

        private static List<string> ReadWords(string filename)
        {
            int maxLen = Math.Max(nRows, nCols);

            return System.IO.File.ReadAllLines(filename)
                .Select(s => s.Trim().ToLower())
                .Where(s => Regex.IsMatch(s, "^[a-z]{3," + maxLen + "}$"))
                .ToList();
        }

        private static Grid CreateWordSearch(List<string> words)
        {
            int numAttempts = 0;

            while (++numAttempts < 100)
            {
                words.Shuffle();

                var grid = new Grid();
                int messageLen = PlaceMessage(grid, "Rosetta Code");
                int target = gridSize - messageLen;

                int cellsFilled = 0;
                foreach (var word in words)
                {
                    cellsFilled += TryPlaceWord(grid, word);
                    if (cellsFilled == target)
                    {
                        if (grid.Solutions.Count >= minWords)
                        {
                            grid.NumAttempts = numAttempts;
                            return grid;
                        }
                        else break; // grid is full but we didn't pack enough words, start over
                    }
                }
            }
            return null;
        }

        private static int TryPlaceWord(Grid grid, string word)
        {
            int randDir = rand.Next(dirs.GetLength(0));
            int randPos = rand.Next(gridSize);

            for (int dir = 0; dir < dirs.GetLength(0); dir++)
            {
                dir = (dir + randDir) % dirs.GetLength(0);

                for (int pos = 0; pos < gridSize; pos++)
                {
                    pos = (pos + randPos) % gridSize;

                    int lettersPlaced = TryLocation(grid, word, dir, pos);
                    if (lettersPlaced > 0)
                        return lettersPlaced;
                }
            }
            return 0;
        }

        private static int TryLocation(Grid grid, string word, int dir, int pos)
        {
            int r = pos / nCols;
            int c = pos % nCols;
            int len = word.Length;

            //  check bounds
            if ((dirs[dir, 0] == 1 && (len + c) > nCols)
                    || (dirs[dir, 0] == -1 && (len - 1) > c)
                    || (dirs[dir, 1] == 1 && (len + r) > nRows)
                    || (dirs[dir, 1] == -1 && (len - 1) > r))
                return 0;

            int rr, cc, i, overlaps = 0;

            // check cells
            for (i = 0, rr = r, cc = c; i < len; i++)
            {
                if (grid.Cells[rr, cc] != 0 && grid.Cells[rr, cc] != word[i])
                {
                    return 0;
                }

                cc += dirs[dir, 0];
                rr += dirs[dir, 1];
            }

            // place
            for (i = 0, rr = r, cc = c; i < len; i++)
            {
                if (grid.Cells[rr, cc] == word[i])
                    overlaps++;
                else
                    grid.Cells[rr, cc] = word[i];

                if (i < len - 1)
                {
                    cc += dirs[dir, 0];
                    rr += dirs[dir, 1];
                }
            }

            int lettersPlaced = len - overlaps;
            if (lettersPlaced > 0)
            {
                grid.Solutions.Add($"{word,-10} ({c},{r})({cc},{rr})");
            }

            return lettersPlaced;
        }

        private static int PlaceMessage(Grid grid, string msg)
        {
            msg = Regex.Replace(msg.ToUpper(), "[^A-Z]", "");

            int messageLen = msg.Length;
            if (messageLen > 0 && messageLen < gridSize)
            {
                int gapSize = gridSize / messageLen;

                for (int i = 0; i < messageLen; i++)
                {
                    int pos = i * gapSize + rand.Next(gapSize);
                    grid.Cells[pos / nCols, pos % nCols] = msg[i];
                }
                return messageLen;
            }
            return 0;
        }

        public static void Shuffle<T>(this IList<T> list)
        {
            int n = list.Count;
            while (n > 1)
            {
                n--;
                int k = rand.Next(n + 1);
                T value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }

        private static void PrintResult(Grid grid)
        {
            if (grid == null || grid.NumAttempts == 0)
            {
                Console.WriteLine("No grid to display");
                return;
            }
            int size = grid.Solutions.Count;

            Console.WriteLine("Attempts: " + grid.NumAttempts);
            Console.WriteLine("Number of words: " + size);

            Console.WriteLine("\n     0  1  2  3  4  5  6  7  8  9");
            for (int r = 0; r < nRows; r++)
            {
                Console.Write("\n{0}   ", r);
                for (int c = 0; c < nCols; c++)
                    Console.Write(" {0} ", grid.Cells[r, c]);
            }

            Console.WriteLine("\n");

            for (int i = 0; i < size - 1; i += 2)
            {
                Console.WriteLine("{0}   {1}", grid.Solutions[i],
                        grid.Solutions[i + 1]);
            }
            if (size % 2 == 1)
                Console.WriteLine(grid.Solutions[size - 1]);

            Console.ReadLine();
        }
    }
}


#include <iomanip>
#include <ctime>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>

const int WID = 10, HEI = 10, MIN_WORD_LEN = 3, MIN_WORD_CNT = 25;

class Cell {
public:
    Cell() : val( 0 ), cntOverlap( 0 ) {}
    char val; int cntOverlap;
};
class Word {
public:
    Word( std::string s, int cs, int rs, int ce, int re, int dc, int dr ) :
      word( s ), cols( cs ), rows( rs ), cole( ce ), rowe( re ), dx( dc ), dy( dr ) {}
    bool operator ==( const std::string& s ) { return 0 == word.compare( s ); }
    std::string word;
    int cols, rows, cole, rowe, dx, dy;
};
class words {
public:
    void create( std::string& file ) {
        std::ifstream f( file.c_str(), std::ios_base::in );
        std::string word;
        while( f >> word ) {
            if( word.length() < MIN_WORD_LEN || word.length() > WID || word.length() > HEI ) continue;
            if( word.find_first_not_of( "abcdefghijklmnopqrstuvwxyz" ) != word.npos ) continue;
            dictionary.push_back( word );
        }
        f.close();
        std::random_shuffle( dictionary.begin(), dictionary.end() );
        buildPuzzle();
    }

    void printOut() {
        std::cout << "\t";
        for( int x = 0; x < WID; x++ ) std::cout << x << "  ";
        std::cout << "\n\n";
        for( int y = 0; y < HEI; y++ ) {
            std::cout << y << "\t";
            for( int x = 0; x < WID; x++ )
                std::cout << puzzle[x][y].val << "  ";
            std::cout << "\n";
        }
        size_t wid1 = 0, wid2 = 0;
        for( size_t x = 0; x < used.size(); x++ ) {
            if( x & 1 ) {
                if( used[x].word.length() > wid1 ) wid1 = used[x].word.length();
            } else {
                if( used[x].word.length() > wid2 ) wid2 = used[x].word.length();
            }
        }
        std::cout << "\n";
        std::vector<Word>::iterator w = used.begin();
        while( w != used.end() ) {
            std::cout << std::right << std::setw( wid1 ) << ( *w ).word << " (" << ( *w ).cols << ", " << ( *w ).rows << ") ("
                      << ( *w ).cole << ", " << ( *w ).rowe << ")\t";
            w++;
            if( w == used.end() ) break;
            std::cout << std::setw( wid2 ) << ( *w ).word << " (" << ( *w ).cols << ", " << ( *w ).rows << ") ("
                      << ( *w ).cole << ", " << ( *w ).rowe << ")\n";
            w++;
        }
        std::cout << "\n\n";
    }
private:
    void addMsg() {
        std::string msg = "ROSETTACODE";
        int stp = 9, p = rand() % stp;
        for( size_t x = 0; x < msg.length(); x++ ) {
            puzzle[p % WID][p / HEI].val = msg.at( x );
            p += rand() % stp + 4;
        }
    }
    int getEmptySpaces() {
        int es = 0;
        for( int y = 0; y < HEI; y++ ) {
            for( int x = 0; x < WID; x++ ) {
                if( !puzzle[x][y].val ) es++;
            }
        }
        return es;
    }
    bool check( std::string word, int c, int r, int dc, int dr ) {
        for( size_t a = 0; a < word.length(); a++ ) {
            if( c < 0 || r < 0 || c >= WID || r >= HEI ) return false;
            if( puzzle[c][r].val && puzzle[c][r].val != word.at( a ) ) return false;
            c += dc; r += dr;
        }
        return true;
    }
    bool setWord( std::string word, int c, int r, int dc, int dr ) {
        if( !check( word, c, r, dc, dr ) ) return false;
        int sx = c, sy = r;
        for( size_t a = 0; a < word.length(); a++ ) {
            if( !puzzle[c][r].val ) puzzle[c][r].val = word.at( a );
            else puzzle[c][r].cntOverlap++;
            c += dc; r += dr;
        }
        used.push_back( Word( word, sx, sy, c - dc, r - dr, dc, dr ) );
        return true;
    }
    bool add2Puzzle( std::string word ) {
        int x = rand() % WID, y = rand() % HEI,
            z = rand() % 8;
        for( int d = z; d < z + 8; d++ ) {
            switch( d % 8 ) {
                case 0: if( setWord( word, x, y,  1,  0 ) ) return true; break;
                case 1: if( setWord( word, x, y, -1, -1 ) ) return true; break;
                case 2: if( setWord( word, x, y,  0,  1 ) ) return true; break;
                case 3: if( setWord( word, x, y,  1, -1 ) ) return true; break;
                case 4: if( setWord( word, x, y, -1,  0 ) ) return true; break;
                case 5: if( setWord( word, x, y, -1,  1 ) ) return true; break;
                case 6: if( setWord( word, x, y,  0, -1 ) ) return true; break;
                case 7: if( setWord( word, x, y,  1,  1 ) ) return true; break;
            }
        }
        return false;
    }
    void clearWord() {
        if( used.size() ) {
            Word lastW = used.back();
            used.pop_back();

            for( size_t a = 0; a < lastW.word.length(); a++ ) {
                if( puzzle[lastW.cols][lastW.rows].cntOverlap == 0 ) {
                    puzzle[lastW.cols][lastW.rows].val = 0;
                }
                if( puzzle[lastW.cols][lastW.rows].cntOverlap > 0 ) {
                    puzzle[lastW.cols][lastW.rows].cntOverlap--;
                }
                lastW.cols += lastW.dx; lastW.rows += lastW.dy;
            }
        }
    }
    void buildPuzzle() {
        addMsg();
        int es = 0, cnt = 0;
        size_t idx = 0;
        do {
            for( std::vector<std::string>::iterator w = dictionary.begin(); w != dictionary.end(); w++ ) {
                if( std::find( used.begin(), used.end(), *w ) != used.end() ) continue;

                if( add2Puzzle( *w ) ) {
                    es = getEmptySpaces();
                    if( !es && used.size() >= MIN_WORD_CNT )
                        return;
                }
            }
            clearWord();
            std::random_shuffle( dictionary.begin(), dictionary.end() );

        } while( ++cnt < 100 );
    }
    std::vector<Word> used;
    std::vector<std::string> dictionary;
    Cell puzzle[WID][HEI];
};
int main( int argc, char* argv[] ) {
    unsigned s = unsigned( time( 0 ) );
    srand( s );
    words w; w.create( std::string( "unixdict.txt" ) );
    w.printOut();
    return 0;
}


import std.random : Random, uniform, randomShuffle;
import std.stdio;

immutable int[][] dirs = [
    [1,  0], [ 0,  1], [ 1, 1],
    [1, -1],           [-1, 0],
    [0, -1], [-1, -1], [-1, 1]
];

enum nRows = 10;
enum nCols = 10;
enum gridSize = nRows * nCols;
enum minWords = 25;

auto rnd = Random();

class Grid {
    int numAttempts;
    char[nRows][nCols] cells;
    string[] solutions;

    this() {
        for(int row=0; row<nRows; ++row) {
            cells[row] = 0;
        }
    }
}

void main() {
    printResult(createWordSearch(readWords("unixdict.txt")));
}

string[] readWords(string filename) {
    import std.algorithm : all, max;
    import std.ascii : isAlpha;
    import std.string : chomp, toLower;

    auto maxlen = max(nRows, nCols);

    string[] words;
    auto source = File(filename);
    foreach(line; source.byLine) {
        chomp(line);
        if (line.length >= 3 && line.length <= maxlen) {
            if (all!isAlpha(line)) {
                words ~= line.toLower.idup;
            }
        }
    }

    return words;
}

Grid createWordSearch(string[] words) {
    Grid grid;
    int numAttempts;

    outer:
    while(++numAttempts < 100) {
        randomShuffle(words);

        grid = new Grid();
        int messageLen = placeMessage(grid, "Rosetta Code");
        int target = gridSize - messageLen;

        int cellsFilled;
        foreach (string word; words) {
            cellsFilled += tryPlaceWord(grid, word);
            if (cellsFilled == target) {
                if (grid.solutions.length >= minWords) {
                    grid.numAttempts = numAttempts;
                    break outer;
                } else break; // grid is full but we didn't pack enough words, start over
            }
        }
    }
    return grid;
}

int placeMessage(Grid grid, string msg) {
    import std.algorithm : filter;
    import std.ascii : isUpper;
    import std.conv : to;
    import std.string : toUpper;

    msg = to!string(msg.toUpper.filter!isUpper);

    if (msg.length > 0 && msg.length < gridSize) {
        int gapSize = gridSize / msg.length;

        for (int i=0; i<msg.length; i++) {
            int pos = i * gapSize + uniform(0, gapSize, rnd);
            grid.cells[pos / nCols][pos % nCols] = msg[i];
        }
        return msg.length;
    }
    return 0;
}

int tryPlaceWord(Grid grid, string word) {
    int randDir = uniform(0, dirs.length, rnd);
    int randPos = uniform(0, gridSize, rnd);

    for (int dir=0; dir<dirs.length; dir++) {
        dir = (dir + randDir) % dirs.length;

        for (int pos=0; pos<gridSize; pos++) {
            pos = (pos + randPos) % gridSize;

            int lettersPlaced = tryLocation(grid, word, dir, pos);
            if (lettersPlaced > 0) {
                return lettersPlaced;
            }
        }
    }
    return 0;
}

int tryLocation(Grid grid, string word, int dir, int pos) {
    import std.format;

    int r = pos / nCols;
    int c = pos % nCols;
    int len = word.length;

    //  check bounds
    if ((dirs[dir][0] == 1 && (len + c) > nCols)
            || (dirs[dir][0] == -1 && (len - 1) > c)
            || (dirs[dir][1] == 1 && (len + r) > nRows)
            || (dirs[dir][1] == -1 && (len - 1) > r)) {
        return 0;
    }

    int i, rr, cc, overlaps = 0;

    // check cells
    for (i=0, rr=r, cc=c; i<len; i++) {
        if (grid.cells[rr][cc] != 0 && grid.cells[rr][cc] != word[i]) {
            return 0;
        }
        cc += dirs[dir][0];
        rr += dirs[dir][1];
    }

    // place
    for (i=0, rr=r, cc=c; i<len; i++) {
        if (grid.cells[rr][cc] == word[i]) {
            overlaps++;
        } else {
            grid.cells[rr][cc] = word[i];
        }

        if (i < len - 1) {
            cc += dirs[dir][0];
            rr += dirs[dir][1];
        }
    }

    int lettersPlaced = len - overlaps;
    if (lettersPlaced > 0) {
        grid.solutions ~= format("%-10s (%d,%d)(%d,%d)", word, c, r, cc, rr);
    }

    return lettersPlaced;
}

void printResult(Grid grid) {
    if (grid is null || grid.numAttempts == 0) {
        writeln("No grid to display");
        return;
    }
    int size = grid.solutions.length;

    writeln("Attempts: ", grid.numAttempts);
    writeln("Number of words: ", size);

    writeln("\n     0  1  2  3  4  5  6  7  8  9");
    for (int r=0; r<nRows; r++) {
        writef("\n%d   ", r);
        for (int c=0; c<nCols; c++) {
            writef(" %c ", grid.cells[r][c]);
        }
    }

    writeln;
    writeln;

    for (int i=0; i<size-1; i+=2) {
        writef("%s   %s\n", grid.solutions[i], grid.solutions[i + 1]);
    }
    if (size % 2 == 1) {
        writeln(grid.solutions[size - 1]);
    }
}


Randomize Timer ' OK getting a good puzzle every time

#Macro TrmSS (n)
    LTrim(Str(n))
#EndMacro

'overhauled
Dim Shared As ULong LengthLimit(3 To 10) 'reset in Initialize, track and limit longer words

'LoadWords opens file of words and sets
Dim Shared As ULong NWORDS 'set in LoadWords, number of words with length: > 2 and < 11  and just letters

' word file words (shuffled) to be fit into puzzle and index position
Dim Shared As String WORDSSS(1 To 24945), CWORDSSS(1 To 24945)
Dim Shared As ULong WORDSINDEX 'the file has 24945 words but many are unsuitable

'words placed in Letters grid, word itself (WSS) x, y head (WX, WY) and direction (WD), WI is the index to all these
Dim Shared As String WSS(1 To 100)
Dim Shared As ULong WX(1 To 100), WY(1 To 100), WD(1 To 100), WI

' letters grid and direction arrays
Dim Shared As String LSS(0 To 9, 0 To 9)
Dim Shared As Long DX(0 To 7), DY(0 To 7)
DX(0) = 1: DY(0) = 0
DX(1) = 1: DY(1) = 1
DX(2) = 0: DY(2) = 1
DX(3) = -1: DY(3) = 1
DX(4) = -1: DY(4) = 0
DX(5) = -1: DY(5) = -1
DX(6) = 0: DY(6) = -1
DX(7) = 1: DY(7) = -1

'to store all the words found embedded in the grid LSS()
Dim Shared As String ALLSS(1 To 200)
Dim Shared As ULong AllX(1 To 200), AllY(1 To 200), AllD(1 To 200) 'to store all the words found embedded in the grid LSS()
Dim Shared As ULong ALLindex

' signal successful fill of puzzle
Dim Shared FILLED As Boolean
Dim Shared As ULong try = 1

Sub LoadWords
    Dim As String wdSS
    Dim As ULong i, m, ff = FreeFile
    Dim ok As Boolean

    Open "unixdict.txt" For Input As #ff
    If Err > 0 Then
        Print !"\n unixdict.txt not found, program will end"
        Sleep 5000
        End
    End If
    While Eof(1) = 0
        Input #ff, wdSS
        If Len(wdSS) > 2 And Len(wdSS) < 11 Then
            ok = TRUE
            For m = 1 To Len(wdSS)
                If Asc(wdSS, m) < 97 Or Asc(wdSS, m) > 122 Then ok = FALSE: Exit For
            Next
            If ok Then i += 1: WORDSSS(i) = wdSS: CWORDSSS(i) = wdSS
        End If
    Wend
    Close #ff
    NWORDS = i
End Sub

Sub Shuffle
    Dim As ULong i, r
    For i = NWORDS To 2 Step -1
        r = Int(Rnd * i) + 1
        Swap WORDSSS(i), WORDSSS(r)
    Next
End Sub

Sub Initialize
    Dim As ULong r, c'', x, y, d
    Dim As String wdSS

    FILLED = FALSE
    For r = 0 To 9
        For c = 0 To 9
            LSS(c, r) = " "
        Next
    Next

    'reset word arrays by resetting the word index back to zero
    WI = 0

    'fun stuff for me but doubt others would like that much fun!
    'pluggin "basic", 0, 0, 2
    'pluggin "plus", 1, 0, 0

    'to assure the spreading of ROSETTA CODE
    LSS(Int(Rnd * 5) + 5, 0) = "R": LSS(Int(Rnd * 9) + 1, 1) = "O"
    LSS(Int(Rnd * 9) + 1, 2) = "S": LSS(Int(Rnd * 9) + 1, 3) = "E"
    LSS(1, 4) = "T": LSS(9, 4) = "T": LSS(Int(10 * Rnd), 5) = "A"
    LSS(Int(10 * Rnd), 6) = "C": LSS(Int(10 * Rnd), 7) = "O"
    LSS(Int(10 * Rnd), 8) = "D": LSS(Int(10 * Rnd), 9) = "E"

    'reset limits
    LengthLimit(3) = 200
    LengthLimit(4) = 6
    LengthLimit(5) = 3
    LengthLimit(6) = 2
    LengthLimit(7) = 1
    LengthLimit(8) = 0
    LengthLimit(9) = 0
    LengthLimit(10) = 0

    'reset word order
    Shuffle
End Sub

'for fun plug-in of words
Sub pluggin (wdSS As String, x As Long, y As Long, d As Long)

    For i As ULong = 0 To Len(wdSS) - 1
        LSS(x + i * DX(d), y + i * DY(d)) = Mid(wdSS, i + 1, 1)
    Next
    WI += WI
    WSS(WI) = wdSS: WX(WI) = x: WY(WI) = y: WD(WI) = d
End Sub

' Function TrmSS (n As Integer) As String
'     TrmSS = RTrim(LTrim(Str(n)))
' End Function

'used in PlaceWord
Function CountSpaces () As ULong
    Dim As ULong x, y, count

    For y = 0 To 9
        For x = 0 To 9
            If LSS(x, y) = " " Then count += 1
        Next
    Next
    CountSpaces = count
End Function

Sub ShowPuzzle
    Dim As ULong i, x, y
    'Dim As String wateSS

    Cls
    Print "    0 1 2 3 4 5 6 7 8 9"
    Locate 3, 1
    For i = 0 To 9
        Print TrmSS(i)
    Next
    For y = 0 To 9
        For x = 0 To 9
            Locate y + 3, 2 * x + 5: Print LSS(x, y)
        Next
    Next
    For i = 1 To WI
        If i < 21 Then
            Locate i + 1, 30: Print TrmSS(i); " "; WSS(i)
        ElseIf i < 41 Then
            Locate i - 20 + 1, 45: Print TrmSS(i); " "; WSS(i)
        ElseIf i < 61 Then
            Locate i - 40 + 1, 60: Print TrmSS(i); " "; WSS(i)
        End If
    Next
    Locate 18, 1: Print "Spaces left:"; CountSpaces
    Locate 19, 1: Print NWORDS
    Locate 20, 1: Print Space(16)
    If WORDSINDEX Then Locate 20, 1: Print TrmSS(WORDSINDEX); " "; WORDSSS(WORDSINDEX)
    'LOCATE 15, 1: INPUT "OK, press enter... "; wateSS
End Sub

'used in PlaceWord
Function Match (word As String, template As String) As Long
    Dim i As ULong
    Dim c As String
    Match = 0
    If Len(word) <> Len(template) Then Exit Function
    For i = 1 To Len(template)
        If Asc(template, i) <> 32 And (Asc(word, i) <> Asc(template, i)) Then Exit Function
    Next
    Match = -1
End Function

'heart of puzzle builder
Sub PlaceWord
    ' place the words randomly in the grid
    ' start at random spot and work forward or back 100 times = all the squares
    ' for each open square try the 8 directions for placing the word
    ' even if word fits Rossetta Challenge task requires leaving 11 openings to insert ROSETTA CODE,
    ' exactly 11 spaces needs to be left, if/when this occurs FILLED will be set true to signal finished to main loop
    ' if place a word update LSS, WI, WSS(WI), WX(WI), WY(WI), WD(WI)

    Dim As String wdSS, templateSS
    Dim As Long rdir
    Dim As ULong wLen, spot, testNum
    Dim As ULong x, y, d, dNum, rdd,  i, j

    Dim As Boolean b1, b2

    wdSS = WORDSSS(WORDSINDEX) ' the right side is all shared
    ' skip too many long words
    If LengthLimit(Len(wdSS)) Then LengthLimit(Len(wdSS)) += 1 Else Exit Sub 'skip long ones
    wLen = Len(wdSS) - 1  '   from the spot there are this many letters to check
    spot = Int(Rnd * 100) '   a random spot on grid
    testNum = 1           '   when this hits 100 we've tested all possible spots on grid
    If Rnd < .5 Then rdir = -1 Else rdir = 1 ' go forward or back from spot for next test
    While testNum < 101
        y = spot \ 10
        x = spot Mod 10
        If LSS(x, y) = Mid(wdSS, 1, 1) Or LSS(x, y) = " " Then
            d = Int(8 * Rnd)
            If Rnd < .5 Then rdd = -1 Else rdd = 1
            dNum = 1
            While dNum < 9
                'will wdSS fit? from  at x, y
                templateSS = ""
                b1 = wLen * DX(d) + x >= 0 And wLen * DX(d) + x <= 9
                b2 = wLen * DY(d) + y >= 0 And wLen * DY(d) + y <= 9
                If b1 And b2 Then 'build the template of letters and spaces from Letter grid
                    For i = 0 To wLen
                        templateSS += LSS(x + i * DX(d), y + i * DY(d))
                    Next
                    If Match(wdSS, templateSS) Then 'the word will fit but does it fill anything?
                        For j = 1 To Len(templateSS)
                            If Asc(templateSS, j) = 32 Then 'yes a space to fill
                                For i = 0 To wLen
                                    LSS(x + i * DX(d), y + i * DY(d)) = Mid(wdSS, i + 1, 1)
                                Next
                                WI += 1
                                WSS(WI) = wdSS: WX(WI) = x: WY(WI) = y: WD(WI) = d
                                ShowPuzzle
                                If CountSpaces = 0 Then FILLED = TRUE
                                Exit Sub 'get out now that word is loaded
                            End If
                        Next
                        'if still here keep looking
                    End If
                End If
                d = (d + 8 + rdd) Mod 8
                dNum += 1
            Wend
        End If
        spot = (spot + 100 + rdir) Mod 100
        testNum += 1
    Wend
End Sub

Sub FindAllWords
    Dim As String wdSS, templateSS, wateSS
    Dim As ULong wLen, x, y, d, j
    Dim As Boolean b1, b2

    For i As ULong = 1 To NWORDS
        wdSS = CWORDSSS(i)
        wLen = Len(wdSS) - 1
        For y = 0 To 9
            For x = 0 To 9
                If LSS(x, y) = Mid(wdSS, 1, 1) Then
                    For d = 0 To 7
                        b1 = wLen * DX(d) + x >= 0 And wLen * DX(d) + x <= 9
                        b2 = wLen * DY(d) + y >= 0 And wLen * DY(d) + y <= 9
                        If b1 And b2 Then 'build the template of letters and spaces from Letter grid
                            templateSS = ""
                            For j = 0 To wLen
                                templateSS += LSS(x + j * DX(d), y + j * DY(d))
                            Next
                            If templateSS = wdSS Then 'found a word
                                'store it
                                ALLindex += 1
                                ALLSS(ALLindex) = wdSS: AllX(ALLindex) = x: AllY(ALLindex) = y: AllD(ALLindex) = d
                                'report it
                                Locate 22, 1: Print Space(50)
                                Locate 22, 1: Print "Found: "; wdSS; " ("; TrmSS(x); ", "; TrmSS(y); ") >>>---> "; TrmSS(d);
                                Input " Press enter...", wateSS
                            End If
                        End If
                    Next
                End If
            Next
        Next
    Next
End Sub

Sub FilePuzzle
    Dim As ULong i, r, c, ff = FreeFile
    Dim As String bSS

    Open "WS Puzzle.txt" For Output As #ff
    Print #ff, "    0 1 2 3 4 5 6 7 8 9"
    Print #ff,
    For r = 0 To 9
        bSS = TrmSS(r) + "   "
        For c = 0 To 9
            bSS += LSS(c, r) + " "
        Next
        Print #ff, bSS
    Next
    Print #ff,
    Print #ff, "Directions >>>---> 0 = East, 1 = SE, 2 = South, 3 = SW, 4 = West, 5 = NW, 6 = North, 7 = NE"
    Print #ff,
    Print #ff, "              These are the items from unixdict.txt used to build the puzzle:"
    Print #ff,
    For i = 1 To WI Step 2
        Print #ff, Right(Space(7) + TrmSS(i), 7); ") "; Right(Space(7) + WSS(i), 10); " ("; TrmSS(WX(i)); ", "; TrmSS(WY(i)); ") >>>---> "; TrmSS(WD(i));
        If i + 1 <= WI Then
            Print #ff, Right(Space(7) + TrmSS(i + 1), 7); ") "; Right(Space(7) + WSS(i + 1), 10); " ("; TrmSS(WX(i + 1)); ", "; TrmSS(WY(i + 1)); ") >>>---> "; TrmSS(WD(i + 1))
        Else
            Print #ff,
        End If
    Next
    Print #ff,
    Print #ff, "            These are the items from unixdict.txt found embedded in the puzzle:"
    Print #ff,
    For i = 1 To ALLindex Step 2
        Print #ff, Right(Space(7) + TrmSS(i), 7); ") "; Right(Space(7) + ALLSS(i), 10); " ("; TrmSS(AllX(i)); ", "; TrmSS(AllY(i)); ") >>>---> "; TrmSS(AllD(i));
        If i + 1 <= ALLindex Then
            Print #ff, Right(Space(7) + TrmSS(i + 1), 7); ") "; Right(Space(7) + ALLSS(i + 1), 10); " ("; TrmSS(AllX(i + 1)); ", "; TrmSS(AllY(i + 1)); ") >>>---> "; TrmSS(AllD(i + 1))
        Else
            Print #ff, ""
        End If
    Next
    Print #ff,
    Print #ff, "On try #" + TrmSS(try) + " a successful puzzle was built and filed."
    Close #ff
End Sub

LoadWords 'this sets NWORDS count to work with

While try < 11
    Initialize
    ShowPuzzle
    For WORDSINDEX = 1 To NWORDS
        PlaceWord
        ' ShowPuzzle
        If FILLED Then Exit For
    Next
    If Not filled And WI > 24 Then ' we have 25 or more words
        For y As ULong = 0 To 9    ' fill spaces with random letters
            For x As ULong = 0 To 9
                If LSS(x, y) = " " Then LSS(x, y) = Chr(Int(Rnd * 26) + 1 + 96)
            Next
        Next
        filled = TRUE
        ShowPuzzle
    End If
    If FILLED And WI > 24 Then
        FindAllWords
        FilePuzzle
        Locate 23, 1: Print "On try #"; TrmSS(try); " a successful puzzle was built and filed."
        Exit While
    Else
        try += 1
    End If
Wend

If Not FILLED Then Locate 23, 1: Print "Sorry, 10 tries and no success."

Sleep
End


package main

import (
    "bufio"
    "fmt"
    "log"
    "math/rand"
    "os"
    "regexp"
    "strings"
    "time"
)

var dirs = [][]int{{1, 0}, {0, 1}, {1, 1}, {1, -1}, {-1, 0}, {0, -1}, {-1, -1}, {-1, 1}}

const (
    nRows    = 10
    nCols    = nRows
    gridSize = nRows * nCols
    minWords = 25
)

var (
    re1 = regexp.MustCompile(fmt.Sprintf("^[a-z]{3,%d}$", nRows))
    re2 = regexp.MustCompile("[^A-Z]")
)

type grid struct {
    numAttempts int
    cells       [nRows][nCols]byte
    solutions   []string
}

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

func readWords(fileName string) []string {
    file, err := os.Open(fileName)
    check(err)
    defer file.Close()
    var words []string
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        word := strings.ToLower(strings.TrimSpace(scanner.Text()))
        if re1.MatchString(word) {
            words = append(words, word)
        }
    }
    check(scanner.Err())
    return words
}

func createWordSearch(words []string) *grid {
    var gr *grid
outer:
    for i := 1; i < 100; i++ {
        gr = new(grid)
        messageLen := gr.placeMessage("Rosetta Code")
        target := gridSize - messageLen
        cellsFilled := 0
        rand.Shuffle(len(words), func(i, j int) {
            words[i], words[j] = words[j], words[i]
        })
        for _, word := range words {
            cellsFilled += gr.tryPlaceWord(word)
            if cellsFilled == target {
                if len(gr.solutions) >= minWords {
                    gr.numAttempts = i
                    break outer
                } else { // grid is full but we didn't pack enough words, start over
                    break
                }
            }
        }
    }
    return gr
}

func (gr *grid) placeMessage(msg string) int {
    msg = strings.ToUpper(msg)
    msg = re2.ReplaceAllLiteralString(msg, "")
    messageLen := len(msg)
    if messageLen > 0 && messageLen < gridSize {
        gapSize := gridSize / messageLen
        for i := 0; i < messageLen; i++ {
            pos := i*gapSize + rand.Intn(gapSize)
            gr.cells[pos/nCols][pos%nCols] = msg[i]
        }
        return messageLen
    }
    return 0
}

func (gr *grid) tryPlaceWord(word string) int {
    randDir := rand.Intn(len(dirs))
    randPos := rand.Intn(gridSize)
    for dir := 0; dir < len(dirs); dir++ {
        dir = (dir + randDir) % len(dirs)
        for pos := 0; pos < gridSize; pos++ {
            pos = (pos + randPos) % gridSize
            lettersPlaced := gr.tryLocation(word, dir, pos)
            if lettersPlaced > 0 {
                return lettersPlaced
            }
        }
    }
    return 0
}

func (gr *grid) tryLocation(word string, dir, pos int) int {
    r := pos / nCols
    c := pos % nCols
    le := len(word)

    // check bounds
    if (dirs[dir][0] == 1 && (le+c) > nCols) ||
        (dirs[dir][0] == -1 && (le-1) > c) ||
        (dirs[dir][1] == 1 && (le+r) > nRows) ||
        (dirs[dir][1] == -1 && (le-1) > r) {
        return 0
    }
    overlaps := 0

    // check cells
    rr := r
    cc := c
    for i := 0; i < le; i++ {
        if gr.cells[rr][cc] != 0 && gr.cells[rr][cc] != word[i] {
            return 0
        }
        cc += dirs[dir][0]
        rr += dirs[dir][1]
    }

    // place
    rr = r
    cc = c
    for i := 0; i < le; i++ {
        if gr.cells[rr][cc] == word[i] {
            overlaps++
        } else {
            gr.cells[rr][cc] = word[i]
        }
        if i < le-1 {
            cc += dirs[dir][0]
            rr += dirs[dir][1]
        }
    }

    lettersPlaced := le - overlaps
    if lettersPlaced > 0 {
        sol := fmt.Sprintf("%-10s (%d,%d)(%d,%d)", word, c, r, cc, rr)
        gr.solutions = append(gr.solutions, sol)
    }
    return lettersPlaced
}

func printResult(gr *grid) {
    if gr.numAttempts == 0 {
        fmt.Println("No grid to display")
        return
    }
    size := len(gr.solutions)
    fmt.Println("Attempts:", gr.numAttempts)
    fmt.Println("Number of words:", size)
    fmt.Println("\n     0  1  2  3  4  5  6  7  8  9")
    for r := 0; r < nRows; r++ {
        fmt.Printf("\n%d   ", r)
        for c := 0; c < nCols; c++ {
            fmt.Printf(" %c ", gr.cells[r][c])
        }
    }
    fmt.Println("\n")
    for i := 0; i < size-1; i += 2 {
        fmt.Printf("%s   %s\n", gr.solutions[i], gr.solutions[i+1])
    }
    if size%2 == 1 {
        fmt.Println(gr.solutions[size-1])
    }
}

func main() {
    rand.Seed(time.Now().UnixNano())
    unixDictPath := "/usr/share/dict/words"
    printResult(createWordSearch(readWords(unixDictPath)))
}


require'web/gethttp'

unixdict=:verb define
  if. _1 -: fread 'unixdict.txt' do.
    (gethttp 'http://www.puzzlers.org/pub/wordlists/unixdict.txt') fwrite 'unixdict.txt'
  end.
  fread 'unixdict.txt'
)

words=:verb define
  (#~ 1 - 0&[email protected]&'abcdefghijklmnopqrstuvwxyz'@>) (#~ [: (2&< * 10&>:) #@>) <;._2 unixdict''
)

dirs=: 10#.0 0-.~>,{,~<i:1
lims=: _10+,"2 +/&>/"1 (0~:i:4)#>,{,~<<"1]1 10 1 +i."0]10*i:_1
dnms=: ;:'nw north ne west east sw south se'

genpuz=:verb define
  words=. words''
  fill=. 'ROSETTACODE'
  grid=. ,10 10$' '
  inds=. ,i.10 10
  patience=. -:#words
  key=. i.0 0
  inuse=. i.0 2
  while. (26>#key)+.0<cap=. (+/' '=grid)-#fill do.
    word=. >({~ [email protected]#) words
    dir=. [email protected]#dirs
    offs=. (inds#~(#word)<:inds{dir{lims)+/(i.#word)*/dir{dirs
    cool=. ' '=offs{grid
    sel=. */"1 cool+.(offs{grid)="1 word
    offs=. (sel*cap>:+/"1 cool)#offs
    if. (#offs) do.
      off=. ({~ [email protected]#) offs
      loc=. ({.off),dir
      if. -. loc e. inuse do.
        inuse=. inuse,loc
        grid=. word off} grid
        patience=. patience+1
        key=. /:~ key,' ',(10{.word),(3":1+10 10#:{.off),' ',dir{::dnms
      end.
    else. NB. grr...
      if. 0 > patience=. patience-1 do.
        inuse=.i.0 2
        key=.i.0 0
        grid=. ,10 10$' '
        patience=. -:#words
      end.
    end.
  end.
  puz=. (_23{.":i.10),' ',1j1#"1(":i.10 1),.' ',.10 10$fill (I.grid=' ')} grid
  puz,' ',1 1}._1 _1}.":((</.~ <.) [email protected]# * 3%#)key
)


import java.io.*;
import static java.lang.String.format;
import java.util.*;

public class WordSearch {
    static class Grid {
        int numAttempts;
        char[][] cells = new char[nRows][nCols];
        List<String> solutions = new ArrayList<>();
    }

    final static int[][] dirs = {{1, 0}, {0, 1}, {1, 1}, {1, -1}, {-1, 0},
    {0, -1}, {-1, -1}, {-1, 1}};

    final static int nRows = 10;
    final static int nCols = 10;
    final static int gridSize = nRows * nCols;
    final static int minWords = 25;

    final static Random rand = new Random();

    public static void main(String[] args) {
        printResult(createWordSearch(readWords("unixdict.txt")));
    }

    static List<String> readWords(String filename) {
        int maxLen = Math.max(nRows, nCols);

        List<String> words = new ArrayList<>();
        try (Scanner sc = new Scanner(new FileReader(filename))) {
            while (sc.hasNext()) {
                String s = sc.next().trim().toLowerCase();
                if (s.matches("^[a-z]{3," + maxLen + "}$"))
                    words.add(s);
            }
        } catch (FileNotFoundException e) {
            System.out.println(e);
        }
        return words;
    }

    static Grid createWordSearch(List<String> words) {
        Grid grid = null;
        int numAttempts = 0;

        outer:
        while (++numAttempts < 100) {
            Collections.shuffle(words);

            grid = new Grid();
            int messageLen = placeMessage(grid, "Rosetta Code");
            int target = gridSize - messageLen;

            int cellsFilled = 0;
            for (String word : words) {
                cellsFilled += tryPlaceWord(grid, word);
                if (cellsFilled == target) {
                    if (grid.solutions.size() >= minWords) {
                        grid.numAttempts = numAttempts;
                        break outer;
                    } else break; // grid is full but we didn't pack enough words, start over
                }
            }
        }

        return grid;
    }

    static int placeMessage(Grid grid, String msg) {
        msg = msg.toUpperCase().replaceAll("[^A-Z]", "");

        int messageLen = msg.length();
        if (messageLen > 0 && messageLen < gridSize) {
            int gapSize = gridSize / messageLen;

            for (int i = 0; i < messageLen; i++) {
                int pos = i * gapSize + rand.nextInt(gapSize);
                grid.cells[pos / nCols][pos % nCols] = msg.charAt(i);
            }
            return messageLen;
        }
        return 0;
    }

    static int tryPlaceWord(Grid grid, String word) {
        int randDir = rand.nextInt(dirs.length);
        int randPos = rand.nextInt(gridSize);

        for (int dir = 0; dir < dirs.length; dir++) {
            dir = (dir + randDir) % dirs.length;

            for (int pos = 0; pos < gridSize; pos++) {
                pos = (pos + randPos) % gridSize;

                int lettersPlaced = tryLocation(grid, word, dir, pos);
                if (lettersPlaced > 0)
                    return lettersPlaced;
            }
        }
        return 0;
    }

    static int tryLocation(Grid grid, String word, int dir, int pos) {

        int r = pos / nCols;
        int c = pos % nCols;
        int len = word.length();

        //  check bounds
        if ((dirs[dir][0] == 1 && (len + c) > nCols)
                || (dirs[dir][0] == -1 && (len - 1) > c)
                || (dirs[dir][1] == 1 && (len + r) > nRows)
                || (dirs[dir][1] == -1 && (len - 1) > r))
            return 0;

        int rr, cc, i, overlaps = 0;

        // check cells
        for (i = 0, rr = r, cc = c; i < len; i++) {
            if (grid.cells[rr][cc] != 0 && grid.cells[rr][cc] != word.charAt(i))
                return 0;
            cc += dirs[dir][0];
            rr += dirs[dir][1];
        }

        // place
        for (i = 0, rr = r, cc = c; i < len; i++) {
            if (grid.cells[rr][cc] == word.charAt(i))
                overlaps++;
            else
                grid.cells[rr][cc] = word.charAt(i);

            if (i < len - 1) {
                cc += dirs[dir][0];
                rr += dirs[dir][1];
            }
        }

        int lettersPlaced = len - overlaps;
        if (lettersPlaced > 0) {
            grid.solutions.add(format("%-10s (%d,%d)(%d,%d)", word, c, r, cc, rr));
        }

        return lettersPlaced;
    }

    static void printResult(Grid grid) {
        if (grid == null || grid.numAttempts == 0) {
            System.out.println("No grid to display");
            return;
        }
        int size = grid.solutions.size();

        System.out.println("Attempts: " + grid.numAttempts);
        System.out.println("Number of words: " + size);

        System.out.println("\n     0  1  2  3  4  5  6  7  8  9");
        for (int r = 0; r < nRows; r++) {
            System.out.printf("%n%d   ", r);
            for (int c = 0; c < nCols; c++)
                System.out.printf(" %c ", grid.cells[r][c]);
        }

        System.out.println("\n");

        for (int i = 0; i < size - 1; i += 2) {
            System.out.printf("%s   %s%n", grid.solutions.get(i),
                    grid.solutions.get(i + 1));
        }
        if (size % 2 == 1)
            System.out.println(grid.solutions.get(size - 1));
    }
}


using Random

const stepdirections = [[1, 0], [0, 1], [1, 1], [1, -1], [-1, 0], [0, -1], [-1, -1], [-1, 1]]
const nrows    = 10
const ncols    = nrows
const gridsize = nrows * ncols
const minwords = 25
const minwordsize = 3

mutable struct LetterGrid
    nattempts::Int
    nrows::Int
    ncols::Int
    cells::Matrix{Char}
    solutions::Vector{String}
    LetterGrid() = new(0, nrows, ncols, fill(' ', nrows, ncols), Vector{String}())
end

function wordmatrix(filename, usepropernames = true)
    words = [lowercase(line) for line in readlines(filename)
        if match(r"^[a-zA-Z]+$", line) != nothing && (usepropernames ||
            match(r"^[a-z]", line) != nothing) && length(line) >= minwordsize && length(line) <= ncols]
    n = 1000
    for i in 1:n
        grid = LetterGrid()
        messagelen = placemessage(grid, "Rosetta Code")
        target = grid.nrows * grid.ncols - messagelen
        cellsfilled = 0
        shuffle!(words)
        for word in words
            cellsfilled += tryplaceword(grid, word)
            if cellsfilled == target
                if length(grid.solutions) >= minwords
                    grid.nattempts = i
                    return grid
                else
                    break
                end
            end
        end
    end
    throw("Failed to place words after $n attempts")
end

function placemessage(grid, msg)
    msg = uppercase(msg)
    msg = replace(msg, r"[^A-Z]" => "")
    messagelen = length(msg)
    if messagelen > 0 && messagelen < gridsize
        p = Int.(floor.(LinRange(messagelen, gridsize, messagelen) .+
                     (rand(messagelen) .- 0.5) * messagelen / 3)) .- div(messagelen, 3)
        foreach(i -> grid.cells[div(p[i], nrows) + 1, p[i] % nrows + 1] = msg[i], 1:length(p))
        return messagelen
    end
    return 0
end

function tryplaceword(grid, word)
    for dir in shuffle(stepdirections)
        for pos in shuffle(1:length(grid.cells))
            lettersplaced = trylocation(grid, word, dir, pos)
            if lettersplaced > 0
                return lettersplaced
            end
        end
    end
    return 0
end

function trylocation(grid, word, dir, pos)
    r, c = divrem(pos, nrows) .+ [1, 1]
    positions = [[r, c] .+ (dir .* i) for i in 1:length(word)]
    if !all(x -> 0 < x[1] <= nrows && 0 < x[2] <= ncols, positions)
        return 0
    end
    for (i, p) in enumerate(positions)
        letter = grid.cells[p[1],p[2]]
        if letter != ' ' && letter != word[i]
            return 0
        end
    end
    lettersplaced = 0
    for (i, p) in enumerate(positions)
        if grid.cells[p[1], p[2]] == ' '
            lettersplaced += 1
            grid.cells[p[1],p[2]] = word[i]
        end
    end
    if lettersplaced > 0
        push!(grid.solutions, lpad(word, 10) * " $(positions[1]) to $(positions[end])")
    end
    return lettersplaced
end

function printresult(grid)
    if grid.nattempts == 0
        println("No grid to display: no solution found.")
        return
    end
    size = length(grid.solutions)
    println("Attempts: ", grid.nattempts)
    println("Number of words: ", size)
    println("\n     0  1  2  3  4  5  6  7  8  9")
    for r in 1:nrows
        print("\n", rpad(r, 4))
        for c in 1:ncols
            print(" $(grid.cells[r, c]) ")
        end
    end
    println()
    for i in 1:2:size
        println("$(grid.solutions[i])   $(i < size ? grid.solutions[i+1] : "")")
    end
end

printresult(wordmatrix("words.txt", false))


// version 1.2.0

import java.util.Random
import java.io.File

val dirs = listOf(
    intArrayOf( 1, 0), intArrayOf(0,  1), intArrayOf( 1,  1), intArrayOf( 1, -1),
    intArrayOf(-1, 0), intArrayOf(0, -1), intArrayOf(-1, -1), intArrayOf(-1,  1)
)

val nRows = 10
val nCols = 10
val gridSize = nRows * nCols
val minWords = 25
val rand = Random()

class Grid {
    var numAttempts = 0
    val cells = List(nRows) { CharArray(nCols) }
    val solutions = mutableListOf<String>()
}

fun readWords(fileName: String): List<String> {
    val maxLen = maxOf(nRows, nCols)
    val rx = Regex("^[a-z]{3,$maxLen}$")
    val f = File(fileName)
    return f.readLines().map { it.trim().toLowerCase() }
                        .filter { it.matches(rx) }
}

fun createWordSearch(words: List<String>): Grid {
    var numAttempts = 0
    lateinit var grid: Grid
    outer@ while (++numAttempts < 100) {
        grid = Grid()
        val messageLen = placeMessage(grid, "Rosetta Code")
        val target = gridSize - messageLen
        var cellsFilled = 0
        for (word in words.shuffled()) {
            cellsFilled += tryPlaceWord(grid, word)
            if (cellsFilled == target) {
                if (grid.solutions.size >= minWords) {
                    grid.numAttempts = numAttempts
                    break@outer
                }
                else { // grid is full but we didn't pack enough words, start over
                    break
                }
            }
        }
    }
    return grid
}

fun placeMessage(grid: Grid, msg: String): Int {
    val rx = Regex("[^A-Z]")
    val msg2 = msg.toUpperCase().replace(rx, "")
    val messageLen = msg2.length
    if (messageLen in (1 until gridSize)) {
        val gapSize = gridSize / messageLen
        for (i in 0 until messageLen) {
            val pos = i * gapSize + rand.nextInt(gapSize)
            grid.cells[pos / nCols][pos % nCols] = msg2[i]
        }
        return messageLen
    }
    return 0
}

fun tryPlaceWord(grid: Grid, word: String): Int {
    val randDir = rand.nextInt(dirs.size)
    val randPos = rand.nextInt(gridSize)
    for (d in 0 until dirs.size) {
        val dir = (d + randDir) % dirs.size
        for (p in 0 until gridSize) {
            val pos = (p + randPos) % gridSize
            val lettersPlaced = tryLocation(grid, word, dir, pos)
            if (lettersPlaced > 0) return lettersPlaced
        }
    }
    return 0
}

fun tryLocation(grid: Grid, word: String, dir: Int, pos: Int): Int {
    val r = pos / nCols
    val c = pos % nCols
    val len = word.length

    // check bounds
    if ((dirs[dir][0] == 1 && (len + c) > nCols)
        || (dirs[dir][0] == -1 && (len - 1) > c)
        || (dirs[dir][1] ==  1 && (len + r) > nRows)
        || (dirs[dir][1] == -1 && (len - 1) > r)) return 0
    var overlaps = 0

    // check cells
    var rr = r
    var cc = c
    for (i in 0 until len) {
        if (grid.cells[rr][cc] != '\u0000' && grid.cells[rr][cc] != word[i]) return 0
        cc += dirs[dir][0]
        rr += dirs[dir][1]
    }

    // place
    rr = r
    cc = c
    for (i in 0 until len) {
        if (grid.cells[rr][cc] == word[i])
            overlaps++
        else
            grid.cells[rr][cc] = word[i]

        if (i < len - 1) {
            cc += dirs[dir][0]
            rr += dirs[dir][1]
        }
    }

    val lettersPlaced = len - overlaps
    if (lettersPlaced > 0) {
        grid.solutions.add(String.format("%-10s (%d,%d)(%d,%d)", word, c, r, cc, rr))
    }
    return lettersPlaced
}

fun printResult(grid: Grid) {
    if (grid.numAttempts == 0) {
        println("No grid to display")
        return
    }
    val size = grid.solutions.size
    println("Attempts: ${grid.numAttempts}")
    println("Number of words: $size")
    println("\n     0  1  2  3  4  5  6  7  8  9")
    for (r in 0 until nRows) {
         print("\n$r   ")
         for (c in 0 until nCols) print(" ${grid.cells[r][c]} ")
    }

    println("\n")

    for (i in 0 until size - 1 step 2) {
        println("${grid.solutions[i]}   ${grid.solutions[i + 1]}")
    }
    if (size % 2 == 1) println(grid.solutions[size - 1])
}

fun main(args: Array<String>) {
    printResult(createWordSearch(readWords("unixdict.txt")))
}


import random, sequtils, strformat, strutils

const

  Dirs = [[1,  0], [ 0,  1], [ 1, 1],
          [1, -1],           [-1, 0],
          [0, -1], [-1, -1], [-1, 1]]

  NRows = 10
  NCols = 10
  GridSize = NRows * NCols
  MinWords = 25

type Grid = ref object
  numAttempts: Natural
  cells: array[NRows, array[NCols, char]]
  solutions: seq[string]

proc readWords(filename: string): seq[string] =

  const MaxLen = max(NRows, NCols)

  for word in filename.lines():
    if word.len in 3..MaxLen:
      if word.allCharsInSet(Letters):
        result.add word.toLowerAscii

proc placeMessage(grid: var Grid; msg: string): int =
  let msg = msg.map(toUpperAscii).filter(isUpperAscii).join()
  if msg.len in 1..<GridSize:
    let gapSize = GridSize div msg.len
    for i in 0..msg.high:
      let pos = i * gapSize + rand(gapSize - 1)
      grid.cells[pos div NCols][pos mod NCols] = msg[i]
    result = msg.len

proc tryLocation(grid: var Grid; word: string; dir, pos: Natural): int =
  let row = pos div NCols
  let col = pos mod NCols
  let length = word.len

  # Check bounds.
  if (Dirs[dir][0] == 1 and (length + col) > NCols) or
     (Dirs[dir][0] == -1 and (length - 1) > col) or
     (Dirs[dir][1] == 1 and (length + row) > NRows) or
     (Dirs[dir][1] == -1 and (length - 1) > row):
    return 0

  # Check cells.
  var r = row
  var c = col
  for ch in word:
    if grid.cells[r][c] != '\0' and grid.cells[r][c] != ch: return 0
    c += Dirs[dir][0]
    r += Dirs[dir][1]

  # Place.
  r = row
  c = col
  var overlaps = 0
  for i, ch in word:
    if grid.cells[r][c] == ch: inc overlaps
    else: grid.cells[r][c] = ch
    if i < word.high:
      c += Dirs[dir][0]
      r += Dirs[dir][1]

  let lettersPlaced = length - overlaps
  if lettersPlaced > 0:
    grid.solutions.add &"{word:<10} ({col}, {row}) ({c}, {r})"

  result = lettersPlaced

proc tryPlaceWord(grid: var Grid; word: string): int =
  let randDir = rand(Dirs.high)
  let randPos = rand(GridSize - 1)

  for dir in 0..Dirs.high:
    let dir = (dir + randDir) mod Dirs.len
    for pos in 0..<GridSize:
      let pos = (pos + randPos) mod GridSize
      let lettersPlaced = grid.tryLocation(word, dir, pos)
      if lettersPlaced > 0:
        return lettersPlaced

proc initGrid(words: seq[string]): Grid =
  var words = words
  for numAttempts in 1..100:
    words.shuffle()
    new(result)
    let messageLen = result.placeMessage("Rosetta Code")
    let target = GridSize - messageLen

    var cellsFilled = 0
    for word in words:
      cellsFilled += result.tryPlaceWord(word)
      if cellsFilled == target:
        if result.solutions.len >= MinWords:
          result.numAttempts = numAttempts
          return
        # Grid is full but we didn't pack enough words: start over.
        break

proc printResult(grid: Grid) =
  if grid.isNil or grid.numAttempts == 0:
    echo "No grid to display."
    return

  let size = grid.solutions.len
  echo "Attempts: ", grid.numAttempts
  echo "Number of words: ", size

  echo "\n    0  1  2  3  4  5  6  7  8  9\n"
  for r in 0..<NRows:
    echo &"{r}   ", grid.cells[r].join("  ")
  echo()

  for i in countup(0, size - 2, 2):
    echo grid.solutions[i], "   ", grid.solutions[i + 1]
  if (size and 1) == 1:
    echo grid.solutions[^1]

randomize()
let grid = initGrid("unixdict.txt".readWords())
grid.printResult()


#!/usr/bin/perl

use strict; # http://www.rosettacode.org/wiki/Word_search
use warnings;
use Path::Tiny;
use List::Util qw( shuffle );

my $size = 10;
my $s1 = $size + 1;
$_ = <<END;
.....R....
......O...
.......S..
........E.
T........T
.A........
..C.......
...O......
....D.....
.....E....
END

my @words = shuffle path('/usr/share/dict/words')->slurp =~ /^[a-z]{3,7}$/gm;
my @played;
my %used;

for my $word ( (@words) x 5 )
  {
  my ($pat, $start, $end, $mask, $nulls) = find( $word );
  defined $pat or next;
  $used{$word}++ and next; # only use words once
  $nulls //= '';
  my $expand = $word =~ s/\B/$nulls/gr;
  my $pos = $start;
  if( $start > $end )
    {
    $pos = $end;
    $expand = reverse $expand;
    }
  substr $_, $pos, length $mask,
    (substr( $_, $pos, length $mask ) & ~ "$mask") | "$expand";
  push @played, join ' ', $word, $start, $end;
  tr/.// > 0 or last;
  }

print "   0 1 2 3 4 5 6 7 8 9\n\n";
my $row = 0;
print s/(?<=.)(?=.)/ /gr =~ s/^/ $row++ . '  ' /gemr;
print "\nNumber of words: ", @played . "\n\n";
my @where = map
  {
  my ($word, $start, $end) = split;
  sprintf "%11s %s", $word, $start < $end
    ? "(@{[$start % $s1]},@{[int $start / $s1]})->" .
      "(@{[$end % $s1 - 1]},@{[int $end / $s1]})"
    : "(@{[$start % $s1 - 1]},@{[int $start / $s1]})->" .
      "(@{[$end % $s1]},@{[int $end / $s1]})";
  } sort @played;
print splice(@where, 0, 3), "\n" while @where;
tr/.// and die "incomplete";

sub find
  {
  my ($word) = @_;
  my $n = length $word;
  my $nm1 = $n - 1;
  my %pats;

  for my $space ( 0, $size - 1 .. $size + 1 )
    {
    my $nulls = "\0" x $space;
    my $mask = "\xff" . ($nulls . "\xff") x $nm1; # vert
    my $gap = qr/.{$space}/s;
    while( /(?=(.(?:$gap.){$nm1}))/g )
      {
      my $pat = ($1 & $mask) =~ tr/\0//dr;
      $pat =~ tr/.// or next;
      my $pos = "$-[1] $+[1]";
      $word =~ /$pat/ or reverse($word) =~ /$pat/ or next;
      push @{ $pats{$pat} }, "$pos $mask $nulls";
      }
    }

  for my $key ( sort keys %pats )
    {
    if( $word =~ /^$key$/ )
      {
      my @all = @{ $pats{$key} };
      return $key, split ' ', $all[ rand @all ];
      }
    elsif( (reverse $word) =~ /^$key$/ )
      {
      my @all = @{ $pats{$key} };
      my @parts = split ' ', $all[ rand @all ];
      return $key, @parts[ 1, 0, 2, 3]
      }
    }

  return undef;
  }


--
-- demo\rosetta\wordsearch.exw
-- ===========================
--
with javascript_semantics
string message = "ROSETTACODE"
sequence words = unix_dict(), solution="", placed

constant grid = split("""
X  0  1  2  3  4  5  6  7  8  9  X
0                                X
1                                X
2                                X
3                                X
4                                X
5                                X
6                                X
7                                X
8                                X
9                                X
X  X  X  X  X  X  X  X  X  X  X  X""",'\n')

constant DX = {-1, 0,+1,+1,+1, 0,-1,-1},
         DY = {-3,-3,-3, 0,+3,+3,+3, 0}

procedure wordsearch(sequence grid, integer rqd, integer left, sequence done)
    sequence rw = shuffle(tagset(length(words))),
             rd = shuffle(tagset(8)),
             rs = shuffle(tagset(100))
    for i=1 to length(rs) do
        integer sx = floor((rs[i]-1)/10)+2,
                sy = remainder(rs[i]-1,10)*3+4
        for w=1 to length(rw) do
            string word = words[rw[w]]
            if not find(word,done[1]) then
                for d=1 to length(rd) do
                    integer {dx,dy} = {DX[rd[d]],DY[rd[d]]},
                            {nx,ny} = {sx,sy},
                            chcount = length(word)
                    sequence newgrid = deep_copy(grid)
                    for c=1 to length(word) do
                        integer ch = grid[nx][ny]
                        if ch!=' ' then
                            if ch!=word[c] then
                                chcount = -1
                                exit
                            end if
                            chcount -= 1
                        end if
                        newgrid[nx][ny] = word[c]
                        nx += dx
                        ny += dy
                    end for
                    if chcount!=-1 then
                        sequence posinfo = {sx-2,(sy-4)/3,nx-dx-2,(ny-dy-4)/3},
                                 newdone = {append(deep_copy(done[1]),word),
                                            append(deep_copy(done[2]),posinfo)}
                        if rqd<=1 and left-chcount=length(message) then
                            {solution, placed} = {newgrid, newdone}
                            return
                        elsif left-chcount>length(message) then
                            wordsearch(newgrid,rqd-1,left-chcount,newdone)
                            if length(solution) then return end if
                        end if
                    end if
                end for
            end if
        end for
    end for
end procedure

function valid_word(string word)
    if length(word)<3 then return false end if
    for i=1 to length(word) do
        integer ch = word[i]
        if ch<'a'
        or ch>'z' then
            return false
        end if
    end for
    return true
end function

for i=length(words) to 1 by -1 do
    if not valid_word(words[i]) then
        words[i] = words[$]
        words = words[1..$-1]
    end if
end for
printf(1,"%d words loaded\n",length(words)) -- 24822

wordsearch(grid,25,100,{{},{}})
for x=2 to 11 do
    for y=4 to 31 by 3 do
        if solution[x][y]=' ' then
            solution[x][y] = message[1]
            message = message[2..$]
        end if
    end for
end for
if length(message) then ?9/0 end if
puts(1,substitute(join(solution,'\n'),"X"," "))
printf(1,"\n%d words\n",length(placed[1]))
for i=1 to length(placed[1]) do
    printf(1,"%10s %10s  ",{placed[1][i],sprint(placed[2][i])})
    if mod(i,3)=0 then puts(1,"\n") end if
end for

{} = wait_key()