logo
HCS12 с применением языка С - royallib

7.7.6. Программный код

//Имя файла: sliding.с

//Программа: Игра в "15"

//Авторы: Scott Lewis, Daniel Pack,

//Дата создания: Начата 27 апреля 2004

//окончена 7 Мая 2004

// Описание: Эта программа реализует игру в "15". Цель игры

// заключается в том, чтобы выстроить фишки по по ряду номеров. Вы

// можете только перемещать на пустое место любую соседнюю фишку.

// Программа постоянно находится в памяти системы по адресу

// $2000. Программа отображает исходное состояние фишек, затем

// показывает состояние к которому необходимо прийти в

// результате. Программа размещает все фишки в случайном

// порядке, и затем позволяет пользователю начать игру

// Конфигурация системы

// Программа: 0x2000

// Данные: 0x3500

// Стек: 0x4000

//

// PDLC0: /WR    PP0 Data 0 PS0: Не используется

// PDLC1: /RD    PP1 Data 1 PS1: Не используется

// PDLC2: /CE    PP2 Data 2 PS2: Кнопка "Влево"

// PDLC3: C/D    PP3 Data 3 PS3: Кнопка "Выбор"

// PDLC4: /Reset PP4 Data 4 PS4: Кнопка "Вниз"

// PDLC5: NC     PP5 Data 5 PS5: Кнопка "Вправо"

// PDLC6: NC     PP6 Data 6 PS6: Кнопка "Вверх"

// PDLC1: NC     PP7 Data 7 PS7: Не используется

//

// Выводы ЖКД

// GND  -  2  1 - GND

// -14V -  3  4 - +5V

// /WR  -  5  6 - /RD

// /CE  -  7  8 - C/D

// NC   -  9 10 - /Reset

// DO   - 11 12 - D1

// D2   - 13 14 - D3

// D4   - 15 16 - D5

// D6   - 17 18 - D7

// GND  - 19 20 - NC

//******************************************************

#include <912b32.h> // описание портов - header file

                    // приведен в приложении

//********************************************************************

// Постоянные

//********************************************************************

#define ARRAY_MAX 15

#define ZERO 0x00

#define L_BUTTON 0x04 // сигналы кнопок

#define R_BUTTON 0x20

#define U_BUTTON 0x40

#define D_BUTTON 0x10

#define S BUTTON 0x08

#define LEFT   1 // выбор направления

#define RIGHT  2

#define UP     3

#define DOWN   4

#define SELECT 5

#define SIZE   4 // Размер строки/колонки

//********************************************************************

// Используемые функции

//********************************************************************

int check_win(int array[ARRAY_MAX+1]);

void convert_multi_single(int A[SIZE][SIZE], int В[SIZE][SIZE]);

void convert_single_multi(int A[ARRAY_MAX+1], int В[SIZE][SIZE]);

void display_board(int A[SIZE][SIZE], int row, int col, int direction);

void display_board2(int board_array[ARRAY_MAX+1]);

void display_error(int n);

void display_intro(void);

void display_win(void);

void get_move(int *direction, int *row, int *col, int *select);

void randomize_board(int board_array[]);

void swap(int row, int col, int new_row, int new_col, int array[SIZE][SIZE]);

void swap2(int from, int to, int array[ARRAY_MAX+1]);

void try_move(int move, int row, int col, int array[SIZE][SIZE]);

unsigned char mode(unsigned char num, int modulus);

void LCD_output(char s[]);

void int2char(int i);

void pause(void);

void delay(int usec);

void enable(void);

void initialize_LCD(void);

void command(unsigned char n);

void data(unsigned char n);

void write(void);

void read(void);

void status_wait(void);

void LCD_char(unsigned char n);

void Clearscreen(void);

void newline(void);

void Reset_cursor(void);

//*****************************************************************

//Переменные

//*****************************************************************

#pragma abs_address 0x3600

static int win_array[ARRAY_MAX+1]

 = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};

#pragma end_abs_address

#pragma abs_address 0x3500

int board_array_single [ARRAY_MAX+1];

int board_array_multi[SIZE][SIZE];

int win; //использовать как булевы переменные

int direction; //направление движения

int row; //выделить ряд

int col; //выделить колонку

int select; //если кнопка нажата

int i; //текущая переменная

#pragma end_abs_address

