Project tutorial

# Chinese Rings Puzzle With Arduino © CC BY-NC-ND

The Chinese Rings Puzzle with Arduino is my version of a centennial puzzle. Play it and have fun for a long time!!

• 4,876 views
• 17 respects

## Components and supplies

 Arduino UNO & Genuino UNO
×1
 DFRobot LCD Keypad Shield For Arduino https://www.dfrobot.com/product-51.html
×1

## Apps and online services

 Arduino IDE

### Introduction

Hello all,

The Chinese Rings Puzzle with Arduino is my version of a centennial Chinese puzzle.

It is very simple to play and it is an example of a combinatorial puzzle, and lots of patience and concentration is required to solve it.

The objective is to untangle the long loop from all nine rings, and the solution takes 341 moves (minimum possible).

Once you learn the method to solve the puzzle, you will see that is very easy to play it!

This project is very simple to be assembled, using only an Arduino UNO R3 and a LCD Keypad Shield.

It took me some time, but the code I developed reproduced exactly the same conditions and constraints as the original mechanical puzzle.

Let's do it and have a fun for a long time!!

LAGSILVA

### The Puzzle Story

Stewart Culin in his book "Games of the Orient" records a story that the Chinese Rings puzzle was invented by the famous Chinese hero Mung Ming (A.D. 181 - 234).

He apparently gave it to his wife when he went to war so she would have something to keep her busy in his absence. The story relates that she forgot her sorrow while trying to solve the puzzle.

This puzzle or the Cardano's Rings was introduced in Europe by Girolamo Cardano in 1550 and it is perhaps the greatest mechanical puzzle of China.

The original puzzle consists of a long loop with a handle on one end that is interlocked with nine rings.

### A Little of Math

The total of moves for a number of rings (n) is determined by the following equations:

1) When n is odd number:

T (n) = (2 ^ (n+1) − 1 ) / 3

2) When n is even number:

T (n) = (2 ^ (n+1) − 2 ) / 3

``````n	T(n)
1	1
2	2
3	5
4	10
5	21
6	42
7	85
8	170
9	341
10	682
11	1365
12	2730
13	5461
14	10922
15	21845
16	43690
17	87381
18	174762
19	349525
20	699050
``````

### Material List

• Arduino UNO R3

### Playing

The first line of LCD is shown the 09 rings, and in the second line is shown the pointer.

You must use the keys LEFT & RIGHT to move the pointer, and the key SELECT to remove or to insert a ring.

The LEFT key moves the pointer direct to the first ring position, and the RIGHT key moves the pointer one position step by step.

The LCD also shows the total amount of moves, counting every time you press SELECT key to remove or insert a ring.

The key RESTART is used to start again the game at any moment.

At the end, after you solve the puzzle completely, you will see the "Congratulations" message and your grade.

Note: You will see there are some restrictions to move the pointer and also to remove a ring, but this is part of the rules to solve the puzzle.

## Code

