⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gpe-lights.c

📁 此程序用于在运行嵌入式Linux系统的手机上
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 
 *   GLOP: Gnomified Lights Out Puzzles
 *   Copyright (C) 2001 Andreas T. Hagli <athagl00@grm.hia.no>
 * 
 *   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.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>

#include <gtk/gtk.h>
#include <glib.h>
#include <libintl.h>

#include <gpe/init.h>
#include <gpe/pixmaps.h>
#include <gpe/picturebutton.h>
#include <gpe/question.h>
#include <gdk-pixbuf/gdk-pixbuf.h>

#define _(x)  gettext(x)

#define LIGHT_SIZE 40
#define MAX_WIDTH 12
#define MAX_HEIGHT 9
#define GAME_EVENTS (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK| GDK_BUTTON_RELEASE_MASK)

enum game_types { CLASSIC, TWOK, DELUX, KEYCHAIN, CUBE, MERLIN };
enum light_state { NO, ON, HALF, OFF };

static GtkWidget *moves_label, *lights_off, *lights_label;
static GtkWidget *vb, *status_box;
static GtkWidget *align, *draw_area;
static GtkWidget *pref_dialog;
static GdkPixbuf *lights;

static gchar *fname;

static int x_dir[8] = { 1, 1, 0,-1,-1,-1,0,1 };
static int y_dir[8] = { 0,-1,-1,-1, 0, 1,1,1 };

static int game_type;
static int moves;
static gboolean randomize;
static gboolean theme_default;
static char *theme;

static char *pref_theme;
static gboolean pref_theme_default;
static gboolean pref_randomize;
static int pref_game_type;

static struct game_values {
  int width;
  int height;
  gboolean cubeform;
  gboolean consistent;
  int states;
  /* From east to south east (like radians; 0 -> 2PI).  */
  gboolean neighbours[8];
} game;

enum game_types grid[MAX_WIDTH][MAX_HEIGHT];

static void new_game (void);

static void
draw_light (int x, int y)
{
  int bx, by;

  if (grid[x][y] != NO)
    {
      by = 0;
      bx = LIGHT_SIZE * (grid[x][y] - 1);

      gdk_draw_pixbuf (draw_area->window,
		       draw_area->style->black_gc, lights,
		       bx, by, x * LIGHT_SIZE, y * LIGHT_SIZE,
		       LIGHT_SIZE, LIGHT_SIZE, GDK_RGB_DITHER_NORMAL, 0, 0);
    }
  else
    gdk_window_clear_area (draw_area->window, x * LIGHT_SIZE, y * LIGHT_SIZE,
			   LIGHT_SIZE, LIGHT_SIZE);
}

static void
paint (GdkRectangle *area)
{
  int x1, y1, x2, y2, x, y;

  x1 = area->x / LIGHT_SIZE;
  y1 = area->y / LIGHT_SIZE;
  x2 = (area->x + area->width) / LIGHT_SIZE;
  y2 = (area->y + area->height) / LIGHT_SIZE;

  for (x = x1; x <= x2; x++){
    for (y = y1; y <= y2; y++){
      draw_light (x, y);
    }
  }
}

static void
game_over (void)
{
  gchar *msg;
  int r;
 
  msg = g_strdup_printf (_("Congratulations!\n\nYou made it with %d moves.\n\nPlay again?"), moves);

  r = gpe_question_ask (msg, _("Game over"), "icon", "!gtk-yes", NULL, "!gtk-no", NULL, NULL, NULL);

  g_free (msg);

  if (r == 0)
    new_game ();
}

static int
count_lights_on (void)
{
  int x, y;
  int counter = 0;

  for (x = 0; x < (game.cubeform ? 4 : 1) * game.width; x++)
    for (y = 0; y < (game.cubeform ? 3 : 1) * game.height; y++)
      if (grid[x][y] == ON || grid[x][y] == HALF)
	counter++;

  return counter;
}

static void
change_light (int x, int y)
{
  if (grid[x][y] == ON && game.states == 2)
    grid[x][y] = OFF;
  else if (grid[x][y] == ON && game.states == 3)
    grid[x][y] = HALF;
  else if (grid[x][y] == HALF)
    grid[x][y] = OFF;
  else if (grid[x][y] == OFF)
    grid[x][y] = ON;

  draw_light (x, y);
}