//*****************************************************************

// Основная программа

//*****************************************************************

void main() {

 win = 0; //инициализировать все переменные

 direction = 0;

 row = 1;

 col = 1;

 select = 0;

 i = 0;

 DDRDLC = 0x1F; //конфигурировать порт DDRDLC как выходной

 DDRP = 0xFF; // конфигурировать линии порта P как выходные

 DDRS = 0x00; // конфигурировать линии порта S как входные

 TSCR = 0x80; //включить таймер

 initialize_LCD(); //инициализировать ЖКД

 Clearscreen();

 Reset_cursor();

 display_intro();

 for (i=0; i < ARRAY_MAX+1; i++) board_array_single[i] = win_array[i];

 convert_single_multi(board_array_single, board_array_multi);

 display_board(board_array_multi, row, col, direction);

 pause(); // ожидание, пока пользователь не нажмет кнопку X

 LCD_output("Now the board is"); // вывод сообщения

 LCD_output("randomized. You ");

 LCD_output("may begin by ");

 LCD_output("choosing a piece");

 LCD_output("to move, and its");

 LCD_output("direction. ");

 newline();

 pause();

 randomize_board(board_array_single); // Случайный выбор исходного

                                      // положения фишек

 convert_single_multi(board_array_single, board_array_multi);

 display_board(board_array_multi, row, col, direction);

 while(win == 0){ //цикл повторяется до успешного окончания игры

  while (select == 0) {

   //если была нажата кнопка x, то задается направ-

   // ление движения ряд и колонка выделенной фишки

   get_move(&direction, &row, &col, &select);

   Reset_cursor(); // установить курсор в верхнее положение

   if (select == 0)

    display_board(board_array_multi, row, col, direction);

  }

  //проверить корректность движения, повторить его, если

  // оно некорректно, или вывести сообщение об ошибке

  try_move(direction, row-1, col-1, board_array_multi);

  select = 0;

  convert_multi_single(board_array_multi, board_array_single);

  win = check_win(board_array_single);

  Clearscreen();

  // показать текущее состояние игры

  display_board(board_array_multi, row, col, direction);

 }

 display_win(); // вывести сообщение об успешном окончании игры

}

//*****************************************************************

// display_intro: DISPLAY INTRO MESSAGE

//*****************************************************************

void display_intro {

 newline();

 LCD_output(" WELCOME ");

 LCD_output(" TO ");

 LCD_output(" SLIDING PUZZLE ");

 new_line();

 pause();

 LCD_output("The object of ");

 LCD_output("this game is to ");

 LCD_output("move each #'ed ");

 LCD_output("puzzle piece so ");

 LCD_output("that you end up ");

 LCD_output("in the order ");

 LCD_output("seen below. The ");

 LCD_output("star shows the ");

 LCD_output("current piece ");

 LCD_output("selected. You ");

 LCD_output("can choose a ");

 LCD_output("different piece ");

 LCD_output(" by using the ");

 LCD_output(" arrow buttons ");

 newline();

 pause();

 LCD_output("and select the ");

 LCD_output("piece you want ");

 LCD_output("to move by ");

 LCD_output("pressing the X ");

 // кнопка "Выбор"

 LCD_output("button. Choose ");

 LCD_output("the direction to ");

 LCD_output("move that piece ");

 LCD_output("with the arrows. ");

 new_line();

 LCD_output("WINDING ");

 LCD_output("CONFIGURATION: ");

 newline();

}

//*****************************************************************

// display_win: ВЫВОД СООБЩЕНИЯ О ПОБЕДЕ

//*****************************************************************

void display_win() {

 LCD_output(" YOU WIN!!! ");

 LCD_output("CONGRATULATIONS ");

}

//********************************************************************

// get_move: ДВИЖЕНИЕ ФИШКИ: задается позиция фишки, выбранной игро-

// ком и направление ее движения

//********************************************************************

