#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
#
# A classic game; don't know how it's called in english. You have to
# restore the original configuration:
#
#  1  2  3  4  5  6
#  7  8  9 10 11 12
# 13 14 15 16 17 18
# 19 20 21 22 23 24
# 25 26 27 28 29  .
#
# or any variant of it. This is my first Tkinter program, I'm sure
# you'll be forgiving...
#
# $Id: taquin.py,v 1.1 2003/08/10 02:09:47 etale Exp $
#
# Written by Thierry Bousch <bousch@topo.math.u-psud.fr> and placed
# in the public domain.

from Tkinter import *
from Canvas import *

BACKGROUND = 'orange'
TSIZE = 90
MARGIN = 5
FONT = '-bitstream-charter-bold-r-normal--70-0-0-0-p-0-iso8859-1'
LINES = 5
COLUMNS = 6

def permute(array):
  # Generate an even permutation, randomly
  from random import random
  n = len(array)
  signature = 1
  for i in range(n-2):
    j = int(random()*(n-1-i)) + (i+1)
    if j != i:
      signature = -signature
      array[i], array[j] = array[j], array[i]
  # There's no choice for the last two elements, if we want
  # an even permutation
  if signature < 0:
    array[n-2], array[n-1] = array[n-1], array[n-2]

#
# Class definitions
#

class Tile:
  def __init__(self, text, canvas):
    self.rect = Rectangle(canvas, 0, 0, TSIZE, TSIZE,
	outline='black', fill='white')
    self.text = CanvasText(canvas, TSIZE/2, TSIZE/2, anchor=CENTER,
	text=text, font=FONT)
    self.group = Group(canvas)
    self.group.addtag_withtag(self.rect)
    self.group.addtag_withtag(self.text)
    self.group.move(MARGIN, MARGIN)
    self.line = self.column = 0

  def moveto(self, line, column):
    S = MARGIN+TSIZE
    self.group.move(S*(column-self.column), S*(line-self.line))
    self.line = line
    self.column = column


class Counter(Label):
  def __init__(self, parent, template):
    Label.__init__(self, parent)
    self.template = template
    self.n = 0
    self.redisplay()

  def reset(self):
    self.n = 0
    self.redisplay()

  def increment(self):
    self.n = self.n + 1
    self.redisplay()

  def redisplay(self):
    self['text'] = self.template % self.n


class Board:
  def __init__(self, root, counter, lines, columns, bg):
    S = MARGIN+TSIZE
    self.lines = lines
    self.columns = columns
    self.counter = counter
    self.canvas = Canvas(root, background=bg,
      height=MARGIN+S*lines, width=MARGIN+S*columns)
    self.tiles = []
    for t in range(lines*columns-1):
      tile = Tile(`t+1`, self.canvas)
      self.tiles.append(tile)
    self.shuffle()
    self.canvas.bind('<1>', self.clickhandler)
    self.canvas.pack()

  def shuffle(self):
    permute(self.tiles)
    for t in range(len(self.tiles)):
      i,j = divmod(t, self.columns)
      self.tiles[t].moveto(i,j)
    self.hl = self.lines-1
    self.hc = self.columns-1
    self.counter.reset()

  def clickhandler(self, event):
    S = MARGIN+TSIZE
    line   = (event.y - MARGIN/2) / S
    column = (event.x - MARGIN/2) / S
    line = max(line, 0)
    line = min(line, self.lines-1)
    column = max(column, 0)
    column = min(column, self.columns-1)
    if line == self.hl:
      if column <> self.hc:
        self.move_line(line, column)
    else:
      if column == self.hc:
        self.move_column(line, column)

  def move_line(self, l, c):
    hc = self.hc
    n = abs(hc - c)
    if c < hc:
      for i in range(n):
        self.move_tile(l, hc-1-i, 0, 1)
    else:
      for i in range(n):
        self.move_tile(l, hc+1+i, 0, -1)
    self.counter.increment()

  def move_column(self, l, c):
    hl = self.hl
    n = abs(hl - l)
    if l < hl:
      for i in range(n):
        self.move_tile(hl-1-i, c, 1, 0)
    else:
      for i in range(n):
        self.move_tile(hl+1+i, c, -1, 0)
    self.counter.increment()

  def move_tile(self, l, c, dl, dc):
    for tile in self.tiles:
      if tile.line == l and tile.column == c:
        tile.moveto(l+dl, c+dc)
        self.hl = l
        self.hc = c

  def bg_color(self, color):
    self.canvas['background'] = color


class Game:
  def __init__(self, lines, columns, bg):
    self.win = Frame()
    self.win.master.title('Taquin')
    self.make_menubar()
    self.board = Board(self.win, self.counter, lines, columns, bg)
    self.make_menu_options()
    self.make_menu_colors()
    self.win.pack()
    self.win.mainloop()

  def make_menubar(self):
    self.menubar = Frame(self.win, relief=RAISED, bd=2)
    self.menubutton1 = Menubutton(self.menubar, text='Options')
    self.menubutton1.pack(side=LEFT)
    self.menubutton2 = Menubutton(self.menubar, text='Colors')
    self.menubutton2.pack(side=LEFT)
    self.counter = Counter(self.menubar, 'Moves: %d')
    self.counter.pack(side=RIGHT)
    self.menubar.pack(side=TOP, fill=X)

  def make_menu_options(self):
    menu = Menu(self.menubutton1)
    menu.add_command(label='About this program...', command=self.about)
    menu.add_command(label='New game', command=self.board.shuffle)
    menu.add_command(label='Quit', command=self.win.quit)
    self.menubutton1['menu'] = menu

  def make_menu_colors(self):
    menu = Menu(self.menubutton2)
    menu.add_command(label='Burlywood', command=self.bg_burlywood)
    menu.add_command(label='Forest Green', command=self.bg_fgreen)
    menu.add_command(label='Orange', command=self.bg_orange)
    self.menubutton2['menu'] = menu

  def about(self):
    from Dialog import Dialog
    Dialog(self.win, title='Program Info', text=
      "C'est un jeu oł l'on pousse\n"
      "Avec le pouce\n"
      'Sans jamais dire "pouce!"',
      bitmap='info', default=0, strings=('OK',))

  def bg_burlywood(self):
    self.board.bg_color('burlywood')

  def bg_fgreen(self):
    self.board.bg_color('Forest Green')

  def bg_orange(self):
    self.board.bg_color('orange')


#
# Main routine
#

if __name__ == '__main__':
  Game(LINES, COLUMNS, BACKGROUND)
