/usr/local/CPAN/Games-Checkers/Games/Checkers/MoveLocationConstructor.pm


# Games::Checkers, Copyright (C) 1996-2004 Mikhael Goikhman
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

use strict;

package Games::Checkers::MoveLocationConstructor;

use base 'Games::Checkers::Board';
use Games::Checkers::Constants;
use Games::Checkers::BoardConstants;
use Games::Checkers::MoveConstants;

use constant MAX_MOVE_JUMP_NUM => 9;

sub new ($$$) {
	my $class = shift;
	my $board = shift;
	my $color = shift;

	my $self = $class->SUPER::new($board);
	my $fields = {
		color => $color,
		destin => [],
		src => NL,
		piece => 0,
		mustBeat => $board->canColorBeat($color),
		origBoard => $board,
	};
	$self->{$_} = $fields->{$_} foreach keys %$fields;
	return $self;
}
	
sub init ($) {
	my $self = shift;
	$self->{destin} = [];
	$self->{src} = NL;
	$self->copy($self->{origBoard});
}

sub source ($$) {
	my $self = shift;
	my $loc = shift;
	$self->init;
	return Err if $loc == NL || !$self->occup($loc) || $self->color($loc) != $self->{color};
	return Err if $self->{mustBeat} && !$self->canPieceBeat($loc) || !$self->{mustBeat} && !$self->canPieceStep($loc);
	$self->{piece} = $self->piece($self->{src} = $loc);
	return Ok;
}

sub addDst ($$) {
	my $self = shift;
	my $dst = shift;
	return Err if $self->{src} == NL || @{$self->{destin}} == MAX_MOVE_JUMP_NUM-1;
	if ($self->{mustBeat}) {
		die "Internal" unless $self->occup($self->dst_1);
		return Err unless $self->canPieceBeat($self->dst_1, $dst);
	} else {
		return Err if @{$self->{destin}} > 0;
		return Err unless $self->canPieceStep($self->{src}, $dst);
	}
	push @{$self->{destin}}, $dst;
	$self->transformOne;
	return Ok;
}

sub delDst ($) {
	my $self = shift;
	return NL if $self->{src} == NL || @{$self->{destin}} == 0;
	my $dst = pop @{$self->{destin}};
	$self->transformAll;
	return $dst;
}

sub canCreateMove ($) {
	my $self = shift;
	return $self->{mustBeat} && @{$self->{destin}} > 0
		&& $self->canPieceBeat($self->dst_1) == No
		|| !$self->{mustBeat} && @{$self->{destin}} == 1;
}

sub createMove ($) {
	my $self = shift;
	return NO_MOVE	if $self->{src} == NL
		|| $self->{mustBeat} && @{$self->{destin}} < 1
		|| !$self->{mustBeat} && @{$self->{destin}} != 1;
	return new Games::Checkers::Move(
		$self->{mustBeat}, $self->{src}, $self->{destin});
}

sub transformOne ($) {
	my $self = shift;
	my $src = $self->dst_2;
	my $dst = $self->dst_1;
	$self->clr($src);
	$self->set($dst, $self->{color}, $self->{piece});
	$self->clr($self->figureBetween($src, $dst)) if $self->{mustBeat};
	if (convertType->[$self->{color}][$self->{piece}] & (1 << $dst)) {
		$self->{pieceMap} ^= (1 << $dst);
		$self->{piece} ^= 1;
	}
}

sub transformAll ($) {
	my $self = shift;
	$self->copy($self->{origBoard});
	return if $self->{src} == NL || @{$self->{destin}} == 0;
	$self->{piece} = $self->piece($self->{src});
	my $destin = $self->{destin};
	$self->{destin} = [];
	while (@$destin) {
		push @{$self->{destin}}, shift @$destin;
		$self->transformOne;
	}
}

sub dst_1 ($) {
	my $self = shift;
	return @{$self->{destin}} == 0? $self->{src}: $self->{destin}->[-1];
}

sub dst_2 ($) {
	my $self = shift;
	return @{$self->{destin}} == 1? $self->{src}: $self->{destin}->[-2];
}

1;