void get_move(int* direction, int *row, int *col, int* select) {

 int n = 0;

 int button = 0;

 unsigned char temp = ZERO;

 newline();

 LCD_output("Choose move or ");

 LCD_output("select piece: ");

 while (button == 0) {

  // цикл выполняется, пока нажата кнопка

  temp = PORTS;

  temp = temp & 0x7С

  switch (temp) //какая кнопка нажата?

  {

  case L_BUTTON:

   button = LEFT;

   break;

  case R_BUTTON:

   button = RIGHT;

   break;

  case U_BUTTON:

   button = UP;

   break;

  case D_BUTTON:

   button = DOWN;

   break;

  case S_BUTTON:

   button = SELECT;

   break;

  } // конец цикла switch

 }//конец цикла while

 n = 0;

 switch (button) //реакция на нажатие кнопки

 {

 case UP:

  if (*row > 1) *row -= 1;

  else display_error(UP);

  break;

 case DOWN:

  if (*row < SIZE) *row += 1;

  else display_error(DOWN);

  break;

 case LEFT:

  if (*col > 1) *col -= 1;

  else display_error(LEFT);

  break;

 case RIGHT:

  if (*col < SIZE) *col += 1

  else display_error(RIGHT);

  break;

 case SELECT:

  *select = 1;

  LCD_output("Pick a direction");

  *direction = 0;

  while (*direction == 0) {

   temp = PORTS;

   temp = temp & 0x7C;

   switch (temp) {

   case L_BUTTON:

    *direction = LEFT;

    break;

   case R_BUTTON:

    *direction = RIGHT;

    break;

   case U_BUTTON:

    *direction = UP;

    break;

   case D_BUTTON:

    *direction = DOWN;

    break;

   }

  }

  break;

 }

}

//********************************************************************

// randomize_board: ВЫБОР СЛУЧАЙНОГО ИСХОДНОГО СОСТОЯНИЯ ФИШЕК

//********************************************************************

void randomize_board(int board_array[]) {

 int temp = 0;

 int i;

 unsigned char temp2 = 0x00;

 for (i=0; i<ARRAY_MAX+1; i++) {

  temp2 = TCNTL;

  temp = mod(temp2,15); //случайное значение using the TCNT counter

  swap2(i,temp, board_array);

 }

}

//********************************************************************

// MOD: МАТЕМАТИЧЕСКАЯ ФУНКЦИЯ

//********************************************************************

unsigned char mod(unsigned char num, int modulus) {

 while ((num - modulus) > 0) num = num - modulus;

 return num;

}

//********************************************************************

// display_board2: Выводит табло, как одну колонку значений

//********************************************************************

void display_board2(int board_array[ARRAY_MAX+1]) {

 int = 0;

 int n;

 for (i=0; i<ARRAY_MAX+1; i++) {

  n = board_array[i];

  int2char(n);

 }

 LCD_output("\n");

}

//********************************************************************

// display_board: Выводит табло как массив 4×4

//********************************************************************

void display_board(int A[SIZE][SIZE], int row, int col, int direction) {

#pragma abs_address 0x0800

 int i;

 int j;

 int num;

#pragma end_abs_address

 newline();

 LCD_output("| Column ");

 LCD_output("| 1 2 3 4 ");

 LCD_output("-------------------");

 for (i=0; i < SIZE; i++) {

  j=0;

  switch(i) {

  case 0:

   LCD_output("R 1 |");

   break;

  case 1:

   LCD_output("o 2 |");

   break;

  case 2:

   LCD_output("w 3 |");

   break;

  case 3:

   LCD_output(" 4 |");

   break;

  }

  for (j=0; j < SIZE; j++) {

   num = A[i][j];

   if (num == 0) LCD_output(" ");

   else int2char(num);

   if ((i+1 == row) && (j+1) == col))

    LCD_output("*");

   else LCD_output(" ");

  }

 }

 newline();

 LCD_output("You are at (R,C)");

 LCD_output(" (");

 int2char(row);

 LCD_output(",");

 int2char(col);

 LCD_output(") =");

 int2char(A[row-1];

 LCD_output(" ");

 newline();

}

//********************************************************************

// INT2CHAR: задается как integer и выводится на ЖКД в виде

// двух символов

//********************************************************************

