#!/usr/bin/env ruby

# Scrabble Pretty Printer
#
# Generates a postscript file from an ascii board diagram via lout
# Lout may be obtained from http://lout.sourceforge.net/
#
# Author: Martin DeMello <martindemello@gmail.com>
# Date: Aug 12, 2004
#
# Usage: 
#   scrabpp <inputfile> [<loutfile>]
#   lout <loutfile> > output.ps
#
# -------------------------------------------------------------------

# convenience methods

module Enumerable
  def map_with_index
    a = []
    each_with_index {|e, i| a << yield(e,i)}
    a
  end
end

# -------------------------------------------------------------------
# Globals

# set up the tile->score mapping
a = ["AEILNORSTU", "DG", "BCMP", "FHVWY", "K", "", "", "JX", "", "QZ"]
$scores = {}
a.each_with_index {|s, i| s.split(//).each {|l| $scores[l] = i+1}}

# premium square placements
# there are more compact ways to do it but this looks pretty
$empty_board = <<HERE
 ------------------------------ 
|=     '       =       '     = |
|  -       "       "       -   |
|    -       '   '       -     |
|'     -       '       -     ' |
|        -           -         |
|  "       "       "       "   |
|    '       '   '       '     |
|=     '       -       '     = |
|    '       '   '       '     |
|  "       "       "       "   |
|        -           -         |
|'     -       '       -     ' |
|    -       '   '       -     |
|  -       "       "       -   |
|=     '       =       '     = |
 ------------------------------ 
HERE


# ----------------------------------------------------------------
# input parsing

# convert a board into a 15x15 array of characters
def split_board(b)
	b.gsub!(/\./, '')
	b = b.split(/\n/).map {|i| i.sub(/.*?\|/, '').sub(/\|[^|]*$/, '')}
	c = d = nil
 	c = b.shift	until c =~ /^[\d\s-]+$/
	d = b.pop until d =~ /^[\d\s-]+$/
	b.map {|i| i.gsub(/(.)./){$1}.split(//)}
end

$mask = split_board($empty_board)

# supply the premium squares if missing
def mask_board(board)
  board = split_board(board)
  
	board.each_index {|i| 
		board[i].each_index {|j|
			board[i][j] = $mask[i][j] if board[i][j] == ' '
		}
	}
end

# ------------------------------------------------------------------
# output generation

#lout definitions
def tile(sq)
	"white @Tile {{Bold @Font #{sq}} @Sub { -2p @Font #{$scores[sq]}}}"
end

def blank(sq)
	"white @Tile {{Bold @Font grey @Color #{sq.upcase}} @Sub { -2p @Font 0}}"
end

def to_lout(board)
	board.map {|row|
		"@Rowa\n" +
		row.map_with_index {|sq, i|
			(?A + i).chr + '{ ' +
			case sq
			when '=';  		 '@TWS'
			when '-';  		 '@DWS'
			when '"';  		 '@TLS'
			when "'";  		 '@DLS'
			when " ";  		 'lightgreen @Sq { }'
			when "a".."z"; blank(sq)
			else    ;  		 tile(sq)
			end + 
			" }\n"
		}.join 
	}.join
end
# inline the lout headers to keep this all in a single file

$loutheaders = <<HERE
@SysInclude {tbl}
@SysInclude {diag}
@SysInclude {doc}
extend @Diag
def @Sq left col right x { @Node paint {col} {x} }
extend @Diag
def @Tile left col right x { @Node paint {col} {x} }
extend @Diag
def @Premium left col right x { col @Sq { -4p @Font {x} } }
extend @Diag
def @TLS { lightblue @Premium{3L} }
extend @Diag
def @TWS { lightred @Premium{3W} }
extend @Diag
def @DWS { lightmagenta @Premium{2W} }
extend @Diag
def @DLS { lightcyan @Premium{2L} }
HERE

$rowformat = ('A'..'O').map {|i| "@Cell #{i}"}.join(" | ")

def lout_board(board)
	$loutheaders +
	<<-HERE
	@Document
	@InitialFont {Helvetica Base 10p}
	//
	@Text @Begin


	@Diag
	vstrut {no}
	vsize {1.3f}
	hsize {1.3f}
	outline {square}
	font {Bold}
	{
		@Tbl
		aformat { #{$rowformat} }
		marginhorizontal {0c}
		marginvertical {0c}
		{
			#{to_lout(board)}
		}
	}

	@End @Text
	HERE
end

# ---------------------------------------------------------
# main

if ARGV.length < 1 
	puts "Usage: #{$0} <inputfile> [<outputfile>]"
	exit
end

infile = ARGV[0]
outfile = ARGV[1] ? File.open(ARGV[1], 'w') : $stdout

a = IO.read(infile)
board = mask_board(a)
outfile.puts(lout_board(board))

