- // ============================ //
- // 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 <xc.h>
- #include <stdint.h>
- #include <math.h>
- #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;
- }
- }