void int2char(int i) {

 if (i > 9) {

  LCD_output("I");

  i -= 10;

 } else {

  LCD_output('; ");

 }

 switch(i) {

 case 0:

  LCD_output("0");

  break;

 case 1:

  LCD_output("1");

  break;

 case 2:

  LCD_output("2");

  break;

 case 3:

  LCD_output("3");

  break;

 case 4:

  LCD_output("4");

  break;

 case 5:

  LCD_output("5");

  break;

 case 6:

  LCD_output("6");

  break;

 case 7:

  LCD_output("7");

  break;

 case 8:

  LCD_output("8");

  break;

 case 9:

  LCD_output("9");

  break;

 }

}

//********************************************************************

//Check_Win: Эта функция проверяет соответствие текущего положения ситуации

// победы при победе win - 1, в остальных случаях - 0

//********************************************************************

int check_win(int array[ARRAY_MAX+1]) {

 int i;

 int win = 1;

 for (i=0; i<ARRAY_MAX+1; i++) {

  if (array[i] != win_array[i]) win = 0;

 }

 return win;

}

//********************************************************************

//Convert_multi_single: Эта функция преобразует двухмерный массив

//в одномерный

//********************************************************************

int convert_multi_single(int A[SIZE][SIZE], int В[ARRAY_MAX+1]) {

 int n = 0;

 int i = 0;

 int j = 0;

 for (i=0; i<SIZE; i++) {

  for (j=0; j<SIZE; j++) {

   B[n] = A[i][j] ;

   n++;

  }

 }

}

//****************************************************************

//Convert_single_multi: Эта функция преобразует одномерный массив

//в двухмерный

//****************************************************************

void convert_single_multitint A[ARRAY_MAX+1], int В[SIZE][SIZE]) {

 B[0][0] = A[0];

 B[0][1] = A[1];

 B[0][2] = A[2];

 B[0][3] = A[3];

 B[1][0] = A[4];

 B[1][1] = A[5];

 B[1][2] = A[6];

 B[1][3] = A[7];

 B[2][0] = A[8];

 B[2][1] = A[9];

 B[2][2] = A[10];

 B[2][3] = A[11];

 B[3][0] = A[13];

 B[3][2] = A[14];

 B[3][3] = A[15];

}

//********************************************************************

// Try_move: Эта функция позволяет игроку определить некорректность

// своего хода. Если он корректен, то движение выполняется,

// если же некорректен, то выводится соответствующее сообщение

//********************************************************************

void try_move(int move, int row, int col, int array[SIZE][SIZE]) {

 switch(move) {

 case UP:

  if ((row-1 >=0) && (array[row-1][col] == 0))

   swap(row, col, row-1, col, array);

  else display_error(UP);

  break;

 case DOWN:

  if ((row+1 <= SIZE) && (array[row+1][col] == 0))

   swap(row, col, row+1, col, array);

  else display_error(DOWN);

  break;

 case LEFT:

  if ((col-1 >=0) && (array[row][col-1] == 0))

   swap(row, col, row, col-1, array);

  else display_error(LEFT);

  break;

 case RIGHT:

  if ((col+1 < = SIZE) && (array[row][col+1] == 0))

   swap(row, col, row, col+1, array);

  else display_error(RIGHT);

  break;

 }

}

//********************************************************************

//********************************************************************

//Swap: Эта функция заменяет два значения двухмерным массивом.

//********************************************************************

void swap(int row, int col, int new_row, int new_col, int array[SIZE][SIZE]) {

 int temp;

 temp = array[row][col];

 array[row][col] = array[new_row][new_col];

 array[new_row][new_col] = temp;

}

//********************************************************************

//Swap2: Эта функция заменяет два значения одномерным массивом.

//********************************************************************

void swap2(int from, int to, int array[ARRAY_MAX+1]) {

 int temp = array[from];

 array[from] = array[to];

 array[to] - temp;

}

//********************************************************************

//ERROR: Эта функция выводит сообщения об ошибке

//********************************************************************

void display_error(int n) {

 LCD_Output("ERROR: ");

 switch(n) {

 case LEFT:

  LCD_output("no move L");

  break;

 case RIGHT:

  LCD_output("no move R");

  break;

 case UP:

  LCD_output("no move U");

  break;

 case DOWN:

  LCD_output("no move D");

  break;

 }

 pause();

}

//********************************************************************

//********************************************************************

//LCD_output: Эта функция выводит на дисплей строку

//********************************************************************

void LCD_output(char s[]) {

 int n = 0;

 while (s[n] != '\0') {

  LCD_char(s[n]);

  ++n;

 }

}

//********************************************************************

//Pause: Функция реализует ожидание, пока игрок не нажмет кнопку

// "Выбор"

//********************************************************************

