nilang 0.4.1

A scripting language interpreter for Advent of Code
Documentation
// Maze Generation using Recursive Backtracking
// Creates a perfect maze (all cells connected, no loops)

// Global seed for random number generation
seed = 12345;

// Multiplicative congruential generator
fn random(min, max) {
  // Constants from Numerical Recipes
  a = 1103515245;
  c = 12345;
  m = 2147483648;  // 2^31

  // Update seed
  seed = ((a * seed + c) % m);

  // Make positive if negative
  if seed < 0 {
    seed = seed + m;
  }

  // Extract high-order bits by dividing before modulo
  // This gives better distribution for small ranges
  range = max - min + 1;
  bucket_size = m / range;

  if bucket_size > 0 {
    result = seed / bucket_size;
    if result >= range {
      result = range - 1;
    }
    return min + result;
  }

  // Fallback for very large ranges
  return min + (seed % range);
}

// Shuffle a list using Fisher-Yates algorithm
fn shuffle(list) {
  i = #list - 1;
  while i > 0 {
    j = random(0, i);

    // Swap elements
    temp = list[i];
    list[i] = list[j];
    list[j] = temp;

    i = i - 1;
  }
  return list;
}

fn create_grid(width, height) {
  height.times(fn(h) {
    row = [];
    width.times(fn(w) {
      row << true;
    });
    row;
  });
}

fn display_maze(grid) {
  top_border = "";
  width = #grid[0];
  height = #grid;

  // add 2 to account for left & right walls
  (width + 2).times(fn(i) {
    top_border << "██";
  });

  print(top_border);

  for row in grid.enumerate() {
    row_str = "██";
    for cell in row[1].enumerate() {
      if row[0] == width - 1 && cell[0] == height - 1 {
          row_str << "EE";
          continue;
      }
      if cell[0] == 0 && row[0] == 0 {
        row_str << "SS";
        continue;
      }

      if cell[1] {
        row_str << "██";
      } else {
        row_str << "  ";
      }
    }
    row_str << "██";
    print(row_str);

  }

  print(top_border);

}

fn count_empty_neighbors(cell, grid) {
  row = cell[0];
  col = cell[1];
  not_top = 0 < row;
  not_left = 0 < col;
  not_right = (col+1) < #grid[0];
  not_bottom = (row+1) < #grid;
  count = 0;

  if not_top && !grid[row - 1][col] {
    count = count + 1;
  }

  if not_left && !grid[row][col - 1] {
    count = count + 1;
  }

  if not_right && !grid[row][col + 1] {
    count = count + 1;
  }

  if not_bottom && !grid[row + 1][col] {
    count = count + 1;
  }

  return count;
}

fn get_wall_neighbors(cell, grid) {
  row = cell[0];
  col = cell[1];
  not_top = 0 < row;
  not_left = 0 < col;
  not_right = (col+1) < #grid[0];
  not_bottom = (row+1) < #grid;
  result = [];

  if not_top && grid[row - 1][col] {
      result << [row - 1, col];
  }

  if not_left && grid[row][col - 1] {
      result << [row, col - 1];
  }

  if not_right && grid[row][col + 1] {
      result << [row, col + 1];
  }

  if not_bottom && grid[row + 1][col] {
      result << [row + 1, col];
  }

  return result;
}

fn carve_passages(grid) {
  grid[0][0] = false;

  walls = [[0,1], [1, 0]];

  while #walls  {
    i = random(0, #walls - 1);
    wall_cell = walls.swap_remove(i);
    empty_neighbors = count_empty_neighbors(wall_cell, grid);
    if empty_neighbors != 1 { 
      continue; 
    }

    grid[wall_cell[0]][wall_cell[1]] = false;

    wall_neighbors = get_wall_neighbors(wall_cell, grid);
    for cell in wall_neighbors {
      walls << cell;
    }
  }
}

fn main() {
  print("=================================");
  print("    Maze Generator");
  print("=================================");
  print("");
  print("Enter maze width (try 10-20):");
  width_str = read.trim();
  width = int(width_str);

  print("Enter maze height (try 10-20):");
  height_str = read.trim();
  height = int(height_str);

  print("Enter random seed:");
  seed_str = read.trim();
  input_seed = int(seed_str);

  if width == null || height == null || input_seed == null {
    print("Invalid input!");
    return;
  }

  // Update global seed
  seed = input_seed;

  if width < 2 || height < 2 {
    print("Maze must be at least 2x2!");
    return;
  }

  print("");
  print("Generating {width}x{height} maze...");

  grid = create_grid(width, height);
  start_cell = [0, 0];
  carve_passages(grid);

  display_maze(grid);

  print("Done! The maze starts at the top-left.");
}

main();