diff --git a/n_queens/Makefile b/n_queens/Makefile new file mode 100644 index 0000000..ccc509c --- /dev/null +++ b/n_queens/Makefile @@ -0,0 +1,86 @@ +# **************************************************************************** # +# # +# ::: :::::::: # +# Makefile :+: :+: :+: # +# +:+ +:+ +:+ # +# By: ruiferna +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# Created: 2025/09/22 17:06:00 by ruiferna #+# #+# # +# Updated: 2025/09/22 17:07:38 by ruiferna ### ########.fr # +# # +# **************************************************************************** # + +# Program name +NAME = n_queens + +# Compiler and flags +CC = gcc +CFLAGS = -Wall -Wextra -Werror + +# Source files +SRCS = n_queens.c + +# Object files +OBJS = $(SRCS:.c=.o) + +# Header files +HEADERS = n_queens.h + +# Colors for output +GREEN = \033[0;32m +RED = \033[0;31m +RESET = \033[0m + +# Main rule +all: $(NAME) + +# Compile the program +$(NAME): $(OBJS) + @echo "$(GREEN)Compiling $(NAME)...$(RESET)" + @$(CC) $(CFLAGS) $(OBJS) -o $(NAME) + @echo "$(GREEN)✓ $(NAME) compiled successfully!$(RESET)" + +# Compile object files +%.o: %.c $(HEADERS) + @echo "Compiling $<..." + @$(CC) $(CFLAGS) -c $< -o $@ + +# Clean object files +clean: + @echo "$(RED)Cleaning object files...$(RESET)" + @rm -f $(OBJS) + @echo "$(RED)✓ Object files cleaned!$(RESET)" + +# Clean everything +fclean: clean + @echo "$(RED)Cleaning executable...$(RESET)" + @rm -f $(NAME) + @echo "$(RED)✓ Everything cleaned!$(RESET)" + +# Rebuild everything +re: fclean all + +# Test the program with different values +test: $(NAME) + @echo "$(GREEN)Testing n_queens program:$(RESET)" + @echo "\n$(GREEN)Testing with n=1:$(RESET)" + @./$(NAME) 1 + @echo "\n$(GREEN)Testing with n=2 (no solutions):$(RESET)" + @./$(NAME) 2 || echo "No solutions found" + @echo "\n$(GREEN)Testing with n=4:$(RESET)" + @./$(NAME) 4 + @echo "\n$(GREEN)Testing with n=8 (counting solutions):$(RESET)" + @echo "Number of solutions for n=8: $$(./$(NAME) 8 | wc -l)" + +# Display help +help: + @echo "$(GREEN)Available commands:$(RESET)" + @echo " make - Compile the program" + @echo " make clean - Remove object files" + @echo " make fclean - Remove all generated files" + @echo " make re - Rebuild everything" + @echo " make test - Run tests with different values" + @echo " make help - Show this help message" + +# Declare phony targets +.PHONY: all clean fclean re test help \ No newline at end of file diff --git a/n_queens/README.md b/n_queens/README.md new file mode 100644 index 0000000..2d5a27b --- /dev/null +++ b/n_queens/README.md @@ -0,0 +1,252 @@ +# N-Queens Problem - Simple Explanation 👑 + +## What is the N-Queens Problem? 🤔 + +Imagine you have a chessboard and some queens (the most powerful pieces in chess). The N-Queens problem is like a puzzle where you need to place N queens on an N×N chessboard so that **none of them can attack each other**. + +### What's a Queen in Chess? ♛ + +A queen is the strongest piece in chess. She can move: +- **Horizontally** (left and right) ←→ +- **Vertically** (up and down) ↕️ +- **Diagonally** (in any diagonal direction) ↗️↖️↙️↘️ + +She can move as many squares as she wants in these directions! + +## The Challenge 🎯 + +Let's say we want to solve the **4-Queens problem** (N=4): +- We have a 4×4 chessboard (16 squares total) +- We need to place 4 queens +- **NO queen can attack any other queen** + +### Example: What Does "Attack" Mean? + +If we put a queen at position (0,0) - that's the top-left corner - she can attack: + +``` +Q . . . ← Queen here attacks all positions marked with X +X . . . +X . . . +X . . . +``` + +``` +Q X X X ← Queen attacks horizontally +. . . . +. . . . +. . . . +``` + +``` +Q . . . ← Queen attacks diagonally +. X . . +. . X . +. . . X +``` + +So we can't put any other queen in any of those X positions! + +## How Our Program Works 🖥️ + +### Step 1: Understanding the Input +When you run our program like this: +```bash +./n_queens 4 +``` + +The number `4` means "solve the 4-Queens problem" (4×4 board with 4 queens). + +### Step 2: How We Represent the Solution + +Instead of drawing the whole board, we use a clever trick! Since we know: +- There must be exactly ONE queen in each row +- There must be exactly ONE queen in each column + +We can represent a solution as a list of numbers: +``` +1 3 0 2 +``` + +This means: +- **Row 0**: Queen is in column 1 +- **Row 1**: Queen is in column 3 +- **Row 2**: Queen is in column 0 +- **Row 3**: Queen is in column 2 + +### Step 3: Visualizing the Solution + +If we draw this on a 4×4 board: + +``` +. Q . . ← Row 0, Column 1 +. . . Q ← Row 1, Column 3 +Q . . . ← Row 2, Column 0 +. . Q . ← Row 3, Column 2 +``` + +Let's check: Can any queen attack another? +- Queen at (0,1): Can't attack any other queen ✅ +- Queen at (1,3): Can't attack any other queen ✅ +- Queen at (2,0): Can't attack any other queen ✅ +- Queen at (3,2): Can't attack any other queen ✅ + +Perfect! This is a valid solution! + +## How Our Code Works 🔧 + +### The Main Function (`main`) + +```c +int main(int argc, char **argv) +{ + int n; + int *queens; + + if (argc != 2) // Check if user gave us exactly one number + return (1); + n = atoi(argv[1]); // Convert the text "4" to number 4 + if (n <= 0) // Make sure the number is positive + return (1); + queens = (int *)malloc(sizeof(int) * n); // Create space to store queen positions + if (!queens) // Check if we got the memory + return (1); + solve_nqueens(queens, 0, n); // Start solving from row 0 + free(queens); // Clean up memory + return (0); +} +``` + +**What this does in simple terms:** +1. "Did the user give me a number?" +2. "Is it a good number (positive)?" +3. "Let me create space to remember where I put the queens" +4. "Now let me solve the puzzle!" +5. "Clean up when I'm done" + +### The Solver Function (`solve_nqueens`) + +This is the "brain" of our program. It uses a technique called **backtracking**: + +```c +void solve_nqueens(int *queens, int row, int n) +{ + int col; + + if (row == n) // Did I place all queens? + { + print_solution(queens, n); // Yes! Print this solution + return ; + } + col = 0; + while (col < n) // Try each column in this row + { + if (is_safe(queens, row, col, n)) // Can I put a queen here? + { + queens[row] = col; // Yes! Put the queen here + solve_nqueens(queens, row + 1, n); // Try the next row + } + col++; + } +} +``` + +**Think of it like this:** +1. "Am I done placing all queens?" → If yes, print the solution! +2. "If not, let me try putting a queen in each column of this row" +3. "For each column, ask: Is it safe to put a queen here?" +4. "If safe, put the queen there and try to solve the next row" + +### The Safety Check (`is_safe`) + +This function checks if a queen position is safe: + +```c +int is_safe(int *queens, int row, int col, int n) +{ + int i; + + i = 0; + while (i < row) // Check all previously placed queens + { + if (queens[i] == col) // Same column? + return (0); // Not safe! + if (queens[i] - i == col - row) // Same diagonal (\)? + return (0); // Not safe! + if (queens[i] + i == col + row) // Same diagonal (/)? + return (0); // Not safe! + i++; + } + return (1); // Safe to place queen here! +} +``` + +**The three checks:** + +1. **Same column**: `queens[i] == col` + - "Is there already a queen in this column?" + +2. **Diagonal 1**: `queens[i] - i == col - row` + - "Is there a queen on the same diagonal going from top-left to bottom-right?" + +3. **Diagonal 2**: `queens[i] + i == col + row` + - "Is there a queen on the same diagonal going from top-right to bottom-left?" + +## Example Run 🏃‍♂️ + +Let's trace through what happens when we run `./n_queens 4`: + +1. **Start with row 0**: Try putting a queen in each column + - Column 0: Check safety → Safe! Put queen at (0,0) + - Move to row 1 + +2. **Row 1**: Try each column + - Column 0: Not safe (same column as row 0) + - Column 1: Not safe (same column... wait, no queen there yet) + - Column 2: Check safety → Safe! Put queen at (1,2) + - Move to row 2 + +3. **Row 2**: Try each column + - Column 0: Not safe (diagonal conflict) + - Column 1: Not safe (diagonal conflict) + - Column 2: Not safe (same column as row 1) + - Column 3: Not safe (diagonal conflict) + - **No solution found!** Go back to row 1 + +4. **Back to row 1**: Try next column + - Column 3: Check safety → Safe! Put queen at (1,3) + - Move to row 2 + +5. Continue this process... + +Eventually, we find: `1 3 0 2` and `2 0 3 1` + +## Results for Different N Values 📊 + +- **N=1**: `0` (1 solution - just put the queen anywhere) +- **N=2**: No output (impossible to solve) +- **N=3**: No output (impossible to solve) +- **N=4**: `1 3 0 2` and `2 0 3 1` (2 solutions) +- **N=8**: 92 solutions! + +## Fun Facts! 🎉 + +1. **Why no solution for N=2 and N=3?** + - For N=2: You need 2 queens on a 2×2 board, but they'll always attack each other! + - For N=3: Same problem - not enough space! + +2. **The 8-Queens problem** (standard chessboard) has exactly **92 solutions**! + +3. **This is a classic computer science problem** that teaches us about: + - **Recursion** (functions calling themselves) + - **Backtracking** (trying something, and if it doesn't work, going back and trying something else) + - **Problem solving** (breaking a big problem into smaller pieces) + +## How to Use the Program 💻 + +1. **Compile**: `make` +2. **Run**: `./n_queens 4` +3. **Test different values**: `make test` +4. **Clean up**: `make clean` + +Try it with different numbers and see what happens! 🚀 \ No newline at end of file diff --git a/n_queens/n_queens.c b/n_queens/n_queens.c new file mode 100644 index 0000000..267c001 --- /dev/null +++ b/n_queens/n_queens.c @@ -0,0 +1,96 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* n_queens.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ruiferna +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/09/22 00:00:00 by student #+# #+# */ +/* Updated: 2025/09/22 17:05:44 by ruiferna ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "n_queens.h" + +void print_number(int n) +{ + char c; + + if (n >= 10) + print_number(n / 10); + c = '0' + (n % 10); + write(1, &c, 1); +} + +void print_solution(int *queens, int n) +{ + int i; + + i = 0; + while (i < n) + { + if (i > 0) + write(1, " ", 1); + print_number(queens[i]); + i++; + } + write(1, "\n", 1); +} + +int is_safe(int *queens, int row, int col, int n) +{ + int i; + + (void)n; + i = 0; + while (i < row) + { + if (queens[i] == col) + return (0); + if (queens[i] - i == col - row) + return (0); + if (queens[i] + i == col + row) + return (0); + i++; + } + return (1); +} + +void solve_nqueens(int *queens, int row, int n) +{ + int col; + + if (row == n) + { + print_solution(queens, n); + return ; + } + col = 0; + while (col < n) + { + if (is_safe(queens, row, col, n)) + { + queens[row] = col; + solve_nqueens(queens, row + 1, n); + } + col++; + } +} + +int main(int argc, char **argv) +{ + int n; + int *queens; + + if (argc != 2) + return (1); + n = atoi(argv[1]); + if (n <= 0) + return (1); + queens = (int *)malloc(sizeof(int) * n); + if (!queens) + return (1); + solve_nqueens(queens, 0, n); + free(queens); + return (0); +} \ No newline at end of file diff --git a/n_queens/n_queens.h b/n_queens/n_queens.h new file mode 100644 index 0000000..f00bd1d --- /dev/null +++ b/n_queens/n_queens.h @@ -0,0 +1,25 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* n_queens.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ruiferna +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/09/22 00:00:00 by student #+# #+# */ +/* Updated: 2025/09/22 17:05:44 by ruiferna ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef N_QUEENS_H +# define N_QUEENS_H + +# include +# include +# include + +int is_safe(int *queens, int row, int col, int n); +void solve_nqueens(int *queens, int row, int n); +void print_solution(int *queens, int n); +void print_number(int n); + +#endif \ No newline at end of file diff --git a/n_queens/subject.txt b/n_queens/subject.txt new file mode 100644 index 0000000..9957439 --- /dev/null +++ b/n_queens/subject.txt @@ -0,0 +1,28 @@ +Assignement name : n_queens + +Expected files : *.c *.h + +Allowed functions : atoi, fprintf, write, calloc, malloc, free, realloc, stdout, stderr + +------------------------------------------------------------------------- + +Write a program that will print all the solutions to the n queens problem +for a n given as argument. +We will not test with negative values. +The order of the solutions is not important. + +You will display the solutions under the following format : + ... \n +where pn are the line index of the queen in each colum starting from 0. + +For example this should work : +$> ./n_queens 2 | cat -e + +$> ./n_queens 4 | cat -e +1 3 0 2$ +2 0 3 1$ + +$> ./n_queens 7 | cat -e +0 2 4 6 1 3 5$ +0 3 6 2 5 1 4$ +etc... \ No newline at end of file