/* Gridlock
Copyright (c) 2002-2003 by Brian Nenninger. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#import "PhotonicAttackGame.h"


@implementation PhotonicAttackGame

-(void)reset {
  [super reset];
  [self setGrid:[DCHypergrid gridWithRows:[[[self configurationInfo] objectForKey:@"rows"] intValue]
                                  columns:[[[self configurationInfo] objectForKey:@"cols"] intValue]]];
}

-(BOOL)prepareMoveSequence:(NSArray *)positions {
  id pos = [positions lastObject];
  int pnum = [self currentPlayerNumber];
  
  [self resetFutureGrid];
  [[self futureGrid] setValue:pnum atPosition:pos];
  // flip opposing pieces up, down, left, right of destination, and continue along each direction
  {
    static int ROW_DIRECTIONS[] = {+1, 0, 0,-1};
    static int COL_DIRECTIONS[] = { 0,-1,+1, 0};
    int oppnum = [self nextPlayerNumber];
    int r0 = [pos row];
    int c0 = [pos column];
    int i;
    for(i=0; i<4; i++) {
      BOOL done = NO;
      int d;
      for(d=1; !done; d++) {
        int r = r0+d*ROW_DIRECTIONS[i];
        int c = c0+d*COL_DIRECTIONS[i];
        if ([self isValidRow:r column:c] && [self valueAtRow:r column:c]==oppnum) {
          [[self futureGrid] setValue:pnum atRow:r column:c];
        }
        else done = YES;
      }
    }
  }
  return YES;
}

-(id)positionForShotFiredFromRow:(int)r ascending:(BOOL)asc {
  int numc = [self numberOfColumns];
  int c0 = (asc) ? 0 : numc-1;
  int dc = (asc) ? 1 : -1;
  int  d = 0;
  BOOL hit = NO;
  while (!hit && d<numc) {
    if ([self valueAtRow:r column:c0+d*dc]==0) d++;
    else hit = YES;
  }
  // d is the number of cells to the nearest piece (or off the other edge), so subtract 1 for the empty cell
  if (d>0) return [DCHypergridPosition positionWithRow:r column:c0+(d-1)*dc];
  else return nil;
}

-(id)positionForShotFiredFromColumn:(int)c ascending:(BOOL)asc {
  int numr = [self numberOfRows];
  int r0 = (asc) ? 0 : numr-1;
  int dr = (asc) ? 1 : -1;
  int  d = 0;
  BOOL hit = NO;
  while (!hit && d<numr) {
    if ([self valueAtRow:r0+d*dr column:c]==0) d++;
    else hit = YES;
  }
  // d is the number of cells to the nearest piece (or off the other edge), so subtract 1 for the empty cell
  if (d>0) return [DCHypergridPosition positionWithRow:r0+(d-1)*dr column:c];
  else return nil;
}

-(NSArray *)allValidMoveSequences {
  NSMutableArray *moves = [NSMutableArray array];
  int i;
  int numr=[self numberOfRows], numc=[self numberOfColumns];
  
  for(i=0; i<numr; i++) {
    id pos = [self positionForShotFiredFromRow:i ascending:YES];
    if (pos) [moves addObject:[pos arrayWithSelf_]];
    pos = [self positionForShotFiredFromRow:i ascending:NO];
    if (pos) [moves addObject:[pos arrayWithSelf_]];
  }
  for(i=0; i<numc; i++) {
    id pos = [self positionForShotFiredFromColumn:i ascending:YES];
    if (pos) [moves addObject:[pos arrayWithSelf_]];
    pos = [self positionForShotFiredFromColumn:i ascending:NO];
    if (pos) [moves addObject:[pos arrayWithSelf_]];
  }
  return moves;
}

-(BOOL)isGameOver {
  int i;
  int numr=[self numberOfRows], numc=[self numberOfColumns];
  // same as allValidMoveSequences, but bail as soon as we find any valid move
  for(i=0; i<numr; i++) {
    if ([self positionForShotFiredFromRow:i ascending:YES]) return NO;
    if ([self positionForShotFiredFromRow:i ascending:NO]) return NO;
  }
  for(i=0; i<numc; i++) {
    if ([self positionForShotFiredFromColumn:i ascending:YES]) return NO;
    if ([self positionForShotFiredFromColumn:i ascending:NO]) return NO;
  } 
  return YES;
}

-(BOOL)showScores {
  return YES;
}

@end