static void
set_lights_off (void)
{
  char buf [10];
  int nlo;

  nlo = game.width * game.height * (game.cubeform ? 6 : 1) - count_lights_on ();

  sprintf (buf, "%.2d", nlo);
  gtk_label_set (GTK_LABEL(lights_off), buf);
}

static void
set_moves (int new_moves)
{
  char buf [10];

  moves = new_moves;
  sprintf (buf, "%.2d ", moves);
  gtk_label_set (GTK_LABEL(moves_label), buf);
}

static void
select_light (int x, int y)
{
  int i;

  if (grid[x][y] == NO)
    return;

  change_light (x, y);

  if (game_type == MERLIN)
    {
      if (x != 0)
	change_light (x-1, y);
      if (x != 2)
	change_light (x+1, y);
      if (y != 0)
	change_light (x, y-1);
      if (y != 2)
	change_light (x, y+1);
      if (!(x == 1 && y == 1))
	change_light (1, 1);	
    }
  else
    {
      for (i = 0; i < 8; i++)
	if (game.neighbours[i])
	  {
	    if (game.cubeform)
	      {
		int tmp_x, tmp_y;

		tmp_x = x + x_dir[i];		  
		tmp_y = y + y_dir[i];		  

		if (tmp_y < 0)
		  {
		    tmp_y = game.height;
		    tmp_x = 5*game.width - tmp_x - 1;
		  }
		else if (y < game.height && tmp_x < game.width)
		  {
		    tmp_x = tmp_y;
		    tmp_y = game.height;
		  }
		else if (y < game.height && tmp_x >= 2*game.width)
		  {
		    tmp_x += game.width - tmp_y - 1;
		    tmp_y = game.height;
		  }
		else if (tmp_y < game.height && tmp_x < game.width)
		  {
		    tmp_y = tmp_x;
		    tmp_x = game.width;
		  }
		else if (tmp_y < game.height && tmp_x >= 3*game.width)
		  {
		    tmp_y = 0;
		    tmp_x = 5*game.width - tmp_x - 1;
		  }
		else if (tmp_y < game.height && tmp_x >= 2*game.width)
		  {
		    tmp_y = 3*game.width - tmp_x - 1;
		    tmp_x = 2*game.width - 1;
		  }
		else if (tmp_x < 0)
		  tmp_x = 4*game.width - 1;
		else if (tmp_x >= 4*game.width)
		  tmp_x = 0;
		else if (y >= 2*game.height && tmp_x < game.width)
		  {
		    tmp_x = 3*game.height - tmp_y - 1;
		    tmp_y = 2*game.height - 1;
		  }
		else if (y >= 2*game.height && tmp_x >= 2*game.width)
		  {
		    tmp_x = tmp_y;
		    tmp_y = 2*game.height - 1;
		  }
		else if (tmp_y >= 2*game.height && tmp_x < game.width)
		  {
		    tmp_y = 3*game.height - tmp_x - 1;
		    tmp_x = game.width;
		  }
		else if (tmp_y >= 2*game.height && tmp_x >= 3*game.width)
		  {
		    tmp_y = 3*game.height - 1;
		    tmp_x = 5*game.width - tmp_x - 1;
		  }
		else if (tmp_y >= 2*game.height && tmp_x >= 2*game.width)
		  {
		    tmp_y = tmp_x;
		    tmp_x = 2*game.width - 1;
		  }
		else if (tmp_y >= 3*game.height)
		  tmp_y = 0;

		change_light (tmp_x, tmp_y);
	      }
	    else if (game.consistent)
	      {
		int tmp_x, tmp_y;

		if ((x_dir[i] + x) < 0)
		  tmp_x = x + x_dir[i] + game.width;
		else if ((x_dir[i] + x) >= game.width)
		  tmp_x = x + x_dir[i] - game.width;
		else
		  tmp_x = x + x_dir[i];

		if ((y_dir[i] + y) < 0)
		  tmp_y = y + y_dir[i] + game.height;
		else if ((y_dir[i] + y) >= game.height)
		  tmp_y = y + y_dir[i] - game.height;
		else
		  tmp_y = y + y_dir[i];

		change_light (tmp_x, tmp_y);
	      }
	    else if ((x_dir[i] + x) >= 0 && (x_dir[i] + x) < game.width &&
		     (y_dir[i] + y) >= 0 && (y_dir[i] + y) < game.height)
	      change_light (x_dir[i] + x, y_dir[i] + y);
	  }
    }
}

