///////////////////////////////////////////////////////////////////////////////////////////
//// 1A2B 遊戲
// 引用arduino內建 SPI 程式庫
#include<SPI.h>
//// 接線
// CS : GPIO5 // CLK : GPIO18 // DATA(MOSI) : GPIO23
const byte CS = 5; // Chip Select晶片選擇線(SS周邊選擇線)
const int deviceNnm = 16; // 串連設備數
const int symbolNum = 38; // 符號數
const byte colPins[4] = {27, 14, 12, 13}; // 設定「行」腳位
const byte rowPins[4] = {22, 33, 25, 26}; // 設定「列」腳位
const char keymap[4][4] = { // 設定按鍵的「行、列」代表值
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
char num[10000][4];
char m[10000];
//// 繪圖資料
const char symbol[symbolNum] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'j',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
':','!'
};
const byte pixel[symbolNum + 1][8] = {
{0x00,0x3c,0x66,0x6e,0x76,0x66,0x3c,0x00}, //0
{0x00,0x18,0x38,0x18,0x18,0x18,0x3c,0x00}, //1
{0x00,0x3c,0x66,0x06,0x3c,0x60,0x7e,0x00}, //2
{0x00,0x3c,0x06,0x1c,0x06,0x66,0x3c,0x00}, //3
{0x00,0x0c,0x1c,0x3c,0x6c,0x7e,0x0c,0x00}, //4
{0x00,0x7c,0x60,0x7c,0x06,0x66,0x3c,0x00}, //5
{0x00,0x3c,0x60,0x7c,0x66,0x66,0x3c,0x00}, //6
{0x00,0x7e,0x66,0x06,0x0c,0x18,0x18,0x00}, //7
{0x00,0x3c,0x66,0x3c,0x66,0x66,0x3c,0x00}, //8
{0x00,0x3c,0x66,0x66,0x3e,0x06,0x3c,0x00}, //9
{0x00,0x3c,0x66,0x66,0x7e,0x66,0x66,0x00}, //A
{0x00,0x7c,0x66,0x7c,0x66,0x66,0x7c,0x00}, //B
{0x00,0x3c,0x66,0x60,0x60,0x66,0x3c,0x00}, //C
{0x00,0x7c,0x66,0x66,0x66,0x66,0x7c,0x00}, //D
{0x00,0x7e,0x60,0x7c,0x60,0x60,0x7e,0x00}, //E
{0x00,0x7e,0x60,0x60,0x7c,0x60,0x60,0x00}, //F
{0x00,0x3c,0x66,0x60,0x6e,0x66,0x3e,0x00}, //G
{0x00,0x66,0x66,0x7e,0x66,0x66,0x66,0x00}, //H
{0x00,0x3c,0x18,0x18,0x18,0x18,0x3c,0x00}, //I
{0x00,0x0e,0x06,0x06,0x06,0x66,0x3c,0x00}, //J
{0x00,0x66,0x6c,0x78,0x78,0x6c,0x66,0x00}, //K
{0x00,0x60,0x60,0x60,0x60,0x60,0x7e,0x00}, //L
{0x00,0x62,0x76,0x7e,0x6a,0x62,0x62,0x00}, //M
{0x00,0x62,0x72,0x7a,0x6e,0x66,0x62,0x00}, //N
{0x00,0x3c,0x66,0x66,0x66,0x66,0x3c,0x00}, //O
{0x00,0x7c,0x66,0x66,0x7c,0x60,0x60,0x00}, //P
{0x00,0x3c,0x66,0x66,0x6e,0x64,0x3a,0x00}, //Q
{0x00,0x7c,0x66,0x66,0x7c,0x66,0x66,0x00}, //R
{0x00,0x3c,0x60,0x3c,0x06,0x66,0x3c,0x00}, //S
{0x00,0x7e,0x18,0x18,0x18,0x18,0x18,0x00}, //T
{0x00,0x66,0x66,0x66,0x66,0x66,0x3c,0x00}, //U
{0x00,0x66,0x66,0x66,0x66,0x3c,0x18,0x00}, //V
{0x00,0x62,0x62,0x6a,0x7e,0x76,0x62,0x00}, //W
{0x00,0x66,0x66,0x3c,0x3c,0x66,0x66,0x00}, //X
{0x00,0x66,0x66,0x66,0x3c,0x18,0x18,0x00}, //Y
{0x00,0x7e,0x0e,0x1c,0x38,0x70,0x7e,0x00}, //Z
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :
{0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x00}, // !
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} //空白
};
//// 轉為pixel
int findMsg(char c){
for(int i = 0; i < symbolNum; i++){
if(c == symbol[i]){
return i;
}
}
return symbolNum;
}
//// bit reversal
// 將資料位元翻轉成所需的順位(高位-低位? 低位- 高位?)
byte reverse(byte b){
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return(b);
};
//// MAX7219暫存器位址(16進制)
// 資料暫存器位址為 0x1~0x8
const byte NOOP = 0x0; // 不運作
const byte DECODEMODE = 0x9; // 解碼模式
const byte INTENSITY = 0xA; // 顯示強度
const byte SCANLIMIT = 0xB; // 掃描限制
const byte SHUTDOWN = 0xC; // 停機
const byte DISPLAYTEST = 0xF; // 顯示器檢測
//// 設定 MAX7219 暫存器資料的自訂函數
// MAX7219每次接收16位元的數據
// reg 為暫存器的位址 ; data 為要傳送的資料
void max7219(byte reg, byte data, int x = deviceNnm){
digitalWrite(CS, LOW); // 傳送或接收資料前CS腳位需設為0
for(int i = 1; i < x; i++){
SPI.transfer(NOOP);
SPI.transfer(0x00);
}
SPI.transfer(reg); // 傳送暫存器的位址
SPI.transfer(reverse(data)); // 傳送資料
for(int i = deviceNnm; i > x; i--){
SPI.transfer(NOOP);
SPI.transfer(0x00);
}
digitalWrite(CS, HIGH); // 傳送結束CS腳位需設為1
}
void light(char c, int x = deviceNnm){
int j = findMsg(c);
for(byte i = 0; i < 8; i++){
max7219(i + 1 , pixel[j][i], x);
}
}
char keyboard() {
byte scanVal; // 暫存掃描到的按鍵值
char k;
while(1){
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
digitalWrite(colPins[j], LOW);
scanVal = digitalRead(rowPins[i]);
if (scanVal == LOW) { // 如果輸入值是「低電位」…
//Serial.println(keymap[i][j]); // 輸出按鍵代表的字元
k = keymap[i][j];
delay(150); // 掃描按鍵的間隔時間
digitalWrite(colPins[j], HIGH);
return k;
}
digitalWrite(colPins[j], HIGH);
}
}
}
}
char mode = '0';
void setup() {
// 啟用鍵盤
Serial.begin(9600);
for (int i = 0; i < 4; i++) {
pinMode(rowPins[i], INPUT);
pinMode(colPins[i], OUTPUT);
pinMode(rowPins[i], INPUT_PULLUP); //啟用上拉電阻
digitalWrite(colPins[i], HIGH);
digitalWrite(rowPins[i], HIGH);
}
// 啟用LED矩陣
pinMode(CS, OUTPUT); // 設定CS腳位為輸出模式
digitalWrite(CS, HIGH); // CS腳位設為高電位表示尚不傳輸
SPI.begin(); // 啟動SPI連線
max7219(DECODEMODE, 0); // 解碼模式 // 設定為0表示不使用BCD解碼
max7219(INTENSITY, 8); // 顯示強度 // 設定亮度0~15
max7219(SCANLIMIT, 7); // 掃描限制 // 設定掃描顯示器的個數0~7,設定為7為顯示LED矩陣所有行數8行
max7219(SHUTDOWN, 1); // 停機 // 關閉停機模式,亦即開機
max7219(DISPLAYTEST, 0); // 顯示器檢測 // 關閉顯示器檢測
// 清除顯示畫面(LED矩陣中的8行都設為0)
for(byte i = 0; i < 8; i++){
max7219(i + 1 , 0);
}
// 顯示遊戲模式選擇
char msg[deviceNnm] = { '1', 'A', '2', 'B', 'G', 'A', 'M', 'E', '1', ':', 'A', 'T', '2', ':', 'D', 'E'};
for(int j = 0; j < deviceNnm; j++){
light(msg[j], j + 1);
}
while(mode == '0'){
char k = keyboard();
if(k =='1'){
mode = '1';
char msg1[deviceNnm] = { 'G', 'A', 'M', 'E', 'M', 'O', 'D', 'E', 'A', 'T', 'T', 'A', 'C', 'K', 'E', 'R'};
for(int j = 0; j < deviceNnm; j++){
light(msg1[j], j + 1);
}
}else if(k =='2'){
mode = '2';
char msg2[deviceNnm] = { 'G', 'A', 'M', 'E', 'M', 'O', 'D', 'E', 'D', 'E', 'F', 'E', 'N', 'D', 'E', 'R'};
for(int j = 0; j < deviceNnm; j++){
light(msg2[j], j + 1);
}
}else{
char msg3[deviceNnm] = { 'R', 'E', 'E', 'N', 'T', 'E', 'R', '!', '1', ':', 'A', 'T', '2', ':', 'D', 'E'};
for(int j = 0; j < deviceNnm; j++){
light(msg3[j], j + 1);
}
}
}
delay(500);
char msg4[deviceNnm] = { 'G', 'A', 'M', 'E', 'G', 'O', '!', '!', 'C', 'O', 'M', 'E', 'O', 'N', '!', '!'};
for(int j = 0; j < deviceNnm; j++){
light(msg4[j], j + 1);
}
delay(500);
}
void loop() {
char answer[4] = {0, 0, 0, 0};
while(mode == '1'){
int times = 0;
char count_a = '0';
char count_b = '0';
answer[0] = random('0', '9');
answer[1] = random('0', '9');
while(answer[1] == answer[0]){
answer[1] = random('0', '9');
}
answer[2] = random('0', '9');
while(answer[2] == answer[0] || answer[2] == answer[1]){
answer[2] = random('0', '9');
}
answer[3] = random('0', '9');
while(answer[3] == answer[0] || answer[3] == answer[1] || answer[3] == answer[2]){
answer[3] = random('0', '9');
}
for(int j = 8; j < deviceNnm; j++){
light(' ', j + 1);
}
// //// 輸出答案
// for(int i = 0; i < 4; i++){
// Serial.print(answer[i]);
// }
while(times < 10000 && count_a != '4'){
times++;
count_a = '0';
count_b = '0';
for(int j = 8; j < deviceNnm; j++){
light(' ', j + 1);
}
// 顯示目前猜測次數
int t = times;
int t1 = t/1000;
char t11 = t1 + 48 ;
t = t - t1 * 1000;
int t2 = t/100;
char t22 = t2 + 48 ;
t = t - t2 * 100;
int t3 = t/10;
char t33 = t3 + 48;
t = t - t3 * 10;
char t44 = t + 48;
light(t11, 5);
light(t22, 6);
light(t33, 7);
light(t44, 8);
//使用者輸入
char k[4] = {0, 0, 0, 0};
k[0] = keyboard();
while((k[0] < '0' || k[0] > '9')){
k[0] = keyboard();
}
light(k[0], 9);
k[1] = keyboard();
while((k[1] < '0' || k[1] > '9') || k[1] == k[0]){
k[1] = keyboard();
}
light(k[1], 10);
k[2] = keyboard();
while((k[2] < '0' || k[2] > '9') || k[2] == k[0] || k[2] == k[1]){
k[2] = keyboard();
}
light(k[2], 11);
k[3] = keyboard();
while((k[3] < '0' || k[3] > '9') || k[3] == k[0] || k[3] == k[1] || k[3] == k[2]){
k[3] = keyboard();
}
light(k[3], 12);
// 驗證
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if(k[i] == answer[j]){
if(i == j){
count_a++;
}else{
count_b++;
}
}
}
}
light(count_a, 13);
light('A', 14);
light(count_b, 15);
light('B', 16);
delay(3000);
}
mode = '0';
char msg5[deviceNnm] = { 'G', 'O', 'O', 'D', 'Y', 'O', 'U', ' ', 'W', 'I', 'N', ' ', answer[0], answer[1], answer[2], answer[3]};
for(int j = 0; j < deviceNnm; j++){
light(msg5[j], j + 1);
}
}
int guess = 0;
while(mode == '2'){
//char num[10000][4];
//char m[10000];
int times = 0;
char k[2] = {0, 0};
char check_A = '0';
char check_B = '0';
for(int i = 0; i < 10000; i++){
if(i < 10){
int temp = i;
num[i][0] = '0';
num[i][1] = '0';
num[i][2] = '0';
char tempD = temp + 48;
num[i][3] = tempD;
}else if(i < 100){
num[i][0] = '0';
num[i][1] = '0';
int temp = i;
int c = temp/10;
char tempC = c + 48;
num[i][2] = tempC;
temp = temp - 10 * c;
char tempD = temp + 48;
num[i][3] = tempD;
}else if(i < 1000){
num[i][0] = '0';
int temp = i;
int b = temp/100;
char tempB = b + 48;
num[i][1] = tempB;
temp = temp - 100 * b;
int c = temp/10;
char tempC = c + 48;
num[i][2] = tempC;
temp = temp - 10 * c;
char tempD = temp + 48;
num[i][3] = tempD;
}else{
int temp = i;
int a = temp/1000;
char tempA = a + 48;
num[i][0] = tempA;
temp = temp - 1000 * a;
int b = temp/100;
char tempB = b + 48;
num[i][1] = tempB;
temp = temp - 100 * b;
int c = temp/10;
char tempC = c + 48;
num[i][2] = tempC;
temp = temp - 10 * c;
char tempD = temp + 48;
num[i][3] = tempD;
}
m[i] = '0';
}
for(int i = 0; i < 10000; i++){
if(num[i][0] == num[i][1]){
m[i] = '1';
continue;
}
if(num[i][0] == num[i][2]){
m[i] = '1';
continue;
}
if(num[i][0] == num[i][3]){
m[i] = '1';
continue;
}
if(num[i][1] == num[i][2]){
m[i] = '1';
continue;
}
if(num[i][1] == num[i][3]){
m[i] = '1';
continue;
}
if(num[i][2] == num[i][3]){
m[i] = '1';
continue;
}
}
while(times < 10000 && k[0] != '4'){
times++;
for(int j = 8; j < deviceNnm; j++){
light(' ', j + 1);
}
// 顯示目前猜測次數
int t = times;
int t1 = t/1000;
char t11 = t1 + 48 ;
t = t - t1 * 1000;
int t2 = t/100;
char t22 = t2 + 48 ;
t = t - t2 * 100;
int t3 = t/10;
char t33 = t3 + 48;
t = t - t3 * 10;
char t44 = t + 48;
light(t11, 5);
light(t22, 6);
light(t33, 7);
light(t44, 8);
while( m[guess] == '1' && guess < 10000){
guess++;
}
light(num[guess][0], 9);
light(num[guess][1], 10);
light(num[guess][2], 11);
light(num[guess][3], 12);
//使用者輸入
k[0] = keyboard();
while((k[0] < '0' || k[0] > '4')){
k[0] = keyboard();
}
light(k[0], 13);
light('A', 14);
k[1] = keyboard();
while((k[1] < '0' || k[1] > '4') || ( (k[1] - '0') + (k[0] - '0') > 4)){
k[1] = keyboard();
}
light(k[1], 15);
light('B', 16);
int Check = guess;
while(Check < 10000){
if(m[Check] == '0'){
for(int i = 0; i < 4; i++){
for(int j = 0; j < 4; j++){
if(num[guess][i] == num[Check][j]){
if(i == j ){
check_A = check_A + 1;
}else{
check_B = check_B + 1;
}
}
}
}
if(check_A != k[0] || check_B != k[1]){
m[Check] = '1';
}
}
Check = Check + 1;
check_A = '0';
check_B = '0';
}
}
mode = '0';
char msg5[deviceNnm] = { 'H', 'A', 'H', 'A', 'Y', 'O', 'U', 'R', 'N', 'U', 'M', ' ', num[guess][0], num[guess][1], num[guess][2], num[guess][3]};
for(int j = 0; j < deviceNnm; j++){
light(msg5[j], j + 1);
}
}
//Serial.println("遊戲結束");
//delay(120000);
}