You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by pk...@apache.org on 2022/07/31 10:41:48 UTC
[incubator-nuttx-apps] branch master updated: apps/games: Add shift game
This is an automated email from the ASF dual-hosted git repository.
pkarashchenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new 8a177cd79 apps/games: Add shift game
8a177cd79 is described below
commit 8a177cd797d701b3214e71c2f1b995f010542769
Author: Alan Carvalho de Assis <ac...@gmail.com>
AuthorDate: Thu Jul 21 16:10:47 2022 -0300
apps/games: Add shift game
---
games/.gitignore | 1 +
games/Make.defs | 21 +
games/Makefile | 23 +
games/shift/Kconfig | 58 +++
games/shift/Make.defs | 23 +
games/shift/Makefile | 34 ++
games/shift/shift_input_console.h | 133 ++++++
games/shift/shift_input_gesture.h | 78 ++++
games/shift/shift_input_joystick.h | 166 +++++++
games/shift/shift_inputs.h | 64 +++
games/shift/shift_main.c | 927 +++++++++++++++++++++++++++++++++++++
11 files changed, 1528 insertions(+)
diff --git a/games/.gitignore b/games/.gitignore
new file mode 100644
index 000000000..9e1d2593e
--- /dev/null
+++ b/games/.gitignore
@@ -0,0 +1 @@
+/Kconfig
diff --git a/games/Make.defs b/games/Make.defs
new file mode 100644
index 000000000..7152bd5c6
--- /dev/null
+++ b/games/Make.defs
@@ -0,0 +1,21 @@
+############################################################################
+# apps/games/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(wildcard $(APPDIR)/games/*/Make.defs)
diff --git a/games/Makefile b/games/Makefile
new file mode 100644
index 000000000..736c18fda
--- /dev/null
+++ b/games/Makefile
@@ -0,0 +1,23 @@
+############################################################################
+# apps/games/Makefile
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+MENUDESC = "Games"
+
+include $(APPDIR)/Directory.mk
diff --git a/games/shift/Kconfig b/games/shift/Kconfig
new file mode 100644
index 000000000..0a59395d9
--- /dev/null
+++ b/games/shift/Kconfig
@@ -0,0 +1,58 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config GAMES_SHIFT
+ bool "Shift Game"
+ default n
+ ---help---
+ Enable Shift games. Shift is a brick game, like a mix
+ between Tetris and Crush Candy. The inspiration came
+ from a Shift game that was available for Android in the
+ F-Droid store. The original game source code still here:
+ https://github.com/boombuler/Shift/ but the game only works
+ for old Android versions (4.x).
+ NOTE: The source code here is not based on that code from
+ above github.
+
+if GAMES_SHIFT
+
+config GAMES_SHIFT_PROGNAME
+ string "Program name"
+ default "shift"
+ ---help---
+ This is the name of the program that will be used when the NSH ELF
+ program is installed.
+
+config GAMES_SHIFT_PRIORITY
+ int "Shift Game task priority"
+ default 100
+
+config GAMES_SHIFT_STACKSIZE
+ int "Shift Game stack size"
+ default DEFAULT_TASK_STACKSIZE
+
+#
+# Input Device Selection
+#
+
+choice
+ prompt "Input Device (Joystick, Gesture Sensor, etc)"
+ default GAMES_SHIFT_USE_CONSOLEKEY
+
+config GAMES_SHIFT_USE_CONSOLEKEY
+ bool "Serial Console as Input"
+ depends on !INPUT_DJOYSTICK && !SENSORS_APDS9960
+
+config GAMES_SHIFT_USE_DJOYSTICK
+ bool "Discrete Joystick as Input"
+ depends on INPUT_DJOYSTICK
+
+config GAMES_SHIFT_USE_GESTURE
+ bool "Gesture Sensor APDS-9960 as Input"
+ depends on SENSORS_APDS9960
+
+endchoice
+
+endif
diff --git a/games/shift/Make.defs b/games/shift/Make.defs
new file mode 100644
index 000000000..0dc269e74
--- /dev/null
+++ b/games/shift/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# apps/games/shift/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifeq ($(CONFIG_GAMES_SHIFT),y)
+CONFIGURED_APPS += $(APPDIR)/games/shift
+endif
diff --git a/games/shift/Makefile b/games/shift/Makefile
new file mode 100644
index 000000000..6bda408e9
--- /dev/null
+++ b/games/shift/Makefile
@@ -0,0 +1,34 @@
+############################################################################
+# apps/games/shift/Makefile
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+# Shift game info
+
+PROGNAME = $(CONFIG_GAMES_SHIFT_PROGNAME)
+PRIORITY = $(CONFIG_GAMES_SHIFT_PRIORITY)
+STACKSIZE = $(CONFIG_GAMES_SHIFT_STACKSIZE)
+MODULE = $(CONFIG_GAMES_SHIFT)
+
+# Shift game application
+
+MAINSRC = shift_main.c
+
+include $(APPDIR)/Application.mk
diff --git a/games/shift/shift_input_console.h b/games/shift/shift_input_console.h
new file mode 100644
index 000000000..d2f974d25
--- /dev/null
+++ b/games/shift/shift_input_console.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+ * apps/games/shift/shift_input_console.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <termios.h>
+
+#include "shift_inputs.h"
+
+/****************************************************************************
+ * Preprocessor Definitions
+ ****************************************************************************/
+
+/* Termios functions to have getch on Linux/NuttX */
+
+static struct termios g_old;
+static struct termios g_new;
+
+/* Initialize g_new terminal I/O settings */
+
+void init_termios(int echo)
+{
+ tcgetattr(0, &g_old); /* grab old terminal i/o settings */
+ g_new = g_old; /* use old settings as starting */
+ g_new.c_lflag &= ~ICANON; /* disable buffered I/O */
+ g_new.c_lflag &= ~ECHO; /* disable ECHO bit */
+ g_new.c_lflag |= echo ? ECHO : 0; /* set echo mode if requested */
+ tcsetattr(0, TCSANOW, &g_new); /* apply terminal I/O settings */
+}
+
+/* Restore g_old terminal i/o settings */
+
+void reset_termios(void)
+{
+ tcsetattr(0, TCSANOW, &g_old);
+}
+
+/* Read 1 character - echo defines echo mode */
+
+char getch_(int echo)
+{
+ char ch;
+
+ init_termios(echo);
+ ch = getchar();
+ reset_termios();
+
+ return ch;
+}
+
+/* Read 1 character without echo getch() function definition. */
+
+char getch(void)
+{
+ return getch_(0);
+}
+
+/****************************************************************************
+ * dev_input_init
+ ****************************************************************************/
+
+int dev_input_init(FAR struct input_state_s *dev)
+{
+ init_termios(0);
+
+ return OK;
+}
+
+/****************************************************************************
+ * dev_read_input
+ ****************************************************************************/
+
+int dev_read_input(FAR struct input_state_s *dev)
+{
+ char ch;
+
+ /* Arrows keys return three bytes: 27 91 [65-68] */
+
+ if ((ch = getch()) == 27)
+ {
+ if ((ch = getch()) == 91)
+ {
+ ch = getch();
+ if (ch == 65)
+ {
+ dev->dir = DIR_UP;
+ }
+ else if (ch == 66)
+ {
+ dev->dir = DIR_DOWN;
+ }
+ else if (ch == 67)
+ {
+ dev->dir = DIR_RIGHT;
+ }
+ else if (ch == 68)
+ {
+ dev->dir = DIR_LEFT;
+ }
+ }
+ else
+ {
+ dev->dir = DIR_NONE;
+ }
+ }
+ else
+ {
+ dev->dir = DIR_NONE;
+ }
+
+ return OK;
+}
+
diff --git a/games/shift/shift_input_gesture.h b/games/shift/shift_input_gesture.h
new file mode 100644
index 000000000..3547b3cf6
--- /dev/null
+++ b/games/shift/shift_input_gesture.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+ * apps/games/shift/shift_input_gesture.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/sensors/apds9960.h>
+
+#include "shift_inputs.h"
+
+/****************************************************************************
+ * Preprocessor Definitions
+ ****************************************************************************/
+
+#define APDS9960_DEVNAME "/dev/gest0"
+
+/****************************************************************************
+ * dev_input_init
+ ****************************************************************************/
+
+int dev_input_init(FAR struct input_state_s *dev)
+{
+ /* Open the gesture sensor APDS9960 */
+
+ dev->fd_gest = open(APDS9960_DEVNAME, O_RDONLY | O_NONBLOCK);
+ if (dev->fd_gest < 0)
+ {
+ int errcode = errno;
+ printf("ERROR: Failed to open %s: %d\n", APDS9960_DEVNAME, errcode);
+ return -ENODEV;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * dev_read_input
+ ****************************************************************************/
+
+int dev_read_input(FAR struct input_state_s *dev)
+{
+ int nbytes;
+ uint8_t gest;
+
+ nbytes = read(dev->fd_gest, (void *)&gest, sizeof(gest));
+ if (nbytes == sizeof(gest))
+ {
+ dev->dir = gest;
+ }
+ else
+ {
+ dev->dir = DIR_NONE;
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
diff --git a/games/shift/shift_input_joystick.h b/games/shift/shift_input_joystick.h
new file mode 100644
index 000000000..4a58217e6
--- /dev/null
+++ b/games/shift/shift_input_joystick.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+ * apps/games/shift/shift_input_joystick.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/input/djoystick.h>
+
+#include "shift_inputs.h"
+
+/****************************************************************************
+ * Preprocessor Definitions
+ ****************************************************************************/
+
+#define DJOYSTICK_DEVNAME "/dev/djoy0"
+#define DJOYSTICK_SIGNO 13
+
+/* The set of supported joystick discretes */
+
+static djoy_buttonset_t g_djoysupported;
+
+/* Last sampled discrete set */
+
+static djoy_buttonset_t g_djoylast;
+
+struct djoy_notify_s notify;
+
+/****************************************************************************
+ * dev_input_init
+ ****************************************************************************/
+
+int dev_input_init(FAR struct input_state_s *dev)
+{
+ int tmp;
+ int ret;
+
+ /* Open the djoystick device */
+
+ dev->fd_joy = open(DJOYSTICK_DEVNAME, O_RDONLY);
+ if (dev->fd_joy < 0)
+ {
+ fprintf(stderr, "ERROR: Failed to open %s: %d\n",
+ DJOYSTICK_DEVNAME, errno);
+ return -ENODEV;
+ }
+
+ /* Get the set of supported discretes */
+
+ ret = ioctl(dev->fd_joy, DJOYIOC_SUPPORTED,
+ (unsigned long)((uintptr_t)&tmp));
+ if (ret < 0)
+ {
+ fprintf(stderr, "ERROR: ioctl(DJOYIOC_SUPPORTED) failed: %d\n", errno);
+ goto errout_with_fd;
+ }
+
+ g_djoysupported = (djoy_buttonset_t)tmp;
+
+ /* Register to receive a signal on any change in the joystick discretes. */
+
+ notify.dn_press = g_djoysupported;
+ notify.dn_release = g_djoysupported;
+
+ notify.dn_event.sigev_notify = SIGEV_SIGNAL;
+ notify.dn_event.sigev_signo = DJOYSTICK_SIGNO;
+
+ ret = ioctl(dev->fd_joy, DJOYIOC_REGISTER,
+ (unsigned long)((uintptr_t)¬ify));
+ if (ret < 0)
+ {
+ fprintf(stderr, "ERROR: ioctl(DJOYIOC_REGISTER) failed: %d\n", errno);
+ goto errout_with_fd;
+ }
+
+ /* Ignore the default signal action */
+
+ signal(DJOYSTICK_SIGNO, SIG_IGN);
+
+ return OK;
+
+errout_with_fd:
+ close(dev->fd_joy);
+ return -ENODEV;
+}
+
+/****************************************************************************
+ * dev_read_input
+ ****************************************************************************/
+
+int dev_read_input(FAR struct input_state_s *dev)
+{
+ struct siginfo value;
+ sigset_t set;
+ djoy_buttonset_t newset;
+ ssize_t nread;
+ int ret;
+
+ /* Wait for a signal */
+
+ sigemptyset(&set);
+ sigaddset(&set, DJOYSTICK_SIGNO);
+ ret = sigwaitinfo(&set, &value);
+ if (ret < 0)
+ {
+ fprintf(stderr, "ERROR: sigwaitinfo() failed: %d\n", errno);
+ }
+
+ newset = (djoy_buttonset_t)value.si_value.sival_int;
+
+ g_djoylast = newset;
+
+ /* Read the signal set and compare */
+
+ nread = read(dev->fd_joy, &newset, sizeof(djoy_buttonset_t));
+ if (nread < 0)
+ {
+ fprintf(stderr, "ERROR: read() failed: %d\n", errno);
+ }
+ else if (nread != sizeof(djoy_buttonset_t))
+ {
+ fprintf(stderr, "ERROR: read() unexpected size: %ld vs %d\n",
+ (long)nread, sizeof(djoy_buttonset_t));
+ }
+
+ g_djoylast = newset;
+
+ switch (newset)
+ {
+ case DJOY_UP_BIT:
+ dev->dir = DIR_UP;
+ break;
+ case DJOY_DOWN_BIT:
+ dev->dir = DIR_DOWN;
+ break;
+ case DJOY_LEFT_BIT:
+ dev->dir = DIR_LEFT;
+ break;
+ case DJOY_RIGHT_BIT:
+ dev->dir = DIR_RIGHT;
+ break;
+ default:
+ dev->dir = DIR_NONE;
+ }
+
+ return OK;
+}
diff --git a/games/shift/shift_inputs.h b/games/shift/shift_inputs.h
new file mode 100644
index 000000000..c2141d6d3
--- /dev/null
+++ b/games/shift/shift_inputs.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * apps/games/shift/shift_inputs.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Preprocessor Definitions
+ ****************************************************************************/
+
+#ifndef DIR_NONE
+# define DIR_NONE 0
+#endif
+
+#ifndef DIR_LEFT
+# define DIR_LEFT 1
+#endif
+
+#ifndef DIR_RIGHT
+# define DIR_RIGHT 2
+#endif
+
+#ifndef DIR_UP
+# define DIR_UP 3
+#endif
+
+#ifndef DIR_DOWN
+# define DIR_DOWN 4
+#endif
+
+struct input_state_s
+{
+#ifdef CONFIG_GAMES_SHIFT_USE_CONSOLEKEY
+ int fd_con;
+#endif
+#ifdef CONFIG_GAMES_SHIFT_USE_DJOYSTICK
+ int fd_joy;
+#endif
+#ifdef CONFIG_GAMES_SHIFT_USE_GESTURE
+ int fd_gest;
+#endif
+ int dir; /* Direction to move the blocks */
+};
+
diff --git a/games/shift/shift_main.c b/games/shift/shift_main.c
new file mode 100644
index 000000000..d0906bf58
--- /dev/null
+++ b/games/shift/shift_main.c
@@ -0,0 +1,927 @@
+/****************************************************************************
+ * apps/games/shift/shift_main.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+
+#include <nuttx/video/fb.h>
+#include <nuttx/video/rgbcolors.h>
+
+#ifdef CONFIG_GAMES_SHIFT_USE_CONSOLEKEY
+#include "shift_input_console.h"
+#endif
+
+#ifdef CONFIG_GAMES_SHIFT_USE_DJOYSTICK
+#include "shift_input_joystick.h"
+#endif
+
+#ifdef CONFIG_GAMES_SHIFT_USE_GESTURE
+#include "shift_input_gesture.h"
+#endif
+
+/****************************************************************************
+ * Preprocessor Definitions
+ ****************************************************************************/
+
+#define BOARDX_SIZE 6
+#define BOARDY_SIZE 6
+
+#define ROW 8
+#define COL 8
+
+/* Difficult mode: 4, 5, 6 */
+
+#define GAMEMODE 6
+
+#define NCOLORS GAMEMODE
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct screen_state_s
+{
+ int fd_fb;
+ struct fb_videoinfo_s vinfo;
+ struct fb_planeinfo_s pinfo;
+#ifdef CONFIG_FB_OVERLAY
+ struct fb_overlayinfo_s oinfo;
+#endif
+ FAR void *fbmem;
+};
+
+struct game_screen_s
+{
+ int xres; /* X display resolution */
+ int yres; /* Y display resolution */
+ int xoff; /* X offset to start drawing */
+ int yoff; /* Y offset to start drawing */
+ int ncolors; /* Supported number of colors */
+ int blklen; /* Size of side of the blocks */
+ int steps; /* Steps to slide a block for a now position */
+ int stepinc; /* Step increment during the sliding */
+ int dir; /* Direction to move the blocks */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char g_default_fbdev[] = "/dev/fb0";
+
+/* The edge of the board is invisible to user */
+
+int board[ROW][COL] =
+{
+ {1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1}
+};
+
+int prev_board[ROW][COL] =
+{
+ {1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 0, 0, 0, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1}
+};
+
+/* Colors used in the game plus Black */
+
+static const uint16_t pallete[NCOLORS + 1] =
+{
+ RGB16_BLACK,
+ RGB16_BLUE,
+ RGB16_GREEN,
+ RGB16_RED,
+ RGB16_CYAN,
+ RGB16_WHITE,
+ RGB16_GOLD,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void draw_rect(FAR struct screen_state_s *state,
+ FAR struct fb_area_s *area, int color)
+{
+ FAR uint16_t *dest;
+ FAR uint8_t *row;
+ int x;
+ int y;
+
+ row = (FAR uint8_t *)state->fbmem + state->pinfo.stride * area->y;
+ for (y = 0; y < area->h; y++)
+ {
+ dest = ((FAR uint16_t *)row) + area->x;
+ for (x = 0; x < area->w; x++)
+ {
+ *dest++ = pallete[color];
+ }
+
+ row += state->pinfo.stride;
+ }
+}
+
+void update_screen(FAR struct screen_state_s *state,
+ FAR struct fb_area_s *area)
+{
+ int ret;
+
+#ifdef CONFIG_FB_UPDATE
+ ret = ioctl(state->fd_fb, FBIO_UPDATE,
+ (unsigned long)((uintptr_t)area));
+ if (ret < 0)
+ {
+ int errcode = errno;
+ fprintf(stderr, "ERROR: ioctl(FBIO_UPDATE) failed: %d\n",
+ errcode);
+ }
+#endif
+}
+
+/* Draw the user board without the edges */
+
+void draw_board(FAR struct screen_state_s *state,
+ FAR struct fb_area_s *area,
+ FAR struct game_screen_s *screen)
+{
+ int row;
+ int col;
+ int x;
+ int y;
+ int i;
+ int color;
+
+ /* Clear the framebuffer, but don't update yet */
+
+ area->x = 0;
+ area->y = 0;
+ area->w = screen->xres;
+ area->h = screen->yres;
+
+ draw_rect(state, area, 0);
+
+ for (i = screen->steps; i > 0; i--)
+ {
+ for (row = 1; row <= BOARDX_SIZE; row++)
+ {
+ for (col = 1; col <= BOARDY_SIZE; col++)
+ {
+ color = board[row][col];
+
+ x = (col - 1) * screen->blklen + screen->xoff;
+ y = (row - 1) * screen->blklen + screen->yoff;
+
+ /* Get original width and height of blocks */
+
+ area->w = screen->blklen;
+ area->h = screen->blklen;
+
+ /* Only do the sliding for blocks that changed */
+
+ if (prev_board[row][col] != board[row][col])
+ {
+ if (screen->dir == DIR_NONE)
+ {
+ area->x = x;
+ area->y = y;
+ }
+
+ if (screen->dir == DIR_UP)
+ {
+ area->x = x;
+ area->y = y + ((i - 1) * screen->stepinc);
+ }
+
+ if (screen->dir == DIR_DOWN)
+ {
+ area->x = x;
+ area->y = y - ((i - 1) * screen->stepinc);
+ }
+
+ if (screen->dir == DIR_LEFT)
+ {
+ area->x = x + ((i - 1) * screen->stepinc);
+ area->y = y;
+ }
+
+ if (screen->dir == DIR_RIGHT)
+ {
+ area->x = x - ((i - 1) * screen->stepinc);
+ area->y = y;
+ }
+ }
+ else
+ {
+ area->x = x;
+ area->y = y;
+ }
+
+ /* Drawn only part of block if above margin */
+
+ if (area->x > (screen->xres - 2 * screen->xoff))
+ {
+ area->x = (screen->xres - 2 * screen->xoff) + 1;
+ area->w = 1;
+ }
+
+ if (area->x < screen->xoff)
+ {
+ area->x = screen->xoff;
+ }
+
+ if (area->y > (screen->yres - 2 * screen->yoff))
+ {
+ area->y = (screen->yres - 2 * screen->yoff) + 1;
+ area->h = 1;
+ }
+
+ if (area->y < screen->yoff)
+ {
+ area->y = screen->yoff;
+ }
+
+ draw_rect(state, area, color);
+ }
+ }
+
+ area->x = 0;
+ area->y = 0;
+ area->w = screen->xres;
+ area->h = screen->yres;
+
+ update_screen(state, area);
+ usleep(100000);
+ }
+}
+
+/****************************************************************************
+ * Name: print_board
+ *
+ * Description:
+ * Draw the board including the user non-visible border for debugging.
+ ****************************************************************************/
+
+#ifdef DEBUG_SHIFT_GAME
+void print_board(void)
+{
+ int row;
+ int col;
+
+ for (row = 0; row < ROW; row++)
+ {
+ printf("+---+---+---+---+---+---+---+---+\n");
+
+ for (col = 0; col < COL; col++)
+ {
+ if (row == 0 || col == 0 || row == ROW - 1 || col == COL - 1)
+ {
+ printf("|>%c<", board[row][col] + 48);
+ }
+ else
+ {
+ printf("| %c ", board[row][col] + 48);
+ }
+ }
+
+ printf("|\n");
+ }
+
+ printf("+---+---+---+---+---+---+---+---+\n\n\n");
+}
+#endif
+
+/****************************************************************************
+ * Name: move_board
+ *
+ * Description:
+ * Move the blocks (represented by numbers) to 'dir' direction (L,R,U,D).
+ ****************************************************************************/
+
+void move_board(int dir)
+{
+ int row;
+ int row_ini;
+ int col;
+ int col_ini;
+ int row_dir;
+ int row_pos;
+ int col_dir;
+ int col_pos;
+ int row_lim;
+ int col_lim;
+
+ if (dir == DIR_UP)
+ {
+ row_ini = 0;
+ row_dir = 1;
+ row_pos = 1;
+ row_lim = BOARDY_SIZE + 1;
+
+ col_ini = 0;
+ col_dir = 1;
+ col_pos = 0;
+ col_lim = BOARDX_SIZE + 1;
+ }
+
+ if (dir == DIR_DOWN)
+ {
+ row_ini = BOARDY_SIZE + 1;
+ row_dir = -1;
+ row_pos = -1;
+ row_lim = 0;
+
+ col_ini = 0;
+ col_dir = 1;
+ col_pos = 0;
+ col_lim = BOARDX_SIZE + 1;
+ }
+
+ if (dir == DIR_RIGHT)
+ {
+ row_ini = 0;
+ row_dir = 1;
+ row_pos = 0;
+ row_lim = BOARDY_SIZE + 1;
+
+ col_ini = BOARDX_SIZE + 1;
+ col_dir = -1;
+ col_pos = -1;
+ col_lim = 0;
+ }
+
+ if (dir == DIR_LEFT)
+ {
+ row_ini = 0;
+ row_dir = 1;
+ row_pos = 0;
+ row_lim = BOARDY_SIZE + 1;
+
+ col_ini = 0;
+ col_dir = 1;
+ col_pos = 1;
+ col_lim = BOARDX_SIZE + 1;
+ }
+
+ for (row = row_ini; row != row_lim; row += row_dir)
+ {
+ for (col = col_ini; col != col_lim; col += col_dir)
+ {
+ /* Never move item if we are in the cache border */
+
+ if ((row != 0 && col != 0) &&
+ (row != 0 && col != BOARDX_SIZE + 1) &&
+ (row != BOARDY_SIZE + 1 && col != 0) &&
+ (row != BOARDY_SIZE + 1 && col != BOARDX_SIZE + 1))
+ {
+ if (board[row][col] == 0)
+ {
+ board[row][col] = board[row + row_pos][col + col_pos];
+ board[row + row_pos][col + col_pos] = 0;
+ }
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: fill_edge
+ *
+ * Description:
+ * Fill the invisible border with "colored" blocks
+ ****************************************************************************/
+
+void fill_edge(void)
+{
+ int i;
+
+ for (i = 0; i <= BOARDX_SIZE + 1; i++)
+ {
+ board[0][i] = (random() % GAMEMODE) + 1;
+ board[BOARDY_SIZE + 1][i] = (random() % GAMEMODE) + 1;
+ }
+
+ for (i = 0; i <= BOARDY_SIZE + 1; i++)
+ {
+ board[i][0] = (random() % GAMEMODE) + 1;
+ board[i][BOARDY_SIZE + 1] = (random() % GAMEMODE) + 1;
+ }
+}
+
+/****************************************************************************
+ * Name: fill_border
+ *
+ * Description:
+ * Fill the visible border with "colored" blocks
+ ****************************************************************************/
+
+void fill_border(void)
+{
+ int i;
+
+ for (i = 1; i < BOARDX_SIZE + 1; i++)
+ {
+ board[1][i] = (random() % GAMEMODE) + 1;
+ board[BOARDY_SIZE][i] = (random() % GAMEMODE) + 1;
+ }
+
+ for (i = 1; i < BOARDY_SIZE + 1; i++)
+ {
+ board[i][1] = (random() % GAMEMODE) + 1;
+ board[i][BOARDY_SIZE] = (random() % GAMEMODE) + 1;
+ }
+}
+
+/****************************************************************************
+ * Name: search_board_squares
+ *
+ * Description:
+ * Search for squares or triples of same colors.
+ ****************************************************************************/
+
+int search_board_squares(void)
+{
+ int row;
+ int col;
+ int found = 0;
+
+ for (row = 1; row < BOARDY_SIZE; row++)
+ {
+ for (col = 1; col < BOARDX_SIZE; col++)
+ {
+ if (board[row][col] != 0)
+ {
+ if (fabs(board[row][col]) == fabs(board[row][col + 1]))
+ {
+ /* Square */
+
+ if (fabs(board[row][col]) == fabs(board[row + 1][col]) &&
+ fabs(board[row][col + 1]) ==
+ fabs(board[row + 1][col + 1]))
+ {
+ found = 1;
+ board[row][col] = board[row][col] > 0 ?
+ -board[row][col] : board[row][col];
+ board[row][col + 1] = board[row][col + 1] > 0 ?
+ -board[row][col + 1] :
+ board[row][col + 1];
+ board[row + 1][col] = board[row + 1][col] > 0 ?
+ -board[row + 1][col] :
+ board[row + 1][col];
+ board[row + 1][col + 1] = board[row + 1][col + 1] > 0 ?
+ -board[row + 1][col + 1] :
+ board[row + 1][col + 1];
+ }
+
+ /* |- */
+
+ if (fabs(board[row][col]) == fabs(board[row + 1][col]))
+ {
+ found = 1;
+ board[row][col] = board[row][col] > 0 ?
+ -board[row][col] :
+ board[row][col];
+ board[row][col + 1] = board[row][col + 1] > 0 ?
+ -board[row][col + 1] :
+ board[row][col + 1];
+ board[row + 1][col] = board[row + 1][col] > 0 ?
+ -board[row + 1][col] :
+ board[row + 1][col];
+ }
+
+ /* -| */
+
+ if (fabs(board[row][col + 1]) ==
+ fabs(board[row + 1][col + 1]))
+ {
+ found = 1;
+ board[row][col] = board[row][col] > 0 ?
+ -board[row][col] : board[row][col];
+ board[row][col + 1] = board[row][col + 1] > 0 ?
+ -board[row][col + 1] :
+ board[row][col + 1];
+ board[row + 1][col + 1] = board[row + 1][col + 1] > 0 ?
+ -board[row + 1][col + 1] :
+ board[row + 1][col + 1];
+ }
+ }
+
+ if (fabs(board[row][col]) == fabs(board[row + 1][col]))
+ {
+ /* |_ */
+
+ if (fabs(board[row + 1][col]) ==
+ fabs(board[row + 1][col + 1]))
+ {
+ found = 1;
+ board[row][col] = board[row][col] > 0 ?
+ -board[row][col] : board[row][col];
+ board[row + 1][col] = board[row + 1][col] > 0 ?
+ -board[row + 1][col] :
+ board[row + 1][col];
+ board[row + 1][col + 1] = board[row + 1][col + 1] > 0 ?
+ -board[row + 1][col + 1] :
+ board[row + 1][col + 1];
+ }
+ }
+ }
+
+ if (board[row + 1][col] != 0)
+ {
+ /* _| */
+
+ if (fabs(board[row + 1][col]) == fabs(board[row + 1][col + 1]))
+ {
+ if (fabs(board[row + 1][col + 1]) ==
+ fabs(board[row][col + 1]))
+ {
+ found = 1;
+ board[row][col + 1] = board[row][col + 1] > 0 ?
+ -board[row][col + 1] :
+ board[row][col + 1];
+ board[row + 1][col] = board[row + 1][col] > 0 ?
+ -board[row + 1][col] :
+ board[row + 1][col];
+ board[row + 1][col + 1] = board[row + 1][col + 1] > 0 ?
+ -board[row + 1][col + 1] :
+ board[row + 1][col + 1];
+ }
+ }
+ }
+ }
+ }
+
+ return found;
+}
+
+/****************************************************************************
+ * Name: search_board_squares
+ *
+ * Description:
+ * Search for vertical/horizontal lines of same colours.
+ ****************************************************************************/
+
+int search_board_lines(void)
+{
+ int row;
+ int col;
+ int h = 0;
+ int hpos = 0;
+ int hfound = 0;
+ int v = 0;
+ int vpos = 0;
+ int vfound = 0;
+ int found = 0;
+ int prev_sym = 0;
+
+ /* Search horizontal lines */
+
+ for (row = 1; row < BOARDY_SIZE + 1; row++)
+ {
+ prev_sym = board[row][1];
+
+ for (col = 1; col < BOARDX_SIZE; col++)
+ {
+ if (board[row][col] != 0)
+ {
+ if (fabs(board[row][col]) == fabs(board[row][col + 1]))
+ {
+ if (!hfound)
+ {
+ hpos = col;
+ hfound = 1;
+ prev_sym = board[row][col];
+ }
+
+ if (fabs(board[row][col]) == fabs(prev_sym))
+ {
+ h++;
+ }
+ }
+ else if (h < 2)
+ {
+ h = 0;
+ hpos = 1;
+ hfound = 0;
+ }
+ }
+ }
+
+ if (h >= 2)
+ {
+ for (int i = hpos; i <= hpos + h; i++)
+ {
+ board[row][i] = board[row][i] > 0 ?
+ -board[row][i] : board[row][i];
+ found = 1;
+ }
+ }
+
+ h = 0;
+ hpos = 1;
+ hfound = 0;
+ }
+
+ /* Search vertical lines */
+
+ for (col = 1; col < BOARDX_SIZE + 1; col++)
+ {
+ prev_sym = board[1][col];
+
+ for (row = 1; row < BOARDY_SIZE; row++)
+ {
+ if (board[row][col] != 0)
+ {
+ if (fabs(board[row][col]) == fabs(board[row + 1][col]))
+ {
+ if (!vfound)
+ {
+ vpos = row;
+ vfound = 1;
+ prev_sym = board[row][col];
+ }
+
+ if (fabs(board[row][col]) == fabs(prev_sym))
+ {
+ v++;
+ }
+ }
+ else if (v < 2)
+ {
+ v = 0;
+ vpos = 1;
+ vfound = 0;
+ }
+ }
+ }
+
+ if (v >= 2)
+ {
+ for (int i = vpos; i <= vpos + v; i++)
+ {
+ board[i][col] = board[i][col] > 0 ?
+ -board[i][col] : board[i][col];
+ found = 1;
+ }
+ }
+
+ v = 0;
+ vpos = 1;
+ vfound = 0;
+ }
+
+ return found;
+}
+
+/****************************************************************************
+ * Name: check_board
+ *
+ * Description:
+ * Verify if there are match lines/squares and remove them
+ ****************************************************************************/
+
+int check_board(void)
+{
+ int found = 0;
+ int row;
+ int col;
+
+ found = search_board_lines();
+ found |= search_board_squares();
+
+ /* Remove all negative values */
+
+ for (row = 0; row < ROW; row++)
+ {
+ for (col = 0; col < COL; col++)
+ {
+ if (board[row][col] < 0)
+ {
+ board[row][col] = 0;
+ }
+ }
+ }
+
+ return found;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * shift_main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+ FAR const char *fbdev = g_default_fbdev;
+ struct game_screen_s screen;
+ struct input_state_s input;
+ struct screen_state_s state;
+ struct fb_area_s area;
+ int score = 0;
+ int ret;
+
+ /* Open the framebuffer driver */
+
+ state.fd_fb = open(fbdev, O_RDWR);
+ if (state.fd_fb < 0)
+ {
+ int errcode = errno;
+ fprintf(stderr, "ERROR: Failed to open %s: %d\n", fbdev, errcode);
+ return EXIT_FAILURE;
+ }
+
+ /* Get the characteristics of the framebuffer */
+
+ ret = ioctl(state.fd_fb, FBIOGET_VIDEOINFO,
+ (unsigned long)((uintptr_t)&state.vinfo));
+ if (ret < 0)
+ {
+ int errcode = errno;
+ fprintf(stderr, "ERROR: ioctl(FBIOGET_VIDEOINFO) failed: %d\n",
+ errcode);
+ close(state.fd_fb);
+ return EXIT_FAILURE;
+ }
+
+ printf("VideoInfo:\n");
+ printf(" fmt: %u\n", state.vinfo.fmt);
+ printf(" xres: %u\n", state.vinfo.xres);
+ printf(" yres: %u\n", state.vinfo.yres);
+ printf(" nplanes: %u\n", state.vinfo.nplanes);
+
+ /* Setup the screen information */
+
+ screen.xres = state.vinfo.xres > state.vinfo.yres ?
+ state.vinfo.yres : state.vinfo.xres;
+ screen.yres = state.vinfo.yres > state.vinfo.xres ?
+ state.vinfo.xres : state.vinfo.yres;
+ screen.xoff = (screen.xres % NCOLORS) / 2;
+ screen.yoff = (screen.yres % NCOLORS) / 2;
+ screen.steps = 2;
+ screen.stepinc = 1;
+ screen.blklen = (screen.xres / NCOLORS);
+ screen.ncolors = NCOLORS;
+
+ /* Get the display planeinfo */
+
+ ret = ioctl(state.fd_fb, FBIOGET_PLANEINFO,
+ (unsigned long)((uintptr_t)&state.pinfo));
+ if (ret < 0)
+ {
+ int errcode = errno;
+ fprintf(stderr, "ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n",
+ errcode);
+ close(state.fd_fb);
+ return EXIT_FAILURE;
+ }
+
+ printf("PlaneInfo (plane 0):\n");
+ printf(" fbmem: %p\n", state.pinfo.fbmem);
+ printf(" fblen: %lu\n", (unsigned long)state.pinfo.fblen);
+ printf(" stride: %u\n", state.pinfo.stride);
+ printf(" display: %u\n", state.pinfo.display);
+ printf(" bpp: %u\n", state.pinfo.bpp);
+
+ state.fbmem = mmap(NULL, state.pinfo.fblen, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FILE, state.fd_fb, 0);
+ if (state.fbmem == MAP_FAILED)
+ {
+ int errcode = errno;
+ fprintf(stderr, "ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n",
+ errcode);
+ close(state.fd_fb);
+ return EXIT_FAILURE;
+ }
+
+ printf("Mapped FB: %p\n", state.fbmem);
+
+ /* Fill the edge with random values */
+
+ fill_edge();
+ fill_border();
+
+ /* Draw the empty board to user */
+
+ draw_board(&state, &area, &screen);
+
+ dev_input_init(&input);
+
+ while (1)
+ {
+ ret = dev_read_input(&input);
+
+ screen.dir = input.dir;
+
+#ifdef DEBUG_SHIFT_GAME
+ printf("Before moving:\n");
+ print_board();
+ usleep(2000000);
+#endif
+
+ /* Save a copy of the board before moving to new position */
+
+ memcpy(prev_board, board, (sizeof(int) * ROW * COL));
+
+ move_board(screen.dir);
+
+ draw_board(&state, &area, &screen);
+
+#ifdef DEBUG_SHIFT_GAME
+ printf("After moving:\n");
+ print_board();
+ usleep(1000000);
+#endif
+
+ /* Save a copy of the board after moving the pieces */
+
+ memcpy(prev_board, board, (sizeof(int) * ROW * COL));
+
+ screen.dir = DIR_NONE;
+
+ /* If we found bricks with same colors */
+
+ if (check_board() == 1)
+ {
+ int i;
+
+ /* Lets do a blinking effect */
+
+ for (i = 0; i < 3; i++)
+ {
+ /* Draw the board with the pieces */
+
+ memcpy(board, prev_board, (sizeof(int) * ROW * COL));
+
+ draw_board(&state, &area, &screen);
+ usleep(100000);
+
+ /* Draw the board without the pieces */
+
+ check_board();
+ draw_board(&state, &area, &screen);
+ usleep(100000);
+ }
+
+ usleep(500000);
+
+ score += 100;
+ }
+
+#ifdef DEBUG_SHIFT_GAME
+ printf("After checking:\n");
+ print_board();
+ usleep(1000000);
+#endif
+
+ usleep(1000000);
+
+ /* Add random pieces in the not visible border */
+
+ fill_edge();
+ }
+
+ return 0;
+}