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)&notify));
+  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;
+}