##### Chinese_Rings_Puzzle_V1_3.inoArduino
Code for Arduino UNO
```/*
Project:  CHINESE RINGS PUZZLE (09 Rings / 341 Moves)
Author:   LAGSILVA
Hardware: Arduino UNO-R3 / LCD Keypad Shield
Date:     03.Set.2018
Revision: 1.3
*/

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

byte anelOff[8] = {
B00000,
B00000,
B00000,
B11111,
B00000,
B00000,
B00000,
B00000,
};

byte anelOn[8] = {
B00100,
B01010,
B10001,
B11111,
B10001,
B01010,
B00100,
B00000,
};

byte ponteiro[8] = {
B00100,
B01110,
B11111,
B00100,
B00100,
B00100,
B00100,
B00000,
};

String aneis;
int px, p1, movimentos, k;
int botoes = 0;

#define btDir 1
#define btEsq 2
#define btCima 3
#define btBaixo 4
#define btOk 5
#define btNone 6

// Leitura dos Botoes
int ler_botoes()
{

//For V1.3 use this threshold (My Configuration)
if (estadoBotoes < 50)   return btDir;
if (estadoBotoes < 250)  return btCima;
if (estadoBotoes < 500)  return btBaixo;
if (estadoBotoes < 750)  return btEsq;
if (estadoBotoes < 850)  return btOk;

/*For V1.1 use this threshold (I use this configuration)
if (estadoBotoes < 50)   return btDir;
if (estadoBotoes < 250)  return btCima;
if (estadoBotoes < 450)  return btBaixo;
if (estadoBotoes < 650)  return btEsq;
if (estadoBotoes < 850)  return btOk;

/* For V1.0 comment the other threshold and use the one below:
if (estadoBotoes < 50)   return btDir;
if (estadoBotoes < 195)  return btCima;
if (estadoBotoes < 380)  return btBaixo;
if (estadoBotoes < 555)  return btEsq;
if (estadoBotoes < 790)  return btOk;
*/

return btNone;  // Retorna None qdo todas as opcoes falharem
}

void setup() {

//Serial.begin (19200);

lcd.begin(16, 2);

lcd.createChar(0, anelOff);
lcd.createChar(1, anelOn);
lcd.createChar(2, ponteiro);

lcd.clear();
lcd.setCursor(1, 0);
lcd.print("CHINESE RINGS");
lcd.setCursor(2, 1);
lcd.print("by LAGSILVA");

delay(3000);

telaInicial();

}

void loop() {

do {
botoes = ler_botoes();
delay(100);
} while (botoes == btNone);

delay(100);

switch (botoes) {

case btDir:
p1 = aneis.indexOf('1', 1);
if (px <= p1) {
if (aneis.substring(p1, p1 + 1) == "1") {
px = px + 1;
}
}
lcd.setCursor(0, 1);
lcd.print("        ");
lcd.setCursor(px - 1 , 1);
lcd.write(byte(2));

break;

case btEsq:

px = 1;
lcd.setCursor(0, 1);
lcd.print("         ");
lcd.setCursor(px - 1 , 1);
lcd.write(byte(2));

break;

case btBaixo:

if (aneis.substring(px - 1, px) == "1") {
if (aneis.substring(px, px + 1) == "1") {
aneis.setCharAt(px, '0');
lcd.setCursor(px - 1, 0);
lcd.write(byte(0));
}
else {
aneis.setCharAt(px, '1');
lcd.setCursor(px - 1, 0);
lcd.write(byte(1));
}
}
movimentos = movimentos + 1;
lcd.setCursor(12, 1);
lcd.print(movimentos);

break;

}

if (aneis == "1000000000") {
lcd.clear();
botoes = ler_botoes();
lcd.setCursor(0, 0);
lcd.print("CONGRATULATIONS!");
lcd.setCursor(0, 1);
lcd.print(34100 / movimentos);

do {
botoes = ler_botoes();
delay(100);
} while (botoes == btNone);
delay(500);
telaInicial();
}

}

void telaInicial() {

// Imprime Aneis e Estado Inicial
lcd.clear();
for (k = 0; k <= 8; k++) {
lcd.setCursor(k, 0);
lcd.write(byte(1));
}
lcd.setCursor(12, 0);
lcd.print("Move");

aneis = "1111111111";
movimentos = 0;

px = 1; //Posicao do Ponteiro "^"
p1 = 1; //Posicao do Primeiro "1"

lcd.setCursor(p1 - 1, 1);
lcd.write(byte(2));
lcd.setCursor(12, 1);
lcd.print(movimentos);

}
```

#### Author

##### LAGSILVA
• 28 projects
• 203 followers

June 2, 2017

#### Members who respect this project

and 9 others

See similar projects
you might like

• 1,815 views
• 1 comment
• 4 respects

#### Lottery Winner: Non-Repeating Random Numbers for Arduino

Project tutorial by LAGSILVA

• 3,864 views
• 26 respects

#### Digital Clock with Mirrored Display Driven by Accelerometers

Project showcase by LAGSILVA

• 14,394 views
• 1 comment
• 38 respects

#### Tiny Calendar and Clock Featuring Moon Phase in a LED Matrix

Project showcase by LAGSILVA

• 6,076 views
• 33 respects

#### Digital Clock with Arduino, RTC and Shift Register 74HC595

Project tutorial by LAGSILVA

• 20,734 views