void pause() {

 unsigned char с = ZERO;

 LCD_output("(Please press X)");

 while (c != S_BUTTON) {

  c = PORTS;

  с = c & 0x7C;

 }

 Clearscreen();

 Reset_cursor();

}

//********************************************************************

//Delay: Эта функция вводит задержку на n мкс, если входная

// величина равна n

//********************************************************************

void delay(int usec) {

 int i,j;

 for (i=0;i<usec; i++) {

  for (j=0; j < 7; j++) {}

 }

}

//********************************************************************

//Initialize_LCD: Функция инициализирует ЖКД

//********************************************************************

void initialize_LCD(void) {

 char temp = 0x00;

 PORTDLC = 0xFF;

 PORTDLC = PORTDLC & 0xEF; // сброс экрана (RESET = 0)

 delay(2000); // задержка в 2 мс

 PORTDLC = 0x7F; // выключение сброса

 write(); //включение записи

 command(0x80);

 //установка текстового режима

 data(0x0); //проверка установки слова

 data(0x10);

 command(0x40);

 data(0x10); // устанавливается размер области текста (1E)

 data(0x00); // - 0x1000

 command(0x41);

 //включается дисплей текста, курсор, выключается мигание

 command(0x94);

 command(0xA7); //курсор 8×8 точек

}

//********************************************************************

//Enable: Функция разрешает работу ИС

//********************************************************************

void enable(void) {

 PORTDLC = PORTDLC | 0x04; // Установить 1 на линии enable

 PORTDLC = PORTDLC & 0xFB; // Установить 0 на линии enable

}

//********************************************************************

//Disable: Функция запрещает работу ИС

//********************************************************************

void disable(void) {

 PORTDLC = PORTDLC | 0x04;

}

//********************************************************************

//Command: Функция посылает команду отключения на ЖКД

//********************************************************************

void command(unsigned char n) {

 status_wait();

 PORTP = n;

 PORTDLC = 0xFF;

 PORTDLC = PORTDLC & 0xFE; // сброс записи

 enable(); // сброс флага CE

 delay(10); // задержка не менее 80 нс

 disable(); // включение флага CE

}

//********************************************************************

//Data: Функция пересылает данные на ЖКД

//********************************************************************

void data(unsigned char n) {

 status_wait();

 PORTP = n;

 PORTDLC = 0xFF;

 PORTDLC = PORTDLC & 0xF7; // перевести C/D на низкий уровень

 PORTDLC = PORTDLC & 0xFE; // перевести WR на низкий уровень

 PORTDLC = PORTDLC & 0xFB;

 delay(10);

 disable();

}

//********************************************************************

//Write: Функция конфигурирует порт P как выходной

//********************************************************************

void write() {

 DDRP = 0xFF;

}

//********************************************************************

//Read: Функция конфигурирует порт P как входной

//********************************************************************

void read() {

 DDRP = 0x00;

}

//********************************************************************

//Status_wait: Создает соответствующие задержки между командами ЖКД

//********************************************************************

void status_wait() {

 char temp = 0x00;

 DDRP = 0x00;

 PORTDLC = PORTDLC | 0x0F; // сбросить все

 PORTDLC = PORTDLC & 0xFD; // сброс флага RD

 enable();

 delay(10);

 while ((temp & 0x03) != 0x03) {

  temp = PORTP;

 }

 disable();

 DDRP = 0xFF;

}

//********************************************************************

//LCD_char: Функция выводит ASCII код на экран ЖКД

//********************************************************************

void LCD_char(unsigned char n) {

 data(n-0x20);

 command(0xC0);

}

//********************************************************************

//Clearscreen: Функция очищает экран ЖКД

//********************************************************************

void Clearscreen() {

 int i,j;

 Reset_cursor();

 for (i=0; i < 16; i++) for (j=0; j<16; j++) LCD_char(' ');

 Reset_cursor();

}

//********************************************************************

//Newline: Функция выводит пустую строку на экран ЖКД

//********************************************************************

void newline() {

 int i;

 for (i=0; i < 16; i++)

 LCD_char(' ');

}

//********************************************************************

//Reset_cursor: Функция возвращает курсор ЖКД в начальную позицию

//********************************************************************

void Reset_cursor() {

 data(0x00);

 data(0x10);

 command(0x24);

}

//********************************************************************