static void
click_light (int x, int y)
{
  if (!count_lights_on ())
    return;

  select_light (x, y);

  if (grid[x][y] != NO)
    set_moves (++moves);
  set_lights_off ();

  gtk_widget_draw (draw_area, NULL);
  if (count_lights_on () == 0)
    game_over ();
}

static gint
area_event (GtkWidget *widget, GdkEvent *event, void *d)
{
  switch (event->type){
  case GDK_EXPOSE: {
    GdkEventExpose *e = (GdkEventExpose *) event;
    paint (&e->area);
    return TRUE;
  }
  case GDK_BUTTON_PRESS: {
    int x, y;
    gtk_widget_get_pointer (widget, &x, &y);
    click_light (x / LIGHT_SIZE, y / LIGHT_SIZE);
  }
  default:
    return FALSE;
  }
}

static void
game_randomize (void)
{
  int x, y, i;

  for (x = 0; x < (game.cubeform ? 4 : 1) * game.width; x++)
    for (y = 0; y < (game.cubeform ? 3 : 1) * game.height; y++)
      for (i = 0; i < rand () % game.states; i++)
	select_light (x, y);

  if (!count_lights_on ()) /* randomize() has "found" solution.  */
    {
      int i;

      for (i = 0; i <= game.states; i++)
	{
	  x = rand () % game.width;
	  y = rand () % game.height;

	  if (game.cubeform)
	    {
	      x += game.width * (rand () % 4);
	      if (x >= game.width && x < 2 * game.width)
		y += game.height * (rand () % 3);
	      else
		y += game.height;
	    }

	  select_light (x, y);
	}
    }

  gtk_widget_draw (draw_area, NULL);
  set_moves (0);
}

static void
reset_grid (void)
{
  int x, y;

  for (x = 0; x < (game.cubeform ? 4 : 1) * game.width; x++)
    for (y = 0; y < (game.cubeform ? 3 : 1) * game.height; y++)
      {
	grid[x][y] = ON;

	if (game.cubeform)
	  {
	    if (x < game.width)
	      if (y < game.height || y >= (2 * game.height))
		grid[x][y] = NO;
	    if (x >= 2 * game.width)
	      if (y < game.height || y >= (2 * game.height))
		grid[x][y] = NO;
	  }
      }
  if (randomize)
    game_randomize ();
}

static void
load_game_values (enum game_types type)
{
  int i;

  if (type == MERLIN)
    {
      game.width = 3;
      game.height = 3;
      game.cubeform = FALSE; /* not used */
      game.consistent = FALSE; /* not used */
      game.states = 2;
      /* The rules for neighbours in merlin is so different from the others
	 that it needs special treatment.  */
    }
  else if (type == KEYCHAIN)
    {
      game.width = 4;
      game.height = 4;
      game.cubeform = FALSE;
      game.consistent = TRUE;
      game.states = 2;
      for (i = 0; i < 8; i++)
	{
	  if ((i/2)*2 == i) /* i is even */
	    game.neighbours[i] = TRUE;
	  else /* i is odd */
	    game.neighbours[i] = FALSE;
	}
    }
  else if (type == CLASSIC)
    {
      game.width = 5;
      game.height = 5;
      game.cubeform = FALSE;
      game.consistent = FALSE;
      game.states = 2;
      for (i = 0; i < 8; i++)
	{
	  if ((i/2)*2 == i) /* i is even */
	    game.neighbours[i] = TRUE;
	  else /* i is odd */
	    game.neighbours[i] = FALSE;
	}
    }
  else if (type == TWOK)
    {
      game.width = 5;
      game.height = 5;
      game.cubeform = FALSE;
      game.consistent = FALSE;
      game.states = 3;
      for (i = 0; i < 8; i++)
	{
	  if ((i/2)*2 == i) /* i is even */
	    game.neighbours[i] = TRUE;
	  else /* i is odd */
	    game.neighbours[i] = FALSE;
	}
    }
  else if (type == DELUX)
    {
      game.width = 6;
      game.height = 6;
      game.cubeform = FALSE;
      game.consistent = FALSE;
      game.states = 2;
      for (i = 0; i < 8; i++)
	{
	  if ((i/2)*2 == i) /* i is even */
	    game.neighbours[i] = FALSE;
	  else /* i is odd */
	    game.neighbours[i] = TRUE;
	}
    }
  else if (type == CUBE)
    {
      game.width = 3;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -