// ============================ // // Do not edit this part!!!! // // ============================ // // 0x300001 - CONFIG1H #pragma config OSC = HSPLL // Oscillator Selection bits (HS oscillator, // PLL enabled (Clock Frequency = 4 x FOSC1)) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit // (Fail-Safe Clock Monitor disabled) #pragma config IESO = OFF // Internal/External Oscillator Switchover bit // (Oscillator Switchover mode disabled) // 0x300002 - CONFIG2L #pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out // Reset disabled in hardware and software) // 0x300003 - CONFIG1H #pragma config WDT = OFF // Watchdog Timer Enable bit // (WDT disabled (control is placed on the SWDTEN bit)) // 0x300004 - CONFIG3L // 0x300005 - CONFIG3H #pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit // (Timer1 configured for higher power operation) #pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; // RE3 input pin disabled) // 0x300006 - CONFIG4L #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply // ICSP disabled) #pragma config XINST = OFF // Extended Instruction Set Enable bit // (Instruction set extension and Indexed // Addressing mode disabled (Legacy mode)) #pragma config DEBUG = OFF // Disable In-Circuit Debugger #define KHZ 1000UL #define MHZ (KHZ * KHZ) #define _XTAL_FREQ (40UL * MHZ) // ============================ // // End // // ============================ // #include #include #include #define T_PRELOAD_LOW 0x6A // BLINK 250MS #define T_PRELOAD_HIGH 0x67 // Add a structure for pieces struct piece { uint8_t x; uint8_t y; uint8_t empty_x; uint8_t empty_y; // Type of the piece: "dot", "l_piece", "square" char *type; }; // ============================ // // Global variables: // Hold the board as an array of 8x4: // C D E F // 0 0 0 0 // 0 0 0 0 // 0 0 0 0 // 0 0 0 0 // 0 0 0 0 // 0 0 0 0 // 0 0 0 0 // 0 0 0 0 uint8_t board[8][4]; // Type of last created piece: // 0: dot // 1: square // 2: l_piece uint8_t last_piece = 2; // Alive piece: struct piece *alive_piece = NULL; // Hold a flag to show alive piece or not: uint8_t is_alive = 0; // Hold a flag to determine whether game is over or not: uint8_t is_game_over = 0; // Hold a flag to determine if the alive piece is submitted or not: uint8_t is_submitted = 0; // Flags for buttons: uint8_t right_button = 0; uint8_t up_button = 0; uint8_t down_button = 0; uint8_t left_button = 0; // ============================ // // Initialize the board void init_board() { for (uint8_t i = 0; i < 8; i++) { for (uint8_t j = 0; j < 4; j++) { board[i][j] = 0; } } } // Submit a piece to board. void submit_piece(struct piece *piece) { // Before submitting the piece, check if the piece can be submitted. // If the piece cannot be submitted, return. if (piece->type == "dot") { if (board[piece->x][piece->y] == 1) { return; } } else if (piece->type == "l_piece") { if (piece->empty_x == piece->x && piece->empty_y == piece->y) { // Empty space is on the top-left. // OX // XX if (board[piece->x + 1][piece->y] == 1 || board[piece->x][piece->y + 1] == 1 || board[piece->x + 1][piece->y + 1] == 1) { return; } } else if (piece->empty_x < piece->x && piece->empty_y == piece->y) { // Empty space is on the top-right. // XO // XX if (board[piece->x][piece->y] == 1 || board[piece->x][piece->y + 1] == 1 || board[piece->x + 1][piece->y + 1] == 1) { return; } } else if (piece->x < piece->empty_x && piece->x < piece->empty_y) { // Empty space is on the bottom-right. // XX // XO if (board[piece->x][piece->y] == 1 || board[piece->x + 1][piece->y] == 1 || board[piece->x][piece->y + 1] == 1) { return; } } else if (piece->empty_x == piece->x + 1) { // Empty space is on the bottom-left. // XX // OX if (board[piece->x][piece->y] == 1 || board[piece->x + 1][piece->y] == 1 || board[piece->x + 1][piece->y + 1] == 1) { return; } } } else if (piece->type == "square") { if (board[piece->x][piece->y] == 1 || board[piece->x][piece->y + 1] == 1 || board[piece->x + 1][piece->y] == 1 || board[piece->x + 1][piece->y + 1] == 1) { return; } } // Set correct values to the board as 1: if (piece->type == "dot") { board[piece->x][piece->y] = 1; } else if (piece->type == "l_piece") { if (piece->empty_x == piece->x && piece->empty_y == piece->y) { // Empty space is on the top-left. // OX // XX board[piece->x + 1][piece->y] = 1; board[piece->x][piece->y + 1] = 1; board[piece->x + 1][piece->y + 1] = 1; } else if (piece->empty_x < piece->x && piece->empty_y == piece->y) { // Empty space is on the top-right. // XO // XX board[piece->x][piece->y] = 1; board[piece->x][piece->y + 1] = 1; board[piece->x + 1][piece->y + 1] = 1; } else if (piece->x < piece->empty_x && piece->x < piece->empty_y) { // Empty space is on the bottom-right. // XX // XO board[piece->x][piece->y] = 1; board[piece->x + 1][piece->y] = 1; board[piece->x][piece->y + 1] = 1; } else if (piece->empty_x == piece->x + 1) { // Empty space is on the bottom-left. // XX // OX board[piece->x][piece->y] = 1; board[piece->x + 1][piece->y] = 1; board[piece->x + 1][piece->y + 1] = 1; } } else if (piece->type == "square") { board[piece->x][piece->y] = 1; board[piece->x][piece->y + 1] = 1; board[piece->x + 1][piece->y] = 1; board[piece->x + 1][piece->y + 1] = 1; } } // Add a helper function to rotate the L-Piece void rotate_l_piece(struct piece *piece) { // Pieces always rotate clockwise. // Within given square space, determine the next position of empty space. // Depending on the current position of the piece, move the empty space to the next position. if (piece->empty_x == piece->x && piece->empty_y == piece->y) { // Empty space is on the top-left. // OX -> XO // XX -> XX piece->empty_x = piece->x + 1; } else if (piece->empty_x < piece->x && piece->empty_y == piece->y) { // Empty space is on the top-right. // XO -> XX // XX -> XO piece->empty_y = piece->y + 1; } else if (piece->empty_y == piece->y) { // Empty space is on the bottom-right. // XX -> XX // XO -> OX piece->empty_x = piece->x - 1; } else if (piece->empty_x == piece->x + 1) { // Empty space is on the bottom-left. // XX -> OX // OX -> XX piece->empty_y = piece->y - 1; } } // Add helper functions to move pieces. void move_piece_left(struct piece *piece) { if (piece->x == 0) { return; } piece->x--; piece->empty_x--; } void move_piece_right(struct piece *piece) { if (piece->x == 6) { return; } piece->x++; piece->empty_x++; } void move_piece_down(struct piece *piece) { if (piece->y == 6) { return; } piece->y++; piece->empty_y++; } void move_piece_up(struct piece *piece) { if (piece->y == 0) { return; } piece->y--; piece->empty_y--; } uint8_t prevB; void poll_porta() { } void Init() { // 2.2 INPUTS // Port A is set as input: // RA0: Right // RA1: Up // RA2: Down // RA3: Left LATA = 0x00; PORTA = 0x00; TRISA = 0x0F; // Port B is also set as input: // RB5: Rotate // RB6: Submit LATB = 0x00; PORTB = 0x00; TRISB = 0x60; // 2.3 OUTPUTS // C TO F FOR GAME AREA // C LATC = 0x00; PORTC = 0x00; TRISC = 0x00; // D LATD = 0x00; PORTD = 0x00; TRISD = 0x00; // E LATE = 0x00; PORTE = 0x00; TRISE = 0x00; // F LATF = 0x00; PORTF = 0x00; TRISF = 0x00; // H AND J ? S-10 // Initialize the 7-segment display ports TRISJ = 0x00; // Set PORTJ to output LATJ = 0x00; // Clear segments (assumes common cathode display) TRISH = 0x00; // Set PORTH to output LATH = 0x00; // Disable all 7-segment displays // Enable the first 7-segment display and set it to show '0' LATH = 0xFF; // Enable D0 (assuming PORTH3 controls D0) LATJ = 0x3F; // '0' on a common cathode 7-segment display } void initialize_timer_and_interrupts() { // Enable pre-scalar // Full pre-scale // we also need to do in-code scaling T0CON = 0x00; T0CONbits.TMR0ON = 1; T0CONbits.T0PS2 = 1; T0CONbits.T0PS1 = 0; T0CONbits.T0PS0 = 1; // Pre-load the value TMR0H = T_PRELOAD_HIGH; TMR0L = T_PRELOAD_LOW; RCONbits.IPEN = 0; INTCON = 0x00; INTCONbits.TMR0IE = 1; INTCONbits.RBIE = 1; INTCONbits.GIE = 1; INTCONbits.PEIE = 1; } // ============================ // // INTERRUPT SERVICE ROUTINE // // ============================ // __interrupt(high_priority) void handle_interrupt() { // Timer overflowed (333 ms) if (INTCONbits.TMR0IF) { INTCONbits.TMR0IF = 0; // Pre-load the value TMR0H = T_PRELOAD_HIGH; TMR0L = T_PRELOAD_LOW; // Fully lit LATD // Blinks LATD // LATD = ~PORTD; } if (INTCONbits.RBIF) { // Read the value to satisfy the interrupt prevB = PORTB; LATC = ~PORTC; // Then clear the bit INTCONbits.RBIF = 0; } } __interrupt(low_priority) void handle_interrupt_2() { } /* Depending on the value of last_piece, create a piece and assign it to alive_piece. */ void create_piece() { struct piece piece = {0, 0, 0, 0, ""}; switch (last_piece) { case 0: // Last piece was a dot. // Create a square and assign it to alive_piece: piece.x = 0; piece.y = 0; piece.type = "square"; last_piece = 1; break; case 1: // Last piece was a square. // Create an l-piece and assign it to alive_piece: piece.x = 0; piece.y = 0; piece.empty_x = 0; piece.empty_y = 1; piece.type = "l_piece"; last_piece = 2; break; case 2: // Last piece was an l-piece. // Create a dot and assign it to alive_piece: piece.x = 0; piece.y = 0; piece.type = "dot"; last_piece = 0; break; default: break; } alive_piece = &piece; } /* Whether port A RA0 is pressed or not. */ void right_button_task() { if (PORTA & 0x01) { right_button = 1; } else { if (right_button == 1) { move_piece_right(alive_piece); right_button = 0; } } } /* Whether port A RA1 is pressed or not. */ void up_button_task() { if (PORTA & 0x02) { up_button = 1; } else { if (up_button == 1) { rotate_l_piece(alive_piece); up_button = 0; } } } /* Whether port A RA2 is pressed or not. */ void down_button_task() { if (PORTA & 0x04) { down_button = 1; } else { if (down_button == 1) { move_piece_down(alive_piece); down_button = 0; } } } /* Whether port A RA3 is pressed or not. */ void left_button_task() { if (PORTA & 0x08) { left_button = 1; } else { if (left_button == 1) { move_piece_left(alive_piece); left_button = 0; } } } void render_submitted() { uint8_t c_lane = 0x00; uint8_t d_lane = 0x00; uint8_t e_lane = 0x00; uint8_t f_lane = 0x00; // For each lane, calculate decimal value of the port: for (uint8_t i = 0; i < 8; i++) { c_lane = c_lane + pow(2, i) * board[i][0]; d_lane = d_lane + pow(2, i) * board[i][1]; e_lane = e_lane + pow(2, i) * board[i][2]; f_lane = f_lane + pow(2, i) * board[i][3]; } // Assign the calculated values to the ports: LATC = c_lane; LATD = d_lane; LATE = e_lane; LATF = f_lane; } // ============================ // // MAIN // // ============================ // void main() { Init(); initialize_timer_and_interrupts(); prevB = PORTB; __delay_ms(100); // Main Loop while (!is_game_over) { create_piece(); submit_piece(alive_piece); while (!is_submitted) { left_button_task(); up_button_task(); down_button_task(); right_button_task(); render_submitted(); } is_submitted = 0; } }