38 Commits

Author SHA1 Message Date
da7e 2828e37853 maze is display once 2026-03-26 18:22:45 +01:00
da7e e33d0a8e29 ADD(main): expected output in file test.txt 2026-03-25 17:48:18 +01:00
da7e a408004bd7 fix(parsing): make output work for AMazeIng class __init__
Basic main to display ascii print
2026-03-25 17:40:13 +01:00
da7e e717bf52e9 fix 42 logo adapt with size 2026-03-25 15:50:08 +01:00
da7e 3fa0d3204e add ft logo to maze 2026-03-25 15:27:39 +01:00
da7e cc6f2eb147 Merge branch 'fix_aster' 2026-03-25 14:52:10 +01:00
da7e c6242eeec0 fix astar algorithm work 2026-03-25 14:51:12 +01:00
Maoake Teriierooiterai 4055a8a7a2 finish to print the 42 2026-03-25 13:58:35 +01:00
Maoake TERIIEROOITERAI a39f348b1e set up the function draw ft 2026-03-24 22:11:54 +01:00
Maoake TERIIEROOITERAI 03c4d206d6 starting the branch parsing need to get a good start on this 2026-03-24 21:21:46 +01:00
Maoake TERIIEROOITERAI 8eb46f601f fixing the DFS and modify the main 2026-03-24 20:47:13 +01:00
da7e 991cdead51 Merge branch 'main' of github.com:maoakeEnterprise/amazing 2026-03-24 16:12:19 +01:00
da7e 6730ebcdb5 It's aliiiive! 2026-03-24 16:10:57 +01:00
Maoake Teriierooiterai c478400640 fix the cell pydantic cause the program was too long 2026-03-24 15:34:43 +01:00
da7e a79d4e5c3b algorithm edited but nothing better 2026-03-24 15:33:50 +01:00
Maoake Teriierooiterai 993bcce857 add generator to my maze generator DFS 2026-03-24 15:22:20 +01:00
Maoake Teriierooiterai a85e342a0a fix conflict 2026-03-24 14:31:49 +01:00
Maoake Teriierooiterai 4d151664ab finish the generator DFS 2026-03-24 14:28:10 +01:00
da7e 8dc00e238a Merge branch 'main' of github.com:maoakeEnterprise/amazing 2026-03-24 13:37:30 +01:00
da7e 0f19d24736 base but not working astar solver 2026-03-24 13:30:32 +01:00
Maoake Teriierooiterai 8b4ef7afce finish the maze generator 2026-03-24 11:10:16 +01:00
Maoake Teriierooiterai 030c6142ba need to fix my infinite while so i make a checkpoint if i need to restore it 2026-03-24 09:34:53 +01:00
Maoake Teriierooiterai f8f0e31598 fix some bug with my unit testing on the DFS 2026-03-23 19:24:32 +01:00
Maoake Teriierooiterai e75e14110d adding my maze need to be tested 2026-03-23 18:49:13 +01:00
Maoake Teriierooiterai 22c44333c1 Merge branch 'main' into parsing 2026-03-19 18:21:30 +01:00
Maoake Teriierooiterai b00ddc7d29 finish the unit testing on the parsing 2026-03-19 18:20:30 +01:00
Maoake Teriierooiterai e4e8ebfc13 adding the unit testing and modify some function for my unit testing its pretty good i learn how to get a good struct for my classes 2026-03-19 18:11:30 +01:00
da7e 0c20d2d063 pytest test_MazeGenerator 2026-03-19 17:45:00 +01:00
da7e 96b39fbeea Maze tester 2026-03-19 17:30:18 +01:00
da7e 97b35fe3eb add Cell tester + FIX: west setter for Cell class 2026-03-19 16:42:45 +01:00
da7e ac13df160f Merge branch 'config_class' 2026-03-19 16:14:04 +01:00
da7e d2d477d1b5 config class added 2026-03-19 16:13:13 +01:00
Maoake Teriierooiterai 721a7d00b9 change the name folder test into tests 2026-03-19 16:07:03 +01:00
Maoake Teriierooiterai 6d849a8121 Merge branch 'main' into parsing 2026-03-19 16:02:58 +01:00
Maoake Teriierooiterai a4d55d5692 finish the parsing need to be test 2026-03-19 16:00:19 +01:00
da7e c6c7e6e47e Generator class rework 2026-03-19 14:59:18 +01:00
Maoake Teriierooiterai 6b90e5fce5 adding in the parsing class DataMaze the funciton transform_data 2026-03-16 15:37:49 +01:00
Maoake Teriierooiterai 2f5d200c0a training on pytest for the unitesting and doing the parsing with a init in a package need to validate this with my teammate 2026-03-16 15:19:11 +01:00
43 changed files with 2856 additions and 163 deletions
+1 -1
View File
@@ -98,7 +98,7 @@ ipython_config.py
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# uv.lock
uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+12 -1
View File
@@ -8,7 +8,7 @@ debug:
uv pdb python3 a_maze_ing.py config.txt
clean:
rm -rf __pycache__ .mypy_cache
rm -rf __pycache__ .mypy_cache .venv
lint:
uv run flake8 . --exclude=.venv
@@ -17,3 +17,14 @@ lint:
lint-strict:
uv run flake8 .
uv run mypy . --strict
run_test_parsing:
PYTHONPATH=src uv run pytest tests/test_parsing.py
run_test_dfs:
PYTHONPATH=src uv run pytest tests/test_Depth.py
run_test_maze_gen:
PYTHONPATH=src uv run pytest tests/test_MazeGenerator.py
run_test:
uv run pytest
+101 -13
View File
@@ -1,21 +1,109 @@
import os
from numpy import ma
from src.amaz_lib import MazeGenerator
from typing import Any, Callable
from src.AMazeIng import AMazeIng
from src.parsing import Parsing
from mlx.mlx import Mlx
import numpy as np
import math
from src.amaz_lib import Maze
class MazeMLX:
def __init__(self, height: int, width: int) -> None:
self.mlx = Mlx()
self.height = height
self.width = width
self.mlx_ptr = self.mlx.mlx_init()
self.win_ptr = self.mlx.mlx_new_window(
self.mlx_ptr, width, height, "amazing"
)
self.img_ptr = self.mlx.mlx_new_image(self.mlx_ptr, width, height)
self.buf, self.bpp, self.size_line, self.format = (
self.mlx.mlx_get_data_addr(self.img_ptr)
)
def __del__(self) -> None:
self.mlx.mlx_destroy_image(self.mlx_ptr, self.img_ptr)
self.mlx.mlx_destroy_window(self.mlx_ptr, self.win_ptr)
def put_pixel(self, x, y) -> None:
offset = y * self.size_line + x * (self.bpp // 8)
self.buf[offset + 0] = 0xFF
self.buf[offset + 1] = 0xFF
self.buf[offset + 2] = 0xFF
if self.bpp >= 32:
self.buf[offset + 3] = 0xFF
def clear_image(self) -> None:
self.buf[:] = b"\x00" * len(self.buf)
def put_line(self, start: tuple[int, int], end: tuple[int, int]) -> None:
sx, sy = start
ex, ey = end
if sy == ey:
for x in range(min(sx, ex), max(sx, ex) + 1):
self.put_pixel(x, sy)
if sx == ex:
for y in range(min(sy, ey), max(sy, ey) + 1):
self.put_pixel(sx, y)
def update_maze(self, maze: np.ndarray) -> None:
self.clear_image()
margin = math.trunc(
math.sqrt(self.width if self.width > self.height else self.height)
// 2
)
line_len = math.trunc(
(
(self.height - margin) // len(maze)
if self.height > self.width
else (self.width - margin) // len(maze[0])
)
)
for y in range(len(maze)):
for x in range(len(maze[0])):
x0 = x * line_len + margin
y0 = y * line_len + margin
x1 = x * line_len + line_len + margin
y1 = y * line_len + line_len + margin
if maze[y][x].get_north():
self.put_line((x0, y0), (x1, y0))
if maze[y][x].get_est():
self.put_line((x1, y0), (x1, y1))
if maze[y][x].get_south():
self.put_line((x0, y1), (x1, y1))
if maze[y][x].get_west():
self.put_line((x0, y0), (x0, y1))
self.mlx.mlx_put_image_to_window(
self.mlx_ptr, self.win_ptr, self.img_ptr, 0, 0
)
def close_loop(self, _: Any):
self.mlx.mlx_loop_exit(self.mlx_ptr)
def gen_maze(self, maze: np.ndarray) -> None:
self.mlx.mlx_loop_hook(self.mlx_ptr, self.update_maze, maze)
self.mlx.mlx_hook(self.win_ptr, 17, 0, self.close_loop, None)
self.mlx.mlx_loop(self.mlx_ptr)
def main() -> None:
# try:
maze = Maze(maze=None, start=(1, 1), end=(16, 15))
for alg in MazeGenerator.Kruskal.kruskal(20, 20):
maze.set_maze(alg)
os.system("clear")
maze.ascii_print()
maze.export_maze("test.txt")
# except Exception as err:
# print(err)
mlx = None
try:
mlx = MazeMLX(1000, 1000)
config = Parsing.DataMaze.get_data_maze("config.txt")
amazing = AMazeIng(**config)
for _ in amazing.generate():
os.system("clear")
amazing.maze.ascii_print()
mlx.gen_maze(amazing.maze.get_maze())
with open("test.txt", "w") as output:
output.write(amazing.__str__())
except Exception as err:
print(err)
if __name__ == "__main__":
+8
View File
@@ -0,0 +1,8 @@
WIDTH=30
HEIGHT=30
ENTRY=1,1
EXIT=29,29
OUTPUT_FILE=maze.txt
PERFECT=True
GENERATOR=Kruskal
SOLVER=AStar
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
# src/mlx/__init__.py
from .mlx import *
+136
View File
@@ -0,0 +1,136 @@
.TH MiniLibX 3 "September 19, 2002"
.SH NAME
MiniLibX - Simple Window Interface Library for students
.SH SYNOPSYS
#include <mlx.h>
.nf
.I void *
.fi
.B mlx_init
();
.nf
.I int
.fi
.B mlx_release
(void *mlx_ptr);
.SH DESCRIPTION
MiniLibX is an easy way to create graphical software,
without any X-Window/Wayland/Vulkan programming knowledge under Unix/Linux,
nor any AppKit programming knowledge under MacOS. It provides
simple window creation, a drawing tool, image and basic events
management.
.SH Unix/Linux: HISTORICAL X-WINDOW CONCEPT
X-Window is a network-oriented graphical system for Unix.
It is based on two main parts:
.br
On one side, your software wants to draw something on the screen and/or
get keyboard & mouse entries.
.br
On the other side, the X-Server manages the screen, keyboard and mouse
(It is often referred to as a "display").
.br
A network connection must be established between these two entities to send
drawing orders (from the software to the X-Server), and keyboard/mouse
events (from the X-Server to the software).
.br
Nowadays, most of the time, both run on the same computer.
.SH Unix/Linux: MODERN GRAPHICAL APPROACH
Modern computers come with a powerful GPU that is directly accessed by applications.
Along GPU libraries like Vulkan or OpenGL, the Wayland protocol ensure communication
with the compositor program that manages the various windows on screen and the user
input events.
For your own application:
.br
The Vulkan or OpenGL library allow you to directly draw any content into your window.
.br
The Wayland compositor handles the place of your window on screen and send you back
the keyboard and mouse inputs from the user.
.br
Unfortunately, this gain of graphical power through GPU access removes the networking aspects
that exist with X-Window. It is not possible for a program to access a remote GPU and show its
window on a remote display. But current software architectures are more likely based on a local
display application that gets data in JSON through a web API.
.SH MacOS: WINDOW SERVER AND GPU
Your software interacts directly with the Window server who handles the
cohabitation on the screen with other software and the event system,
and interacts with the GPU to handle all drawing commands.
.SH INCLUDE FILE
.B mlx.h
should be included for a correct use of the MiniLibX API.
It only contains function prototypes, no structure is needed.
.SH LIBRARY FUNCTIONS
.P
First of all, you need to initialize the connection
between your software and the graphic and user sub-systems.
Once this completed, you'll be able to use other MiniLibX
functions to send and receive the messages from
the display, like "I want to draw a yellow pixel in this window" or
"did the user hit a key?".
.P
The
.B mlx_init
function will create this connection. No parameters are needed, ant it will
return a
.I "void *"
identifier, used for further calls to the library routines. The
.B mlx_release
function can be used at the end of the program to disconnect from the graphic
system and release resources.
.P
All other MiniLibX functions are described in the following man pages:
.TP 20
.B mlx_new_window
: manage windows
.TP 20
.B mlx_pixel_put
: draw inside a window
.TP 20
.B mlx_new_image
: manipulate images
.TP 20
.B mlx_loop
: handle keyboard or mouse events
.TP 20
.B mlx_extra
: extra functions available in the MinilibX
.SH LINKING MiniLibX
To use MiniLibX functions, you may -or not- need to link
your software with several libraries, including the MiniLibX library itself.
On Unix/Linux, depending on the specific operating system, either just using
.B -lmlx
works, or you need to add
.B -lxcb -lxcb-keysyms -lvulkan -lz -lbsd
\&.
On MacOS, the dynamic Metal library will find on its own the missing components:
.B -lmlx
\&.
You may also need to specify the path to these libraries, using the
.B -L
flag.
.SH RETURN VALUES
If
.B mlx_init()
fails to set up the connection to the display, it will return NULL, otherwise
a non-null pointer is returned as a connection identifier.
.SH SEE ALSO
mlx_new_window(3), mlx_pixel_put(3), mlx_new_image(3), mlx_loop(3), mlx_extra(3)
.SH AUTHOR
Copyright ol@ - 2002-2025 - Olivier Crouzet
+209
View File
@@ -0,0 +1,209 @@
/*
** mlx.h for MinilibX in
**
** Made by Charlie Root
** Login <ol@42.fr>
**
** Started on Mon Jul 31 16:37:50 2000 Olivier Crouzet
** Last update Tue Jun 25 16:23:28 2025 Olivier Crouzet
*/
/*
** MinilibX - Please report bugs
*/
/* mlx_CLXV version 2.2 */
/*
**
** This library is a simple framework to help 42 students
** create simple graphical apps.
** It only provides the minimum functions, it's students' job
** to create the missing pieces for their own project :)
**
** Current XCB-Vulkan requirements for Linux:
** libxcb, libxcb-keysyms, libvulkan,
** libz, libbsd
** You also need glslc to re-compile shaders if needed.
** At 42, on current Ubuntu 22.04 dump in cluster, you need to get
** libxcb-keysyms source for the include file and compile the .a library.
**
** The MinilibX can load XPM and PNG images.
** Please note that both image loaders are incomplete, some
** image may not load. Also, image loaders only work for little endian hosts.
**
** Historically, the alpha byte did represent transparency
** instead of opacity. It's not the case anymore. MLX matches GPUs standards.
**
** MLX_CLXV API changes:
** - mlx_get_data_addr now provides the image format instead of the
endian, and returns an 'unsigned char' pointer.
** - 'unsigned int' replace 'int' in many calls.
** - mlx_get_color_value() is now deprecated.
** - adding mlx_loop_exit().
**
** With recent X11 implementation and default configuration, the Expose event is only
** received once at the program launch. This is often due to X server saving the
** content of the window.
** With Wayland, there is no such thing like Expose event, and the compositor saves
** the window's content.
**
*/
#ifndef MLX_H
#define MLX_H
/*
** mlx_init() is needed before everything else.
** mlx_init() returns 'void *0' in case of failure.
** mlx_release() returns 0 on success.
*/
void *mlx_init();
int mlx_release(void *mlx_ptr);
/*
** Window actions
*/
void *mlx_new_window(void *mlx_ptr, unsigned int width,
unsigned int height, const char *title);
int mlx_clear_window(void *mlx_ptr, void *win_ptr);
int mlx_pixel_put(void *mlx_ptr, void *win_ptr,
unsigned int x, unsigned int y, unsigned int color);
int mlx_destroy_window(void *mlx_ptr, void *win_ptr);
/*
** mlx_new_window() returns 'void *0' if failed.
** Other functions return 0 on success.
** Origin for x & y is top left corner of the window, y down is positive.
** x and y must fit into the size of the window, values are not controled
** Color byte order is B8G8R8A8, which could be 0xAARRGGBB or 0xBBGGRRAA
** depending on local endianess.
*/
/*
** Images
*/
void *mlx_new_image(void *mlx_ptr, unsigned int width, unsigned int height);
unsigned char *mlx_get_data_addr(void *img_ptr, unsigned int *bits_per_pixel,
unsigned int *size_line,
unsigned int *format);
int mlx_put_image_to_window(void *mlx_ptr, void *win_ptr, void *img_ptr,
int x, int y);
int mlx_destroy_image(void *mlx_ptr, void *img_ptr);
/*
** mlx_new_image() returns 'void *0' in case of failure.
** mlx_get_data_addr() returns a pointer to a height * size_line bytes buffer
** that holds the pixel values.
** Other functions return 0 on success.
** 'format' can be: 0 = B8G8R8A8; 1 = A8R8G8B8; (byte order).
** Carefully consider the format, it can be reversed in some cases, like a remote graphic server
*/
/*
** deprecated function - format of image allows conversion on student's side
** unsigned int mlx_get_color_value(void *mlx_ptr, int color);
**
*/
/*
** main loop & dealing with events
*/
typedef int (*mlx_mouse_callback)(unsigned int, unsigned int, unsigned int, void*);
typedef int (*mlx_key_callback)(unsigned int, void *);
typedef int (*mlx_expose_callback)(void *);
typedef int (*mlx_loop_callback)(void *);
typedef int (*mlx_hook_callback)(void *);
int mlx_loop(void *mlx_ptr);
int mlx_loop_exit(void *mlx_ptr);
int mlx_mouse_hook(void *win_ptr, mlx_mouse_callback funct_ptr, void *param);
int mlx_key_hook(void *win_ptr, mlx_key_callback funct_ptr, void *param);
int mlx_expose_hook(void *win_ptr, mlx_expose_callback funct_ptr, void *param);
int mlx_loop_hook(void *mlx_ptr, mlx_loop_callback funct_ptr, void *param);
/*
** Functions return 0 on success.
** Key event is triggered on KeyRelease, not KeyPressed.
** Mouse event is triggered on clic.
**
** hook functions are called as follow:
** expose_hook(void *param);
** key_hook(unsigned int keycode, void *param);
** mouse_hook(unsigned int button, unsigned int x, unsigned int y,
** void *param);
** loop_hook(void *param);
*/
/*
** Generic hook system for all events, and minilibX functions that
** can be hooked. Some macro and defines from X11/X.h are needed here.
** Warning: you may need to cast your function pointer for key and mouse events
** as there will be extra parameters.
*/
int mlx_hook(void *win_ptr, unsigned int x_event, unsigned int x_mask,
mlx_hook_callback funct_ptr, void *param);
/*
** Convenience functions
** mlx_string_put() display may vary in size between OS and between
** mlx implementations
** mlx_string_put() returns 0 on success.
** Other functions return an image (like mlx_new_image()) or 'void *0'.
**
*/
int mlx_string_put(void *mlx_ptr, void *win_ptr,
unsigned int x, unsigned int y,
unsigned int color, char *string);
void *mlx_xpm_to_image(void *mlx_ptr, const char **xpm_data,
unsigned int *width, unsigned int *height);
void *mlx_xpm_file_to_image(void *mlx_ptr, const char *filename,
unsigned int *width, unsigned int *height);
void *mlx_png_file_to_image(void *mlx_ptr, const char *filename,
unsigned int *width, unsigned int *height);
/*
** Convenience functions
** All functions return 0 on success.
*/
int mlx_mouse_hide(void *mlx_ptr);
int mlx_mouse_show(void *mlx_ptr);
int mlx_mouse_move(void *win_ptr, int x, int y);
int mlx_mouse_get_pos(void *win_ptr, int *x, int *y);
int mlx_do_key_autorepeatoff(void *mlx_ptr);
int mlx_do_key_autorepeaton(void *mlx_ptr);
int mlx_get_screen_size(void *mlx_ptr,
unsigned int *width, unsigned int *height);
/*
** Flush & Sync
*/
int mlx_do_sync(void *mlx_ptr);
#define MLX_SYNC_IMAGE_WRITABLE 1
#define MLX_SYNC_WIN_FLUSH 2
#define MLX_SYNC_WIN_COMPLETED 3
int mlx_sync(void *mlx_ptr, int cmd, void *param);
/*
** Functions return 0 on success.
** mlx_do_sync() will *flush* (not sync) all requests and wait for completion.
** Note: mlx_loop() always flush requests.
** mlx_sync() 'cmd' commands are:
** - 'image_writable' returns when image data can be written again.
** - 'win_flush' returns when all pending requests are sent to server.
** - 'win_completed' returns after flush and completion.
** 'param' is image pointer or window pointer, according to the command.
** mlx_do_sync() equals 'win_flush' for all windows.
**
*/
#endif /* MLX_H */
+121
View File
@@ -0,0 +1,121 @@
.TH MiniLibX 3 "September 19, 2002"
.SH NAME
MiniLibX - Extra functions
.SH SYNOPSYS
.nf
.I int
.fi
.B mlx_mouse_hide
(
.I void *mlx_ptr
);
.nf
.I int
.fi
.B mlx_mouse_show
(
.I void *mlx_ptr
);
.nf
.I int
.fi
.B mlx_mouse_move
(
.I void *mlx_ptr, int x, int y
);
.nf
.I int
.fi
.B mlx_mouse_get_pos
(
.I void *win_ptr, int *x, int *y
);
.nf
.I int
.fi
.B mlx_do_key_autorepeatoff
(
.I void *mlx_ptr
);
.nf
.I int
.fi
.B mlx_do_key_autorepeaton
(
.I void *mlx_ptr
);
.nf
.I int
.fi
.B mlx_get_screen_size
(
.I void *mlx_ptr, unsigned int *width, unsigned int *height
);
.nf
.I int
.fi
.B mlx_do_sync
(
.I void *mlx_ptr
);
.nf
.I int
.fi
.B mlx_sync
(
.I void *mlx_ptr, int cmd, void *param
);
.SH MOUSE EXTRA FUNCTIONS
It is possible to show / hide the mouse, and get its current position without user click or
force its position inside a window.
.SH KEYBOARD EXTRA FUNCTIONS
The auto-repeat mode of the keyboard can be controlled. By default, auto-repeat is on:
multiple "key pressed" events are generated every second until the key is released.
.SH SCREEN EXTRA FUNCTION
It is possible to retrieve the size of the current screen, even before the first
window is created.
.SH FLUSH AND SYNC FUNCTIONS
The
.B mlx_do_sync
function will flush the pending commands to the graphic subsystems, ensuring nothing
is cached on your software's side. On return, there is no guarantee that your
commands have been processed.
.br
With
.B mlx_sync
you have more detailed control over the synchronisation mechanisms. Three different commands
are available:
.br
#define MLX_SYNC_IMAGE_WRITABLE 1
.br
#define MLX_SYNC_WIN_FLUSH 2
.br
#define MLX_SYNC_WIN_COMPLETED 3
.br
The third parameter
.I param
can be either the image identifier (command #1) or the window identifier (commands #2 and #3).
.SH SEE ALSO
mlx(3), mlx_new_window(3), mlx_pixel_put(3), mlx_new_image(3), mlx_loop(3)
.SH AUTHOR
Copyright ol@ - 2002-2025 - Olivier Crouzet
+154
View File
@@ -0,0 +1,154 @@
.TH MiniLibX 3 "September 19, 2002"
.SH NAME
MiniLibX - Handle events
.SH SYNOPSYS
.nf
.I int
.fi
.B mlx_loop
(
.I void *mlx_ptr
);
.nf
.I int
.fi
.B mlx_key_hook
(
.I void *win_ptr, int (*funct_ptr)(), void *param
);
.nf
.I int
.fi
.B mlx_mouse_hook
(
.I void *win_ptr, int (*funct_ptr)(), void *param
);
.nf
.I int
.fi
.B mlx_expose_hook
(
.I void *win_ptr, int (*funct_ptr)(), void *param
);
.nf
.I int
.fi
.B mlx_loop_hook
(
.I void *mlx_ptr, int (*funct_ptr)(), void *param
);
.nf
.I int
.fi
.B mlx_loop_exit
(
.I void *mlx_ptr
);
.SH EVENTS
The graphical system is bi-directional. On one hand, the program sends orders to
the screen to display pixels, images, and so on. On the other hand,
it can get information from the keyboard and mouse associated to
the screen. To do so, the program receives "events" from the keyboard or the
mouse.
.SH DESCRIPTION
To receive events, you must use
.B mlx_loop
(). This function never returns, unless
.B mlx_loop_exit
is called. It is an
infinite loop that waits for an event, and then calls a user-defined
function associated with this event. A single parameter is needed,
the connection identifier
.I mlx_ptr
(see the
.B mlx manual).
You can assign different functions to the three following events:
.br
- A key is released
.br
- The mouse button is pressed
.br
- A part of the window should be re-drawn
(this is called an "expose" event, and it is your program's job to handle it in the
Unix/Linux X11 environment, but at the opposite it never happens on Unix/Linux Wayland-Vulkan nor on MacOS).
.br
Each window can define a different function for the same event.
The three functions
.B mlx_key_hook
(),
.B mlx_mouse_hook
() and
.B mlx_expose_hook
() work exactly the same way.
.I funct_ptr
is a pointer to the function you want to be called
when an event occurs. This assignment is specific to the window defined by the
.I win_ptr
identifier. The
.I param
address will be passed back to your function every time it is called, and should be
used to store the parameters it might need.
The syntax for the
.B mlx_loop_hook
() function is similar to the previous ones, but the given function will be
called when no event occurs, and is not bound to a specific window.
When it catches an event, the MiniLibX calls the corresponding function
with fixed parameters:
.nf
expose_hook(void *param);
key_hook(unsigned int keycode, void *param);
mouse_hook(unsigned int button, unsigned int x, unsigned int y, void *param);
loop_hook(void *param);
.fi
These function names are arbitrary. They here are used to distinguish
parameters according to the event. These functions are NOT part of the
MiniLibX.
.I param
is the address specified in the mlx_*_hook calls. This address is never
used nor modified by the MiniLibX. On key and mouse events, additional
information is passed:
.I keycode
tells you which key is pressed (just try to find out :) ),
(
.I x
,
.I y
) are the coordinates of the mouse click in the window, and
.I button
tells you which mouse button was pressed.
.SH GOING FURTHER WITH EVENTS
The MiniLibX provides a much generic access to other available events. The
.I mlx.h
include define
.B mlx_hook()
in the same manner mlx_*_hook functions work. The event and mask values
will be taken from the historical X11 include file "X.h". Some Wayland and MacOS events are mapped
to these values when it makes sense, and the mask may not be used in some configurations.
See source code of the MiniLibX to find out how it will
call your own function for a specific event.
.SH SEE ALSO
mlx(3), mlx_new_window(3), mlx_pixel_put(3), mlx_new_image(3), mlx_extra(3)
.SH AUTHOR
Copyright ol@ - 2002-2025 - Olivier Crouzet
+180
View File
@@ -0,0 +1,180 @@
.TH MiniLibX 3 "September 19, 2002"
.SH NAME
MiniLibX - Manipulating images
.SH SYNOPSYS
.nf
.I void *
.fi
.B mlx_new_image
(
.I void *mlx_ptr, unsigned int width, unsigned int height
);
.nf
.I unsigned char *
.fi
.B mlx_get_data_addr
(
.I void *img_ptr, unsigned int *bits_per_pixel, unsigned int *size_line, unsigned int *format
);
.nf
.I int
.fi
.B mlx_put_image_to_window
(
.I void *mlx_ptr, void *win_ptr, void *img_ptr, int x, int y
);
.nf
.I void *
.fi
.B mlx_xpm_to_image
(
.I void *mlx_ptr, const char **xpm_data, unsigned int *width, unsigned int *height
);
.nf
.I void *
.fi
.B mlx_xpm_file_to_image
(
.I void *mlx_ptr, const char *filename, unsigned int *width, unsigned int *height
);
.nf
.I void *
.fi
.B mlx_png_file_to_image
(
.I void *mlx_ptr, const char *filename, unsigned int *width, unsigned int *height
);
.nf
.I int
.fi
.B mlx_destroy_image
(
.I void *mlx_ptr, void *img_ptr
);
.SH DESCRIPTION
.B mlx_new_image
() creates a new image in memory. It returns a
.I void *
identifier needed to manipulate this image later. It only needs
the size of the image to be created, using the
.I width
and
.I height
parameters, and the
.I mlx_ptr
connection identifier (see the
.B mlx
manual).
The user can draw inside the image (see below), and
can dump the image inside a specified window at any time to
display it on the screen. This is done using
.B mlx_put_image_to_window
(). Three identifiers are needed here, for the connection to the
display, the window to use, and the image (respectively
.I mlx_ptr
,
.I win_ptr
and
.I img_ptr
). The (
.I x
,
.I y
) coordinates define where the image should be placed in the window.
.B mlx_get_data_addr
() returns information about the created image, allowing a user
to modify it later. The
.I img_ptr
parameter specifies the image to use. The three next parameters should
be the addresses of three different valid unsigned integers.
.I bits_per_pixel
will be filled with the number of bits needed to represent a pixel colour
(also called the depth of the image).
.I size_line
is the number of bytes used to store one line of the image in memory.
This information is needed to move from one line to another in the image.
.I format
tells you how each pixel colour in the image is structured. Currently only 2 values are defined:
.P
0 means format B8G8R8A8
.P
1 means format A8R8G8B8
.B mlx_get_data_addr
returns an
.I unsigned char *
address that represents the beginning of the memory area where the image
is stored. From this address, the first
.I bits_per_pixel
bits represent the colour of the first pixel in the first line of
the image. The second group of
.I bits_per_pixel
bits represent the second pixel of the first line, and so on.
Add
.I size_line
to the address to get the beginning of the second line. You can reach any
pixels of the image that way.
.B mlx_destroy_image
destroys the given image (
.I img_ptr
).
.SH STORING COLOURS INSIDE IMAGES
Depending on the graphic system, the number of bits used to store a pixel colour
used to be different from one hardware to another. Today, the way the user usually
represents a colour, in the ARGB mode, almost always matches the hardware capabilities
on modern computers.
Keep in mind that packing the 4-byte ARGB into an unsigned int depends on the local
computer's endian. Adjust your code accordingly.
.SH XPM AND PNG IMAGES
The
.B mlx_xpm_to_image
() ,
.B mlx_xpm_file_to_image
() and
.B mlx_png_file_to_image
() functions will create a new image the same way.
They will fill it using the specified
.I xpm_data
or
.I filename
, depending on which function is used.
Note that MiniLibX does not use the standard
Xpm and png libraries to deal with xpm and png images. You may not be able to
read all types of xpm and png images. It however handles transparency.
.SH RETURN VALUES
The four functions that create images,
.B mlx_new_image()
,
.B mlx_xpm_to_image()
,
.B mlx_xpm_file_to_image()
and
.B mlx_png_file_to_image()
, will return NULL if an error occurs. Otherwise they return a non-null pointer
as an image identifier.
.SH SEE ALSO
mlx(3), mlx_new_window(3), mlx_pixel_put(3), mlx_loop(3), mlx_extra(3)
.SH AUTHOR
Copyright ol@ - 2002-2025 - Olivier Crouzet
+79
View File
@@ -0,0 +1,79 @@
.TH MiniLibX 3 "September 19, 2002"
.SH NAME
MiniLibX - Managing windows
.SH SYNOPSYS
.nf
.I void *
.fi
.B mlx_new_window
(
.I void *mlx_ptr, unsigned int width, unsigned int height, const char *title
);
.nf
.I int
.fi
.B mlx_clear_window
(
.I void *mlx_ptr, void *win_ptr
);
.nf
.I int
.fi
.B mlx_destroy_window
(
.I void *mlx_ptr, void *win_ptr
);
.SH DESCRIPTION
The
.B mlx_new_window
() function creates a new window on the screen, using the
.I width
and
.I height
parameters to determine its size, and
.I title
as the text that should be displayed in the window's title bar.
The
.I mlx_ptr
parameter is the connection identifier returned by
.B mlx_init
() (see the
.B mlx
man page).
.B mlx_new_window
() returns a
.I void *
window identifier that can be used by other MiniLibX calls.
Note that the MiniLibX
can handle an arbitrary number of separate windows.
.B mlx_clear_window
() and
.B mlx_destroy_window
() respectively clear (in black) and destroy the given window. They both have
the same parameters:
.I mlx_ptr
is the screen connection identifier, and
.I win_ptr
is a window identifier.
.SH RETURN VALUES
If
.B mlx_new_window()
fails to create a new window (whatever the reason), it will return NULL,
otherwise a non-null pointer is returned as a window identifier.
.B mlx_clear_window
and
.B mlx_destroy_window
return nothing.
.SH SEE ALSO
mlx(3), mlx_pixel_put(3), mlx_new_image(3), mlx_loop(3), mlx_extra(3)
.SH AUTHOR
Copyright ol@ - 2002-2025 - Olivier Crouzet
+83
View File
@@ -0,0 +1,83 @@
.TH MiniLibX 3 "September 19, 2002"
.SH NAME
MiniLibX - Drawing inside windows
.SH SYNOPSYS
.nf
.I int
.fi
.B mlx_pixel_put
(
.I void *mlx_ptr, void *win_ptr, unsigned int x, unsigned int y, unsigned int color
);
.nf
.I int
.fi
.B mlx_string_put
(
.I void *mlx_ptr, void *win_ptr, unsigned int x, unsigned int y, unsigned int color, char *string
);
.SH DESCRIPTION
The
.B mlx_pixel_put
() function draws a defined pixel in the window
.I win_ptr
using the (
.I x
,
.I y
) coordinates, and the specified
.I color
\&. The origin (0,0) is the upper left corner of the window, the x and y axis
respectively pointing right and down. The connection
identifier,
.I mlx_ptr
, is needed (see the
.B mlx
man page).
Parameters for
.B mlx_string_put
() have the same meaning. Instead of a simple pixel, the specified
.I string
will be displayed at (
.I x
,
.I y
).
Both functions will discard any display outside the window. This makes
.B mlx_pixel_put
slow. Consider using images instead.
.SH COLOUR MANAGEMENT
The
.I color
parameter has an unsigned integer type. The displayed colour needs to be encoded
in this integer, following a defined scheme. All displayable colours
can be split in 3 basic colours: red, green and blue. Three associated
values, in the 0-255 range, represent how much of each colour is mixed up
to create the original colour. The fourth byte represent transparency,
where 0 is fully transparent and 255 opaque. Theses four values must be set inside the
unsigned integer to display the right colour. The bytes of
this integer are filled as shown in the picture below:
.nf
| B | G | R | A | colour integer
+---+---+---+---+
.fi
While filling the integer, make sure you avoid endian problems. Example:
the "blue" byte will be the least significant byte inside the integer on a
little endian machine.
.SH SEE ALSO
mlx(3), mlx_new_window(3), mlx_new_image(3), mlx_loop(3), mlx_extra(3)
.SH AUTHOR
Copyright ol@ - 2002-2025 - Olivier Crouzet
+268
View File
@@ -0,0 +1,268 @@
# MLX python wrapper for Mlx C library
# See mlx manuals and mlx.h from C library for function usage
# C Functions that require addresses to pass back info are converted to
# Pythod methods that return a tuple
from ctypes import *
import os
class Mlx:
def __init__(self):
module_dir = os.path.dirname(os.path.abspath(__file__))
self.so_file = os.path.join(module_dir, "libmlx.so")
self.mlx_func = CDLL(self.so_file)
self._python_ref_std = {}
self._python_ref_gen = {}
self._img_height = {}
# Initialisation
def mlx_init(self):
self.mlx_func.mlx_init.restype = c_void_p
return self.mlx_func.mlx_init()
def mlx_release(self, mlx_ptr):
self.mlx_func.mlx_release.argtypes = [c_void_p]
self.mlx_func.mlx_release.restypes = [c_int]
return self.mlx_func.mlx_release(mlx_ptr)
# Windows
def mlx_new_window(self, mlx_ptr, width, height, title):
self.mlx_func.mlx_new_window.argtypes = [c_void_p, c_uint, c_uint, c_char_p]
self.mlx_func.mlx_new_window.restype = c_void_p
return self.mlx_func.mlx_new_window(mlx_ptr, width, height, title.encode('utf-8'))
def mlx_clear_window(self, mlx_ptr, win_ptr):
self.mlx_func.mlx_clear_window.argtypes = [c_void_p, c_void_p]
self.mlx_func.mlx_clear_window.restype = c_int
return self.mlx_func.mlx_clear_window(mlx_ptr, win_ptr)
def mlx_pixel_put(self, mlx_ptr, win_ptr, x, y, color):
self.mlx_func.mlx_pixel_put.argtypes = [c_void_p, c_void_p, c_uint, c_uint, c_uint]
self.mlx_func.mlx_pixel_put.restype = c_int
return self.mlx_func.mlx_pixel_put(mlx_ptr, win_ptr, x, y, color)
def mlx_destroy_window(self, mlx_ptr, win_ptr):
self.mlx_func.mlx_destroy_window.argtypes = [c_void_p, c_void_p]
self.mlx_func.mlx_destroy_window.restype = c_int
return self.mlx_func.mlx_destroy_window(mlx_ptr, win_ptr)
# Images
def mlx_new_image(self, mlx_ptr, width, height):
self.mlx_func.mlx_new_image.argtypes = [c_void_p, c_uint, c_uint]
self.mlx_func.mlx_new_image.restype = c_void_p
ret = self.mlx_func.mlx_new_image(mlx_ptr, width, height)
if ret is not None:
self._img_height[str(ret)] = height
return ret
# API break, returns tuple
def mlx_get_data_addr(self, img_ptr):
bits_per_pixel = c_uint()
size_line = c_uint()
theformat = c_uint()
data = POINTER(c_char)
self.mlx_func.mlx_get_data_addr.argtypes = [c_void_p, POINTER(c_uint), POINTER(c_uint), POINTER(c_uint)]
self.mlx_func.mlx_get_data_addr.restype = POINTER(c_char)
data = self.mlx_func.mlx_get_data_addr(img_ptr, byref(bits_per_pixel), byref(size_line), byref(theformat))
data_array = c_char * (self._img_height[str(img_ptr)] * size_line.value)
data_view = data_array.from_address(addressof(data.contents))
return (memoryview(data_view).cast('B'), bits_per_pixel.value, size_line.value, theformat.value)
def mlx_put_image_to_window(self, mlx_ptr, win_ptr, img_ptr, x, y):
self.mlx_func.mlx_put_image_to_window.argtypes = [c_void_p, c_void_p, c_void_p, c_int, c_int]
self.mlx_func.mlx_put_image_to_window.restype = c_int
return self.mlx_func.mlx_put_image_to_window(mlx_ptr, win_ptr, img_ptr, x, y)
def mlx_destroy_image(self, mlx_ptr, img_ptr):
self._img_height.pop(str(img_ptr))
self.mlx_func.mlx_destroy_image.argtypes = [c_void_p, c_void_p]
self.mlx_func.mlx_destroy_image.restype = c_int
return self.mlx_func.mlx_destroy_image(mlx_ptr, img_ptr)
# Events & main loop
# Note: Python can't catch C^-C from keyboard during mlx_loop execution.
# Use C^-\ to kill your program.
def mlx_loop(self, mlx_ptr):
self.mlx_func.mlx_loop.argtypes = [c_void_p]
self.mlx_func.mlx_loop.restype = c_int
return self.mlx_func.mlx_loop(mlx_ptr)
def mlx_loop_exit(self, mlx_ptr):
self.mlx_func.mlx_loop_exit.argtypes = [c_void_p]
self.mlx_func.mlx_loop_exit.restype = c_int
return self.mlx_func.mlx_loop_exit(mlx_ptr)
def mlx_mouse_hook(self, win_ptr, callback, param):
self.mlx_func.mlx_mouse_hook.restype = c_int
if not callback:
self._python_ref_std[str(win_ptr)+"_mouse_f"] = None
self._python_ref_std[str(win_ptr)+"_mouse_p"] = None
self.mlx_func.mlx_mouse_hook.argtypes = [c_void_p, c_void_p, c_void_p]
return self.mlx_func.mlx_mouse_hook(win_ptr, None, None)
callback_type = CFUNCTYPE(None, c_uint, c_uint, c_uint, py_object)
self.mlx_func.mlx_mouse_hook.argtypes = [c_void_p, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_std[str(win_ptr)+"_mouse_f"] = callback_ref
self._python_ref_std[str(win_ptr)+"_mouse_p"] = param
return self.mlx_func.mlx_mouse_hook(win_ptr, callback_ref, param)
def mlx_key_hook(self, win_ptr, callback, param):
self.mlx_func.mlx_key_hook.restype = c_int
if not callback:
self._python_ref_std[str(win_ptr)+"_key_f"] = None
self._python_ref_std[str(win_ptr)+"_key_p"] = None
self.mlx_func.mlx_key_hook.argtypes = [c_void_p, c_void_p, c_void_p]
return self.mlx_func.mlx_key_hook(win_ptr, None, None)
callback_type = CFUNCTYPE(None, c_uint, py_object)
self.mlx_func.mlx_key_hook.argtypes = [c_void_p, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_std[str(win_ptr)+"_key_f"] = callback_ref
self._python_ref_std[str(win_ptr)+"_key_p"] = param
return self.mlx_func.mlx_key_hook(win_ptr, callback_ref, param)
def mlx_expose_hook(self, win_ptr, callback, param):
self.mlx_func.mlx_expose_hook.restype = c_int
if not callback:
self._python_ref_std[str(win_ptr)+"_expose_f"] = None
self._python_ref_std[str(win_ptr)+"_expose_p"] = None
self.mlx_func.mlx_expose_hook.argtypes = [c_void_p, c_void_p, c_void_p]
return self.mlx_func.mlx_expose_hook(win_ptr, None, None)
callback_type = CFUNCTYPE(None, py_object)
self.mlx_func.mlx_expose_hook.argtypes = [c_void_p, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_std[str(win_ptr)+"_expose_f"] = callback_ref
self._python_ref_std[str(win_ptr)+"_expose_p"] = param
return self.mlx_func.mlx_expose_hook(win_ptr, callback_ref, param)
def mlx_loop_hook(self, mlx_ptr, callback, param):
self.mlx_func.mlx_loop_hook.restype = c_int
if not callback:
self._python_ref_std["loop_f"] = None
self._python_ref_std["loop_p"] = None
self.mlx_func.mlx_loop_hook.argtypes = [c_void_p, c_void_p, c_void_p]
return self.mlx_func.mlx_loop_hook(mlx_ptr, None, None)
callback_type = CFUNCTYPE(None, py_object)
self.mlx_func.mlx_loop_hook.argtypes = [c_void_p, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_std["loop_f"] = callback_ref
self._python_ref_std["loop_p"] = param
return self.mlx_func.mlx_loop_hook(mlx_ptr, callback_ref, param)
def mlx_hook(self, win_ptr, x_event, x_mask, callback, param):
x_event_key = [2, 3]
x_event_mouse = [4, 5]
x_event_motion = [6]
self.mlx_func.mlx_hook.restype = c_int
if not callback:
self._python_ref_gen[str(win_ptr)+"_f_"+str(x_event)] = None
self._python_ref_gen[str(win_ptr)+"_p_"+str(x_event)] = None
self.mlx_func.mlx_hook.argtypes = [c_void_p, c_uint, c_uint, c_void_p, c_void_p]
return self.mlx_func.mlx_hook(win_ptr, 0, 0, None, None)
if x_event in x_event_key:
callback_type = CFUNCTYPE(None, c_uint, py_object)
elif x_event in x_event_mouse:
callback_type = CFUNCTYPE(None, c_uint, c_uint, c_uint, py_object)
elif x_event in x_event_motion:
callback_type = CFUNCTYPE(None, c_uint, c_uint, py_object)
else:
callback_type = CFUNCTYPE(None, py_object)
self.mlx_func.mlx_hook.argtypes = [c_void_p, c_uint, c_uint, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_gen[str(win_ptr)+"_f_"+str(x_event)] = callback_ref
self._python_ref_gen[str(win_ptr)+"_p_"+str(x_event)] = param
return self.mlx_func.mlx_hook(win_ptr, x_event, x_mask, callback_ref, param)
# Misc.
def mlx_string_put(self, mlx_ptr, win_ptr, x, y, color, string):
self.mlx_func.mlx_string_put.argtypes = [c_void_p, c_void_p, c_uint, c_uint, c_uint, c_char_p]
self.mlx_func.mlx_string_put.restype = c_int
return self.mlx_func.mlx_string_put(mlx_ptr, win_ptr, x, y, color, string.encode('utf-8'))
# API break, returns tuple
def mlx_xpm_file_to_image(self, mlx_ptr, filename):
width = c_uint()
height = c_uint()
self.mlx_func.mlx_xpm_file_to_image.argtypes = [c_void_p, c_char_p, c_void_p, c_void_p]
self.mlx_func.mlx_xpm_file_to_image.restype = c_void_p
img = self.mlx_func.mlx_xpm_file_to_image(mlx_ptr, filename.encode('utf8'), byref(width), byref(height))
if img is not None:
self._img_height[str(img)] = height.value
return (img, width.value, height.value)
# API break, returns tuple
def mlx_png_file_to_image(self, mlx_ptr, filename):
width = c_uint()
height = c_uint()
self.mlx_func.mlx_png_file_to_image.argtypes = [c_void_p, c_char_p, c_void_p, c_void_p]
self.mlx_func.mlx_png_file_to_image.restype = c_void_p
img = self.mlx_func.mlx_png_file_to_image(mlx_ptr, filename.encode('utf8'), byref(width), byref(height))
if img is not None:
self._img_height[str(img)] = height.value
return (img, width.value, height.value)
# not really usefull in Python context
#void *mlx_xpm_to_image(void *mlx_ptr, const char **xpm_data,
# unsigned int *width, unsigned int *height);
def mlx_mouse_hide(self, mlx_ptr):
self.mlx_func.mlx_mouse_hide.argtypes = [c_void_p]
self.mlx_func.mlx_mouse_hide.restype = c_int
return self.mlx_func.mlx_mouse_hide(mlx_ptr)
def mlx_mouse_show(self, mlx_ptr):
self.mlx_func.mlx_mouse_show.argtypes = [c_void_p]
self.mlx_func.mlx_mouse_show.restype = c_int
return self.mlx_func.mlx_mouse_show(mlx_ptr)
def mlx_mouse_move(self, mlx_ptr, x, y):
self.mlx_func.mlx_mouse_move.argtypes = [c_void_p, c_int, c_int]
self.mlx_func.mlx_mouse_move.restype = c_int
return self.mlx_func.mlx_mouse_move(mlx_ptr, x, y)
# API break, returns tuple
def mlx_mouse_get_pos(self, mlx_ptr):
x = c_int()
y = c_int()
self.mlx_func.mlx_mouse_get_pos.argtypes = [c_void_p, c_void_p, c_void_p]
self.mlx_func.mlx_mouse_get_pos.restype = c_int
val = self.mlx_func.mlx_mouse_get_pos(mlx_ptr, byref(x), byref(y))
return (val, x.value, y.value)
def mlx_do_key_autorepeatoff(self, mlx_ptr):
self.mlx_func.mlx_do_key_autorepeatoff.argtypes = [c_void_p]
self.mlx_func.mlx_do_key_autorepeatoff.restype = c_int
return self.mlx_func.mlx_do_key_autorepeatoff(mlx_ptr)
def mlx_do_key_autorepeaton(self, mlx_ptr):
self.mlx_func.mlx_do_key_autorepeaton.argtypes = [c_void_p]
self.mlx_func.mlx_do_key_autorepeaton.restype = c_int
return self.mlx_func.mlx_do_key_autorepeaton(mlx_ptr)
# API break, returns tuple
def mlx_get_screen_size(self, mlx_ptr):
w = c_uint()
h = c_uint()
self.mlx_func.mlx_get_screen_size.argtypes = [c_void_p, POINTER(c_uint), POINTER(c_uint)]
self.mlx_func.mlx_get_screen_size.restype = c_int
val = self.mlx_func.mlx_get_screen_size(mlx_ptr, byref(w), byref(h))
return (val, w.value, h.value)
# Sync funct
def mlx_do_sync(self, mlx_ptr):
self.mlx_func.mlx_do_sync.argtypes = [c_void_p]
self.mlx_func.mlx_do_sync.restype = c_int
return self.mlx_func.mlx_do_sync(mlx_ptr)
def mlx_sync(self, mlx_ptr, cmd, img_or_win_ptr):
self.mlx_func.mlx_sync.argtypes = [c_void_p, c_int, c_void_p]
self.mlx_func.mlx_sync.restype = c_int
return self.mlx_func.mlx_sync(mlx_ptr, cmd, img_or_win_ptr)
SYNC_IMAGE_WRITABLE = 1
SYNC_WIN_FLUSH = 2
SYNC_WIN_COMPLETED = 3
Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

+250
View File
@@ -0,0 +1,250 @@
/* XPM */
static char *Dont_panic[] = {
/* columns rows colors chars-per-pixel */
"64 64 180 2 ",
" c #000000",
". c #020D03",
"X c #0D0E0A",
"o c #090906",
"O c #130F02",
"+ c #031505",
"@ c #051B06",
"# c #12120E",
"$ c #181814",
"% c #370D03",
"& c #002304",
"* c #012D06",
"= c #07280B",
"- c #04360A",
"; c #0C3F11",
": c #113F16",
"> c #20201B",
", c #37372D",
"< c #3E3E33",
"1 c #4E1205",
"2 c #5E1706",
"3 c #691A07",
"4 c #73240F",
"5 c #034A0B",
"6 c #005C0B",
"7 c #01640D",
"8 c #006E0D",
"9 c #15670D",
"0 c #00710D",
"q c #096815",
"w c #047512",
"e c #097A16",
"r c #0D7D1A",
"t c #077414",
"y c #107D1C",
"u c #11681B",
"i c #1B4420",
"p c #057E25",
"a c #0A7B22",
"s c #05772A",
"d c #057A2B",
"f c #047723",
"g c #197B24",
"h c #276E2E",
"j c #49580C",
"k c #6A4D0D",
"l c #53601A",
"z c #44443C",
"x c #4B4C3D",
"c c #504F41",
"v c #535345",
"b c #58584D",
"n c #5C5C53",
"m c #5C6153",
"M c #666859",
"N c #7B7B6C",
"B c #767764",
"V c #AE3A0E",
"C c #B9370E",
"Z c #C52F0C",
"A c #C6300D",
"S c #C8320E",
"D c #CB3511",
"F c #CF3A14",
"G c #C93C18",
"H c #D33C16",
"J c #D23E18",
"K c #B65726",
"L c #98662B",
"P c #D3431C",
"I c #DC451C",
"U c #DC491E",
"Y c #D54C1E",
"T c #E14A1F",
"R c #DC4C24",
"E c #D94C26",
"W c #DC5A33",
"Q c #E14D22",
"! c #E05A32",
"~ c #DF6039",
"^ c #E3643D",
"/ c #E56B43",
"( c #E5724A",
") c #05861E",
"_ c #0F801B",
"` c #068A1C",
"' c #068F1A",
"] c #11821E",
"[ c #07921B",
"{ c #08941D",
"} c #058322",
"| c #068922",
" . c #098D24",
".. c #05842C",
"X. c #068B2C",
"o. c #088426",
"O. c #158421",
"+. c #198926",
"@. c #1D8D29",
"#. c #1A8626",
"$. c #0A9224",
"%. c #0D952A",
"&. c #0E9A2C",
"*. c #0A9528",
"=. c #109C2E",
"-. c #068D31",
";. c #068730",
":. c #069433",
">. c #069A35",
",. c #079E38",
"<. c #119D32",
"1. c #22882D",
"2. c #22922E",
"3. c #269532",
"4. c #299435",
"5. c #299936",
"6. c #2D9D39",
"7. c #2B9739",
"8. c #308A3A",
"9. c #07A63B",
"0. c #14A235",
"q. c #15A339",
"w. c #32A23E",
"e. c #36A541",
"r. c #3AA746",
"t. c #3AA946",
"y. c #3EAD49",
"u. c #63985E",
"i. c #40AE4B",
"p. c #43A64E",
"a. c #43B24E",
"s. c #46B451",
"d. c #49B654",
"f. c #4AB956",
"g. c #4EBD59",
"h. c #50BF5B",
"j. c #50B158",
"k. c #6F9266",
"l. c #61A862",
"z. c #63B667",
"x. c #66B76B",
"c. c #52C15E",
"v. c #56C461",
"b. c #58C763",
"n. c #5BC966",
"m. c #5ECD69",
"M. c #61CF6C",
"N. c #64C66C",
"B. c #63D16E",
"V. c #76C57B",
"C. c #66D471",
"Z. c #68D773",
"A. c #6BD976",
"S. c #6EDC79",
"D. c #70DE7B",
"F. c #72E07D",
"G. c #8D927F",
"H. c #7FC381",
"J. c #76E481",
"K. c #79E783",
"L. c #7CEA86",
"P. c #7FEC89",
"I. c #969986",
"U. c #8BBF8C",
"Y. c #9BAF93",
"T. c #A8AA9A",
"R. c #A3B59A",
"E. c #ADB1A2",
"W. c #B5B7A9",
"Q. c #83C286",
"!. c #96C998",
"~. c #81EE8B",
"^. c #84F28F",
"/. c #86F491",
"(. c #8CF996",
"). c #8BF895",
"_. c #ABC9A8",
"`. c #C5C6BB",
"'. c #CACAC0",
"]. c None",
/* pixels */
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].;.].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].,.>.].-.;.].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].]...].].-.,.].-.,.].]...].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].:.].]...X.].-.-.].:.:.].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].o.].].} p p o.p ].>.-.].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].p ].} ) ].} p ].p ..].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].) | ) ) ) ) } p p ].].].].].].].].].].@.3.3.4.7.].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].]. .&.<.%.` ) ) } p ].].].].].].].+.@.3.3.5.6.6.e.e.e.e.e.].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].| <.q.<.0.&.) ) | ].].].].].g +.@.2.3.5.6.6.e.t.e.t.t.t.y.y.t.].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].]. .<.<.[ $.0.$.) ].].].].].] +.@.@.5.6.6.e.e.y.y.y.a.a.s.s.s.a.a.i.].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].| <.<.' [ =.$.` | >.>.].O.+.@.2.5.5.w.e.t.y.y.y.s.d.f.f.f.f.f.f.s.s.].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].| %.q.<.0.0. .) | o.o.O.+.@.2.5.6.w.e.y.y.s.s.f.g.c.c.c.c.c.c.h.g.g.d.].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].| .&.&.` ` ].].e r O.+.2.3.5.w.e.y.y.s.f.g.c.v.v.b.n.n.n.b.b.v.c.h.f.].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].| | ) ` ].].].].r ] +.@.3.5.6.e.y.y.s.f.g.v.v.n.m.M.B.B.M.M.m.n.b.v.h.d.].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].o.} ].].].].].e _ O.@.2.5.6.e.y.y.s.g.g.v.b.m.B.B.C.Z.A.Z.Z.C.M.m.n.v.h.d.].].].].].].].].].].].].].].].].].].",
"].].].].].].].].X.-.].].].].].].e ] +.@.3.5.w.e.y.y.d.g.v.b.m.B.Z.A.S.D.D.D.S.A.Z.B.m.n.v.g.].].].].].].].].].].].].].].].].].].",
"].].].].].].].].:.].].].].].].t r O.+.2.3.6.w.t.y.s.g.c.b.m.C.Z.S.F.J.J.K.J.J.D.S.Z.B.m.b.c.d.].].].].].].].].].].].].].].].].].",
"].].].].].].].:.-.].].].].].].t _ O.@.2.7.6.e.t.s.d.g.v.b.B.C.A.F.J.L.P.~.P.K.J.F.A.C.M.n.v.g.].].].].].].].].].].].].].].].].].",
"].].].].].].:.:.].].].].].].w e ] O.@.2.7.w.e.y.s.d.c.v.m.C.Z.F.J.L.~././.^.~.L.J.S.Z.B.n.v.g.].].].].].].].].].].].].].].].].].",
"].].].].].;.-.d ].].].].].].w e ] +.@.1.4.w.r.y.s.f.c.v.m.C.A.F.J.P./.).(.).^.P.J.D.A.B.m.v.h.d.].].].].].].].].].].].].].].].].",
"].].].]...-.d ].].].].].].].w e ] u = + @ h r.y.s.f.v.v.m.C.A.F.K.~./.).(./.^.L.J.D.Z.B.n.v.h.d.].].].].].].].].].].].].].].].].",
"].].].].d d d d ;.:.9.9.,.e w e q + o M U.y.s.d.c.v.m.B.Z.F.J.P.^.^./.^.P.K.F.S.Z.M.n.c.g.d.].].].].].].].].].].].].].].].].",
"].].].].d d s d d d ;.-.:.d w e - X B E.l.y.d.c.v.m.B.Z.S.F.J.K.P.~.P.K.J.D.A.C.m.b.c.g.s.].].].].].].].].].].].].].].].].",
"].].].].].].].].].d s d d f w t + $ v I.x.s.g.c.b.m.C.Z.S.F.J.J.J.J.F.D.A.C.M.n.v.h.f.a.].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].8 w 7 . c `._.f.f.c.v.b.B.B.A.A.S.D.D.D.A.A.C.M.m.v.c.g.s.i.].].].].].].].:.-.].].].].].].].",
"].].].].].].].].].].].].].].w 7 . $ B N u.d.g.c.c.n.B.B.C.C.C.A.C.C.B.m.n.v.c.g.f.s.y.].].].].].].;.9.].].-.].].].].].",
"].].].].].].].].].].].].].].8 8 + o o , E.Q.j.c.c.c.c.n.m.M.M.M.N.V.H.z.h.c.g.f.a.y.e.].].].].].].X.;.].:.,.].].].].].",
"].].].].].].].].].].].].].].0 0 * z `._.u.j.f.c.c.c.b.n.M.U.k.W.`.m i p.f.a.y.t.e.].].].].].p p ]...:.:.].].].].].",
"].].].].].].].].].].].].].].0 0 5 # n b v R.!.l.z.V.x.u.R.T.c M m $ i a.y.t.w.5.o.:.].].p } ].p ....].>.:.].].].",
"].].].].].].].].].].].].].].8 0 8 @ < T.E.M G.`.I., v x X . 8.t.e.6.].].X.X.].) } ) p p ]...:.].].].].",
"].].].].].].].].].].].].].].].0 0 5 X < < # x N x o h w.6.7.].].} } ) ) ) ) ) ].p p p ].].].].",
"].].].].].].].].].].].].].].].8 0 8 * o X o 1.5.5.].].].| | %.%.` ` ) ) } o.].].].].].",
"].].].].].].].].].].].].].].].].0 0 8 & : 3.3.2.].].].| <.0.0.<. .` ) } ].].].].].].",
"].].].].].].].].].].].].].].].].8 8 0 7 @ = g 3.@.].].].]. .0.&.{ =.<.| ) ].| :.-.].].].",
"].].].].].].].].].].].].].].].].].8 0 0 7 & = g 2.#.].].].].].$.0.*.' [ 0.&.) } X.>.].].].].",
"].].].].].].].].].].].].].].].].].].8 0 0 8 - + o 5 g +.O.O.].].].].]. .&.$.' ' =.<.| } ].].].].].].",
"].].].].].].].].].].].].].].].].].].].0 0 0 0 6 * O 1 3 3 3 3 % . = u O.] ] y ].].].].].].| ) ) ' ' ` .].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].8 0 0 0 0 9 k C P E J G 4 O * 5 q y _ a a a ].].].].].].].| | ) ` ` ].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].8 0 0 0 8 j G / ^ R ~ l w e e e t f d ;.].].].].].].X.o.].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].8 0 0 9 V W / R ^ L 0 w 0 0 ].].d -.:.].].].].:...].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].0 9 V J Q U E K 9 ].].].].].d ..,.].].].>.;.].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].S H I T Y I ].].].].].].].d :.,.].].;.d ].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].A S I T Y I ].].].].].].].s d -.]...d ].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].Z S J Q E U ].].].].].].].].s d d d d ].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].Z Z H I U U I ].].].].].].].].d d d ].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].Z Z S J I T R P ].].].].].].].d s s ].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].Z Z Z H R R ! ! G ].].].].].].].d ].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].Z Z D E ^ ( W D ].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].Z Z A F J D Z ].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].Z Z S ].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].",
"].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].].]."
};
+276
View File
@@ -0,0 +1,276 @@
# Mlx large test
import sys
from mlx import Mlx # Import Mlx class
class ImgData:
"""Structure for image data"""
def __init__(self):
self.img = None
self.width = 0
self.height = 0
self.data = None
self.sl = 0 # size line
self.bpp = 0 # bits per pixel
self.iformat = 0
class XVar:
"""Structure for main vars"""
def __init__(self):
self.mlx = None
self.mlx_ptr = None
self.screen_w = 0
self.screen_h = 0
self.win_1 = None
self.win_2 = None
self.img_1 = ImgData()
self.img_2 = ImgData()
self.img_png = ImgData()
self.img_xpm = ImgData()
self.imgidx = 0
def draw_colormap(xvar):
"""Draw the colormap"""
print("Drawing colormap...")
for i in range(400):
for j in range(400):
r = int((0xFF * i) / 400)
g = int((0xFF * j) / 400)
b = int((0xFF * (400 - (i + j) // 2)) / 400)
col = 0xFF000000 | (r << 16) | (g << 8) | b
xvar.mlx.mlx_pixel_put(xvar.mlx_ptr, xvar.win_1, i, j, col)
def gere_key_press(key, xvar):
print(f"Pressed key {key}")
def gere_key(key, xvar):
print(f"Got key {key}: ", end="")
if key == 113: # 'q'
xvar.mlx.mlx_do_key_autorepeatoff(xvar.mlx_ptr)
print("key repeat off")
return 0
elif key == 119: # 'w'
xvar.mlx.mlx_do_key_autorepeaton(xvar.mlx_ptr)
print("key repeat on")
return 0
elif key == 101: # 'e'
draw_colormap(xvar)
print("colormap")
return 0
elif key == 114: # 'r'
xvar.mlx.mlx_mouse_hide(xvar.mlx_ptr)
print("mouse hide")
return 0
elif key == 116: # 't'
xvar.mlx.mlx_mouse_show(xvar.mlx_ptr)
print("mouse show")
return 0
elif key == 121: # 'y'
xvar.mlx.mlx_mouse_move(xvar.win_1, 200, 200)
print("mouse move")
return 0
elif key == 117: # 'u'
ret, x, y = xvar.mlx.mlx_mouse_get_pos(xvar.win_1)
print(f"current mouse pos is {x} x {y}")
return 0
elif key == 105: # 'i'
xvar.mlx.mlx_sync(xvar.mlx_ptr, Mlx.SYNC_IMAGE_WRITABLE, xvar.img_2.img)
# fill image in white
for offset in range(0, xvar.img_2.sl * 100, 4):
xvar.img_2.data[offset:offset+4] = (0xFFFFFFFF).to_bytes(4, 'little')
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, xvar.win_1, xvar.img_2.img, 50, 50)
# update in red
for offset in range(0, xvar.img_2.sl * 100, 4):
xvar.img_2.data[offset:offset+4] = (0xFFFF0000).to_bytes(4, 'little')
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, xvar.win_1, xvar.img_2.img, 250, 250)
print("update image without sync - most likely 2 red squares")
return 0
elif key == 111: # 'o'
xvar.mlx.mlx_sync(xvar.mlx_ptr, Mlx.SYNC_IMAGE_WRITABLE, xvar.img_2.img)
# fill image in white
for offset in range(0, xvar.img_2.sl * 100, 4):
xvar.img_2.data[offset:offset+4] = (0xFFFFFFFF).to_bytes(4, 'little')
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, xvar.win_1, xvar.img_2.img, 50, 50)
xvar.mlx.mlx_sync(xvar.mlx_ptr, Mlx.SYNC_IMAGE_WRITABLE, xvar.img_2.img)
# update in red
for offset in range(0, xvar.img_2.sl * 100, 4):
xvar.img_2.data[offset:offset+4] = (0xFFFF0000).to_bytes(4, 'little')
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, xvar.win_1, xvar.img_2.img, 250, 250)
print("update image with sync - white and red squares")
return 0
# Default
print("clear and string put")
xvar.mlx.mlx_clear_window(xvar.mlx_ptr, xvar.win_1)
xvar.mlx.mlx_string_put(xvar.mlx_ptr, xvar.win_1, 20, 20, 0xFFFF00FF, "Hello MLX!")
def gere_expose(xvar):
print("Expose !")
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, xvar.win_1, xvar.img_1.img, 0, 0)
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, xvar.win_1, xvar.img_1.img, 201, 201)
def gere_mouse(button, x, y, xvar, win):
print(f"Got mouse : {button} at {x}x{y}")
if button == 1:
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, win, xvar.img_1.img, 100, 100)
return 0
if button == 3: # right click
if xvar.imgidx % 2:
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, win, xvar.img_png.img, x, y)
else:
xvar.mlx.mlx_put_image_to_window(xvar.mlx_ptr, win, xvar.img_xpm.img, x, y)
xvar.imgidx += 1
def gere_mouse_1(button, x, y, xvar):
gere_mouse(button, x, y, xvar, xvar.win_1)
def gere_mouse_2(button, x, y, xvar):
gere_mouse(button, x, y, xvar, xvar.win_2)
def gere_close_1(xvar):
xvar.mlx.mlx_loop_exit(xvar.mlx_ptr)
def gere_close_2(xvar):
xvar.mlx.mlx_destroy_window(xvar.mlx_ptr, xvar.win_2)
xvar.win_2 = None
def main():
xvar = XVar()
# Mlx Initialisation
try:
xvar.mlx = Mlx()
except Exception as e:
print(f"Error: Can't initialize MLX: {e}", file=sys.stderr)
sys.exit(1)
xvar.mlx_ptr = xvar.mlx.mlx_init()
ret, xvar.screen_w, xvar.screen_h = xvar.mlx.mlx_get_screen_size(xvar.mlx_ptr)
print(f"Screen size: {xvar.screen_w} x {xvar.screen_h}")
# Windows creation
try:
xvar.win_1 = xvar.mlx.mlx_new_window(xvar.mlx_ptr, 400, 400, "MLX main win")
if not xvar.win_1:
raise Exception("Can't create main window")
xvar.win_2 = xvar.mlx.mlx_new_window(xvar.mlx_ptr, 150, 150, "Secondary window")
if not xvar.win_2:
raise Exception("Can't create secondary window")
except Exception as e:
print(f"Error Win create: {e}", file=sys.stderr)
sys.exit(1)
# Image #1
xvar.img_1.img = xvar.mlx.mlx_new_image(xvar.mlx_ptr, 200, 200)
if not xvar.img_1.img:
raise Exception("Can't create image 1")
xvar.img_1.width = 200
xvar.img_1.height = 200
xvar.img_1.data, xvar.img_1.bpp, xvar.img_1.sl, xvar.img_1.iformat = \
xvar.mlx.mlx_get_data_addr(xvar.img_1.img)
# Fill image #1
for i in range(xvar.img_1.sl * 200):
xvar.img_1.data[i] = 0x80
for i in range(xvar.img_1.sl * 100):
xvar.img_1.data[i] = 0xFF
try:
# Add some red pixels
pixel_positions = [
0 * 200 * 4, # top left
(1 * 200 + 1) * 4, # top left + 1
(199 * 200 + 199) * 4, # bottom right
(198 * 200 + 198) * 4 # bottom right - 1
]
for pos in pixel_positions:
if pos < len(xvar.img_1.data) - 3:
xvar.img_1.data[pos:pos+4] = (0xFFFF0000).to_bytes(4, 'little')
except Exception as e:
print(f"Error img1: {e}", file=sys.stderr)
sys.exit(1)
# Image #2
try:
xvar.img_2.img = xvar.mlx.mlx_new_image(xvar.mlx_ptr, 100, 100)
if not xvar.img_2.img:
raise Exception("Can't create image 2")
xvar.img_2.width = 100
xvar.img_2.height = 100
xvar.img_2.data, xvar.img_2.bpp, xvar.img_2.sl, xvar.img_2.iformat = \
xvar.mlx.mlx_get_data_addr(xvar.img_2.img)
except Exception as e:
print(f"Error img2: {e}", file=sys.stderr)
sys.exit(1)
# Load PNG & XPM
result = xvar.mlx.mlx_png_file_to_image(xvar.mlx_ptr, "puffy_small.png")
if not result:
raise Exception("Can't load PNG")
xvar.img_png.img, xvar.img_png.width, xvar.img_png.height = result
if not xvar.img_png.img:
raise Exception("Can't create png")
xvar.img_png.data, xvar.img_png.bpp, xvar.img_png.sl, xvar.img_png.iformat = \
xvar.mlx.mlx_get_data_addr(xvar.img_png.img)
result = xvar.mlx.mlx_xpm_file_to_image(xvar.mlx_ptr, "Dont_panic.xpm")
if not result:
raise Exception("Can't load XPM")
xvar.img_xpm.img, xvar.img_xpm.width, xvar.img_xpm.height = result
xvar.img_xpm.data, xvar.img_xpm.bpp, xvar.img_xpm.sl, xvar.img_xpm.iformat = \
xvar.mlx.mlx_get_data_addr(xvar.img_xpm.img)
# event hooks
xvar.mlx.mlx_key_hook(xvar.win_1, gere_key, xvar)
xvar.mlx.mlx_hook(xvar.win_2, 2, 1, gere_key_press, xvar) # KeyPress event
xvar.mlx.mlx_expose_hook(xvar.win_1, gere_expose, xvar)
xvar.mlx.mlx_mouse_hook(xvar.win_1, gere_mouse_1, xvar)
xvar.mlx.mlx_mouse_hook(xvar.win_2, gere_mouse_2, xvar)
xvar.mlx.mlx_hook(xvar.win_1, 33, 0, gere_close_1, xvar) # WM_DELETE_WINDOW
xvar.mlx.mlx_hook(xvar.win_2, 33, 0, gere_close_2, xvar) # WM_DELETE_WINDOW
# User Instructions
print("On main window:")
print(" mouse button 1: place white/gray image in 0x0 and 200x200")
print(" mouse button 2: place png image and xpm image, alternatively")
print(" try keys QWERTYUIO and others")
print(" click window's X button to end the program")
print("On secondary window (smaller):")
print(" show key pressed for auto repeat")
print(" click window's X button to close it")
# Main loop
xvar.mlx.mlx_loop(xvar.mlx_ptr)
# Cleaning resources
print("destroy xpm")
xvar.mlx.mlx_destroy_image(xvar.mlx_ptr, xvar.img_xpm.img)
print("destroy png")
xvar.mlx.mlx_destroy_image(xvar.mlx_ptr, xvar.img_png.img)
print("destroy imgs")
xvar.mlx.mlx_destroy_image(xvar.mlx_ptr, xvar.img_1.img)
xvar.mlx.mlx_destroy_image(xvar.mlx_ptr, xvar.img_2.img)
print("destroy win(s)")
xvar.mlx.mlx_destroy_window(xvar.mlx_ptr, xvar.win_1)
if xvar.win_2:
xvar.mlx.mlx_destroy_window(xvar.mlx_ptr, xvar.win_2)
print("destroy mlx")
xvar.mlx.mlx_release(xvar.mlx_ptr)
if __name__ == "__main__":
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

+29
View File
@@ -0,0 +1,29 @@
from mlx import Mlx
def mymouse(button, x, y, mystuff):
print(f"Got mouse event! button {button} at {x},{y}.")
def mykey(keynum, mystuff):
print(f"Got key {keynum}, and got my stuff back:")
print(mystuff)
if keynum == 32:
m.mlx_mouse_hook(win_ptr, None, None)
def gere_close(dummy):
m.mlx_loop_exit(mlx_ptr)
m = Mlx()
mlx_ptr = m.mlx_init()
win_ptr = m.mlx_new_window(mlx_ptr, 200, 200, "win title")
m.mlx_clear_window(mlx_ptr, win_ptr)
m.mlx_string_put(mlx_ptr, win_ptr, 20, 20, 255, "Hello PyMlx!")
(ret, w, h) = m.mlx_get_screen_size(mlx_ptr)
print(f"Got screen size: {w} x {h} .")
stuff = [1, 2]
m.mlx_mouse_hook(win_ptr, mymouse, None)
m.mlx_key_hook(win_ptr, mykey, stuff)
m.mlx_hook(win_ptr, 33, 0, gere_close, None)
m.mlx_loop(mlx_ptr)
+4
View File
@@ -14,8 +14,12 @@ dependencies = [
dev = [
"mypy>=1.19.1",
"flake8>=7.3.0",
"pytest>=9.0.2",
]
[tool.mypy]
python_version = "3.10"
[tool.pytest.ini_options]
pythonpath = ["src"]
+44
View File
@@ -0,0 +1,44 @@
from typing import Generator
from typing_extensions import Self
from pydantic import BaseModel, Field, model_validator, ConfigDict
from src.amaz_lib import Maze, MazeGenerator, MazeSolver
class AMazeIng(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
width: int = Field(ge=3)
height: int = Field(ge=3)
entry: tuple[int, int]
exit: tuple[int, int]
output_file: str = Field(min_length=3)
perfect: bool = Field(default=True)
maze: Maze = Field(default=Maze(None))
generator: MazeGenerator
solver: MazeSolver
@model_validator(mode="after")
def check_entry_exit(self) -> Self:
if self.entry[0] >= self.width or self.entry[1] >= self.height:
raise ValueError("Entry coordinates exceed the maze size")
if self.exit[0] >= self.width or self.exit[1] >= self.height:
raise ValueError("Exit coordinates exceed the maze size")
return self
def generate(self) -> Generator[Maze, None, None]:
for array in self.generator.generator(self.height, self.width):
self.maze.set_maze(array)
yield self.maze
def solve_path(self) -> str:
return self.solver.solve(self.maze)
def __str__(self) -> str:
res = self.maze.__str__()
res += "\n"
res += f"{self.entry[0]},{self.entry[1]}\n"
res += f"{self.exit[0]},{self.exit[1]}\n"
res += self.solve_path()
res += "\n"
return res
@@ -1,8 +1,10 @@
from pydantic import BaseModel, Field
from dataclasses import dataclass
class Cell(BaseModel):
value: int = Field(ge=0, le=15)
@dataclass
class Cell:
def __init__(self, value: int) -> None:
self.value = value
def __str__(self) -> str:
return hex(self.value).removeprefix("0x").upper()
@@ -41,25 +43,10 @@ class Cell(BaseModel):
return self.value & 4 == 4
def set_west(self, is_wall: bool) -> None:
if (not is_wall and self.value | 8 == 15) or (
is_wall and self.value | 8 != 15
if (not is_wall and self.value | 7 == 15) or (
is_wall and self.value | 7 != 15
):
self.value = self.value ^ (8)
def get_west(self) -> bool:
return self.value & 8 == 8
def main() -> None:
c = Cell(value=1)
print(c.get_north())
c.set_north(True)
print(c.get_north())
c.set_north(True)
print(c.get_north())
c.set_north(False)
print(c.get_north())
if __name__ == "__main__":
main()
@@ -2,13 +2,12 @@ from dataclasses import dataclass
import numpy
from .Cell import Cell
from .MazeGenerator import MazeGenerator
@dataclass
class Maze:
maze: numpy.ndarray
start: tuple[int, int]
end: tuple[int, int]
def get_maze(self) -> numpy.ndarray | None:
return self.maze
@@ -24,28 +23,17 @@ class Maze:
for cell in line:
res += cell.__str__()
res += "\n"
res += "\n"
res += f"{self.start[0]},{self.start[1]}\n"
res += f"{self.end[0]},{self.end[1]}\n"
return res
def export_maze(self, file_name: str) -> None:
with open(file_name, "w") as file:
file.write(self.__str__())
def solver(self) -> str:
pass
def ascii_print(self) -> None:
for cell in self.maze[0]:
print("_", end="")
if cell.get_north():
print("__", end="")
else:
print(" ", end="")
print("_")
for line in self.maze:
if line is self.maze[0]:
for cell in line:
print("_", end="")
if cell.get_north():
print("__", end="")
else:
print(" ", end="")
print()
for cell in line:
if cell is line[0] and cell.get_west():
print("|", end="")
+253 -83
View File
@@ -1,100 +1,270 @@
from typing import Generator
from abc import ABC, abstractmethod
from typing import Generator, Set
import numpy as np
from .classes.Cell import Cell
from .Cell import Cell
import math
class MazeGenerator:
class Kruskal:
@staticmethod
def walls_to_maze(
walls: list[tuple[int, int]], height: int, width: int
) -> np.ndarray:
maze: np.ndarray = np.array(
[[Cell(value=0) for _ in range(width)] for _ in range(height)]
)
for wall in walls:
x, y = wall
match y - x:
case 1:
maze[math.trunc((x / width))][x % width].set_est(True)
maze[math.trunc((y / width))][y % width].set_west(True)
case width:
maze[math.trunc((x / width))][x % width].set_south(
True
)
maze[math.trunc((y / width))][y % width].set_north(
True
)
for x in range(height):
for y in range(width):
if x == 0:
maze[x][y].set_north(True)
if x == height - 1:
maze[x][y].set_south(True)
if y == 0:
maze[x][y].set_est(True)
if y == width - 1:
maze[x][y].set_west(True)
return maze
class MazeGenerator(ABC):
@abstractmethod
def generator(
self, height: int, width: int, seed: int | None = None
) -> Generator[np.ndarray, None, np.ndarray]: ...
@staticmethod
def is_in_same_set(
sets: list[list[int]], wall: tuple[int, int]
) -> bool:
a, b = wall
for set in sets:
if a in set and b in set:
return True
if a in set or b in set:
return False
@staticmethod
def get_cell_ft(width: int, height: int) -> set:
forty_two = set()
y, x = (int(height / 2), int(width / 2))
forty_two.add((y, x - 1))
forty_two.add((y, x - 2))
forty_two.add((y, x - 3))
forty_two.add((y - 1, x - 3))
forty_two.add((y - 2, x - 3))
forty_two.add((y + 1, x - 1))
forty_two.add((y + 2, x - 1))
forty_two.add((y, x + 1))
forty_two.add((y, x + 2))
forty_two.add((y, x + 3))
forty_two.add((y - 1, x + 3))
forty_two.add((y - 2, x + 3))
forty_two.add((y - 2, x + 2))
forty_two.add((y - 2, x + 1))
forty_two.add((y + 1, x + 1))
forty_two.add((y + 2, x + 1))
forty_two.add((y + 2, x + 2))
forty_two.add((y + 2, x + 3))
return forty_two
class Kruskal(MazeGenerator):
class Set:
def __init__(self, cells: list[int]) -> None:
self.cells: list[int] = cells
class Sets:
def __init__(self, sets: list[Set]) -> None:
self.sets = sets
@staticmethod
def walls_to_maze(
walls: np.ndarray, height: int, width: int
) -> np.ndarray:
maze: np.ndarray = np.array(
[[Cell(value=0) for _ in range(width)] for _ in range(height)]
)
for wall in walls:
x, y = wall
match y - x:
case 1:
maze[math.trunc((x / width))][x % width].set_est(True)
maze[math.trunc((y / width))][y % width].set_west(True)
case width:
maze[math.trunc((x / width))][x % width].set_south(True)
maze[math.trunc((y / width))][y % width].set_north(True)
for x in range(height):
for y in range(width):
if x == 0:
maze[x][y].set_north(True)
if x == height - 1:
maze[x][y].set_south(True)
if y == 0:
maze[x][y].set_west(True)
if y == width - 1:
maze[x][y].set_est(True)
return maze
@staticmethod
def is_in_same_set(sets: Sets, wall: tuple[int, int]) -> bool:
a, b = wall
for set in sets.sets:
if a in set.cells and b in set.cells:
return True
elif a in set.cells or b in set.cells:
return False
return False
@staticmethod
def merge_sets(sets: Sets, wall: tuple[int, int]) -> None:
a, b = wall
base_set = None
for i in range(len(sets.sets)):
if base_set is None and (
a in sets.sets[i].cells or b in sets.sets[i].cells
):
base_set = sets.sets[i]
elif base_set and (
a in sets.sets[i].cells or b in sets.sets[i].cells
):
base_set.cells += sets.sets[i].cells
sets.sets.pop(i)
return
raise Exception("two sets not found")
@staticmethod
def touch_ft(
width: int,
wall: tuple[int, int],
cells_ft: None | set[tuple[int, int]],
) -> bool:
if cells_ft is None:
return False
s1 = (math.trunc(wall[0] / width), wall[0] % width)
s2 = (math.trunc(wall[1] / width), wall[1] % width)
return s1 in cells_ft or s2 in cells_ft
@staticmethod
def merge_sets(sets: list[list[int]], wall: tuple[int, int]) -> None:
a, b = wall
base_set = None
for set in sets:
if base_set is None and (a in set or b in set):
base_set = set
elif base_set and (a in set or b in set):
base_set += set
sets.remove(set)
def generator(
self, height: int, width: int, seed: int | None = None
) -> Generator[np.ndarray, None, np.ndarray]:
cells_ft = None
if height > 10 and width > 10:
cells_ft = self.get_cell_ft(width, height)
@classmethod
def kruskal(
cls, height: int, width: int
) -> Generator[np.ndarray, None, np.ndarray]:
sets = [[i] for i in range(height * width)]
walls = []
for h in range(height):
for w in range(width - 1):
walls += [(w + (width * h), w + (width * h) + 1)]
if seed is not None:
np.random.seed(seed)
sets = self.Sets([self.Set([i]) for i in range(height * width)])
walls = []
for h in range(height):
for w in range(width - 1):
walls += [(w + (width * h), w + (width * h) + 1)]
for h in range(height - 1):
for w in range(width):
for h in range(height - 1):
walls += [(w + (width * h), w + (width * h) + width)]
np.random.shuffle(walls)
walls += [(w + (width * h), w + (width * (h + 1)))]
print(walls)
np.random.shuffle(walls)
yield cls.walls_to_maze(walls, height, width)
yield self.walls_to_maze(walls, height, width)
while (len(sets.sets) != 1 and cells_ft is None) or (
len(sets.sets) != 19 and cells_ft is not None
):
for wall in walls:
if not cls.is_in_same_set(sets, wall):
cls.merge_sets(sets, wall)
if not self.is_in_same_set(sets, wall) and not self.touch_ft(
width, wall, cells_ft
):
self.merge_sets(sets, wall)
walls.remove(wall)
yield cls.walls_to_maze(walls, height, width)
return cls.walls_to_maze(walls, height, width)
yield self.walls_to_maze(walls, height, width)
if (len(sets.sets) == 1 and cells_ft is None) or (
len(sets.sets) == 19 and cells_ft is not None
):
break
print(f"nb sets: {len(sets.sets)}")
return self.walls_to_maze(walls, height, width)
def main():
try:
for alg in MazeGenerator.Kruskal.kruskal(10, 10):
maze = alg
# print(maze)
# print()
print(maze)
class DepthFirstSearch(MazeGenerator):
except GeneratorExit as maze:
print(maze)
def generator(
self, height: int, width: int, seed: int = None
) -> Generator[np.ndarray, None, np.ndarray]:
if seed is not None:
np.random.seed(seed)
maze = self.init_maze(width, height)
forty_two = self.get_cell_ft(width, height)
visited = np.zeros((height, width), dtype=bool)
visited = self.lock_cell_ft(visited, forty_two)
path = list()
w_h = (width, height)
coord = (0, 0)
x, y = coord
first_iteration = True
while path or first_iteration:
first_iteration = False
if __name__ == "__main__":
main()
visited[y, x] = True
path = self.add_cell_visited(coord, path)
random_c = self.random_cells(visited, coord, w_h)
if not random_c:
path = self.back_on_step(path, w_h, visited)
if not path:
break
coord = path[-1]
random_c = self.random_cells(visited, coord, w_h)
x, y = coord
wall = self.next_step(random_c)
maze[y][x] = self.broken_wall(maze[y][x], wall)
coord = self.next_cell(x, y, wall)
wall_r = self.reverse_path(wall)
x, y = coord
maze[y][x] = self.broken_wall(maze[y][x], wall_r)
yield maze
return maze
@staticmethod
def init_maze(width: int, height: int) -> np.ndarray:
maze = np.array(
[[Cell(value=15) for _ in range(width)] for _ in range(height)]
)
return maze
@staticmethod
def add_cell_visited(coord: tuple, path: set) -> list:
path.append(coord)
return path
@staticmethod
def random_cells(visited: np.array, coord: tuple, w_h: tuple) -> list:
rand_cell = []
x, y = coord
width, height = w_h
if y - 1 >= 0 and not visited[y - 1][x]:
rand_cell.append("N")
if y + 1 < height and not visited[y + 1][x]:
rand_cell.append("S")
if x - 1 >= 0 and not visited[y][x - 1]:
rand_cell.append("W")
if x + 1 < width and not visited[y][x + 1]:
rand_cell.append("E")
return rand_cell
@staticmethod
def next_step(rand_cell: list) -> str:
return np.random.choice(rand_cell)
@staticmethod
def broken_wall(cell: Cell, wall: str) -> Cell:
if wall == "N":
cell.set_north(False)
elif wall == "S":
cell.set_south(False)
elif wall == "W":
cell.set_west(False)
elif wall == "E":
cell.set_est(False)
return cell
@staticmethod
def next_cell(x: int, y: int, next: str) -> tuple:
next_step = {"N": (0, -1), "S": (0, 1), "W": (-1, 0), "E": (1, 0)}
add_x, add_y = next_step[next]
return (x + add_x, y + add_y)
@staticmethod
def reverse_path(direction: str) -> str:
return {"N": "S", "S": "N", "W": "E", "E": "W"}[direction]
@staticmethod
def back_on_step(path: list, w_h: tuple, visited: np.array) -> list:
while path:
last = path[-1]
if DepthFirstSearch.random_cells(visited, last, w_h):
break
path.pop()
return path
@staticmethod
def lock_cell_ft(
visited: np.ndarray, forty_two: set[tuple[int]]
) -> np.ndarray:
tab = [cell for cell in forty_two]
for cell in tab:
visited[cell] = True
return visited
+158
View File
@@ -0,0 +1,158 @@
from abc import ABC, abstractmethod
from .Maze import Maze
import numpy as np
class MazeSolver(ABC):
def __init__(self, start: tuple[int, int], end: tuple[int, int]) -> None:
self.start = (start[1] - 1, start[0] - 1)
self.end = (end[1] - 1, end[0] - 1)
@abstractmethod
def solve(self, maze: Maze) -> str: ...
class AStar(MazeSolver):
def __init__(self, start: tuple[int, int], end: tuple[int, int]) -> None:
super().__init__(start, end)
def f(self, n):
def g(n: tuple[int, int]) -> int:
res = 0
if n[0] < self.start[0]:
res += self.start[0] - n[0]
else:
res += n[0] - self.start[0]
if n[1] < self.start[1]:
res += self.start[1] - n[1]
else:
res += n[1] - self.start[1]
return res
def h(n: tuple[int, int]) -> int:
res = 0
if n[0] < self.end[0]:
res += self.end[0] - n[0]
else:
res += n[0] - self.end[0]
if n[1] < self.end[1]:
res += self.end[1] - n[1]
else:
res += n[1] - self.end[1]
return res
try:
return g(n) + h(n)
except Exception:
return 1000
def best_path(
self,
maze: np.ndarray,
actual: tuple[int, int],
last: str | None,
) -> dict[str, int]:
path = {
"N": (
self.f((actual[0], actual[1] - 1))
if not maze[actual[1]][actual[0]].get_north() and actual[1] > 0
else None
),
"E": (
self.f((actual[0] + 1, actual[1]))
if not maze[actual[1]][actual[0]].get_est()
and actual[0] < len(maze[0]) - 1
else None
),
"S": (
self.f((actual[0], actual[1] + 1))
if not maze[actual[1]][actual[0]].get_south()
and actual[1] < len(maze) - 1
else None
),
"W": (
self.f((actual[0] - 1, actual[1]))
if not maze[actual[1]][actual[0]].get_west() and actual[0] > 0
else None
),
}
return {
k: v
for k, v in sorted(path.items(), key=lambda item: item[0])
if v is not None and k != last
}
def get_opposit(self, dir: str) -> str:
match dir:
case "N":
return "S"
case "E":
return "W"
case "S":
return "N"
case "W":
return "E"
case _:
return ""
def get_next_pos(
self, dir: str, actual: tuple[int, int]
) -> tuple[int, int]:
match dir:
case "N":
return (actual[0], actual[1] - 1)
case "E":
return (actual[0] + 1, actual[1])
case "S":
return (actual[0], actual[1] + 1)
case "W":
return (actual[0] - 1, actual[1])
case _:
return actual
def get_path(self, maze: np.ndarray) -> str | None:
path = [(self.start, self.best_path(maze, self.start, None))]
visited = [self.start]
while len(path) > 0 and path[-1][0] != self.end:
if len(path[-1][1]) == 0:
path.pop(-1)
if len(path) == 0:
break
k = next(iter(path[-1][1]))
path[-1][1].pop(k)
continue
while len(path[-1][1]) > 0:
next_pos = self.get_next_pos(
list(path[-1][1].keys())[0], path[-1][0]
)
if next_pos in visited:
k = next(iter(path[-1][1]))
path[-1][1].pop(k)
else:
break
if len(path[-1][1]) == 0:
path.pop(-1)
continue
pre = self.get_opposit(list(path[-1][1].keys())[0])
path.append(
(
next_pos,
self.best_path(maze, next_pos, pre),
)
)
visited += [next_pos]
if len(path) == 0:
return None
path[-1] = (self.end, {})
return "".join(
str(list(c[1].keys())[0]) for c in path if len(c[1]) > 0
)
def solve(self, maze: Maze) -> str:
res = self.get_path(maze.get_maze())
if res is None:
raise Exception("Path not found")
return res
+7 -4
View File
@@ -1,7 +1,10 @@
from .classes.Cell import Cell
from .classes.Maze import Maze
from .MazeGenerator import MazeGenerator
from .Cell import Cell
from .Maze import Maze
from .MazeGenerator import MazeGenerator, DepthFirstSearch
from .MazeGenerator import Kruskal
from .MazeSolver import MazeSolver, AStar
__version__ = "1.0.0"
__author__ = "us"
__all__ = ["Cell", "Maze", "MazeGenerator"]
__all__ = ["Cell", "Maze", "MazeGenerator",
"MazeSolver", "AStar", "Kruskal", "DepthFirstSearch"]
+122
View File
@@ -0,0 +1,122 @@
from src.amaz_lib.MazeGenerator import DepthFirstSearch, Kruskal
from src.amaz_lib.MazeSolver import AStar
class DataMaze:
@staticmethod
def get_file_data(name_file: str) -> str:
with open(name_file, "r") as file:
data = file.read()
if data == "":
raise ValueError("The file is empty")
return data
@staticmethod
def transform_data(data: str) -> dict:
tmp = data.split("\n")
tmp2 = [value.split("=", 1) for value in tmp if "=" in value]
data_t = {value[0]: value[1] for value in tmp2}
return data_t
@staticmethod
def verif_key_data(data: dict) -> None:
key_test = {
"WIDTH",
"HEIGHT",
"ENTRY",
"EXIT",
"OUTPUT_FILE",
"PERFECT",
"GENERATOR",
"SOLVER",
}
set_key = {key for key in data.keys()}
if len(set_key) != len(key_test):
raise KeyError("Missing some data the len do not correspond")
res_key = {key for key in set_key if key not in key_test}
if len(res_key) != 0:
raise KeyError(
"Some Key " f"do not correspond the keys: {res_key}"
)
@staticmethod
def convert_values(data: dict):
key_int = {"WIDTH", "HEIGHT"}
key_tuple = {"ENTRY", "EXIT"}
key_bool = {"PERFECT"}
res: dict = {}
for key in key_int:
res.update({key: int(data[key])})
for key in key_tuple:
res.update({key: DataMaze.convert_tuple(data[key])})
for key in key_bool:
res.update({key: DataMaze.convert_bool(data[key])})
res.update({"OUTPUT_FILE": data["OUTPUT_FILE"]})
res.update(
DataMaze.get_solver_generator(data, res["ENTRY"], res["EXIT"])
)
return res
@staticmethod
def get_solver_generator(data: dict, entry: int, exit: int) -> dict:
available_generator = {
"Kruskal": Kruskal,
"DFS": DepthFirstSearch,
}
available_solver = {
"AStar": AStar,
}
res = {}
res["GENERATOR"] = available_generator[data["GENERATOR"]]()
res["SOLVER"] = available_solver[data["SOLVER"]](entry, exit)
return res
@staticmethod
def convert_tuple(data: str) -> tuple:
data_t = data.split(",")
if len(data_t) != 2:
raise ValueError(
"There is too much " "argument in the coordinate given"
)
x, y = data_t
tup = (int(x), int(y))
return tup
@staticmethod
def convert_bool(data: str) -> bool:
if data != "True" and data != "False":
raise ValueError("This is not True or False")
if data == "True":
return True
return False
@staticmethod
def get_data_maze(name_file: str) -> dict:
try:
data_str = DataMaze.get_file_data(name_file)
data_dict = DataMaze.transform_data(data_str)
DataMaze.verif_key_data(data_dict)
data_maze = DataMaze.convert_values(data_dict)
return {k.lower(): v for k, v in data_maze.items()}
except FileNotFoundError:
print("The file do not exist")
exit()
except PermissionError:
print("We dont have the Permission")
exit()
except ValueError as e:
print(f"Error during the convert or the file is empty: {e}")
exit()
except KeyError as e:
print(f"Error on the key in the file: {e}")
exit()
except IndexError as e:
print(
"In the function transform Data some data cannot "
f"be splited by '=' because '=' was not present: {e}"
)
exit()
except AttributeError as e:
print("Error on the " f"funciton get_data_maze : {e}")
exit()
+6
View File
@@ -0,0 +1,6 @@
__version__ = "1.0.0"
__author__ = "mteriier, dgaillet"
from .Parsing import DataMaze
__all__ = ["DataMaze"]
+32 -21
View File
@@ -1,23 +1,34 @@
7D53BFD3D57951517D1D
3D12C3903BD03AD4178D
2BAEBEEEAA92EED547C9
2287ED17AAAC5393FFF0
6C6951292A87D2AEBD30
37D43E8686E93AABAB8C
21516D2D47FEE8284049
6C7857C3FB9116C696D8
751453D6D2AAC57BE970
3BA952D17EA83BD05470
22AAD2907BAE86967B74
2AA83C2EFC69696FBC35
686EE96FD7D4783FAD21
7ED17ED3D57D3EC52FA0
7B943D16FB7BABD3AFC8
7407C5297EB82EB84174
392D53C6912EE9447E9D
62A952BBAAC13EFD7B89
3AAC3EC6EABAAD557824
66C7C7D7D6C6C7D556CD
BBBBBB97D397BBBB917BBD15513D17
84684003BAA946AAA854696D3EEBC3
C112D2AC28443D06EAB9103945507A
BEAED283E857C3AD52AEAEAC7D5452
87C53EAEBC393C4154012D29553956
A95147EBAD6AEBB87D2EC386D52853
86D4517AC17C50443B813AABD1443E
EBD1787850513A9506AAEAAC3A93EB
B8543850787EEAAB87EC3EC3C2A852
AEBD443AD4517EC6ED3D2D3EB8687E
838553AC7BD2BD3BBD43EB85069457
EAC57843D2B86D4407D0106943C7BB
D01552B856C4553BC556AC783E97C2
92C7D6C29557F96AFFFD6D16850512
E83D15382D3BFC7857FD39696907EA
BEAD6D46ABC2FFFAFFF96AD2D2C57A
87ABD13BC6D293FAFD50547C3C3D3E
C168128455106EFAFFFABD17EBA907
9056AEC7B92ABBBAD15407ABD2C2C3
EAD1691786E8044296952D06B8147A
BEB87EAD053E87D6ED07812BAE8796
87AAD5412B87C7957BEBEAAC2D07EB
C3C2D55286857905169456E9438796
D07EBBD287A97EAB8507957E944507
96BD0692AD445146C7EBC55503D3AB
C16D2BEAC3D514553D52BD53AE92EA
B8552C12BE97AB952D104796C52E92
C47D016AABC16869456AD5413BAD6A
D113AED2C292D03ED53ABD52800392
D6EC457C7C6C7EC57D446D56EEEC6E
1,1
16,15
29,29
SSEESSEESWSEESSSESSWSWWWWSSESSSWSEENEENESEEEESWSWSEESSSSEEEENNEESEENEEENNWNNWNNEENNENENESEESWSSESSESWSSSSWWSSSEESSESEN
+31
View File
@@ -0,0 +1,31 @@
import pytest
from amaz_lib.Cell import Cell
def test_cell_setter_getter() -> None:
cell = Cell(value=0)
cell.set_north(True)
assert cell.get_north() is True
cell.set_north(False)
assert cell.get_north() is False
cell.set_est(True)
assert cell.get_est() is True
cell.set_est(False)
assert cell.get_est() is False
cell.set_south(True)
assert cell.get_south() is True
cell.set_south(False)
assert cell.get_south() is False
cell.set_west(True)
assert cell.get_west() is True
cell.set_west(False)
assert cell.get_west() is False
cell.set_value(8)
assert cell.get_value() == 8
cell.set_value(0)
assert cell.get_value() == 0
+27
View File
@@ -0,0 +1,27 @@
from amaz_lib.MazeGenerator import DepthFirstSearch
from amaz_lib.Cell import Cell
import numpy as np
class TestDepth:
def test_init_maze(self) -> None:
maze = DepthFirstSearch.init_maze(10, 10)
cell = Cell(value=15)
maze[1][1].set_est(False)
assert maze[0][0].value == cell.value
def test_rand_cells(self) -> None:
w_h = (10, 10)
lst = np.zeros((10, 10), dtype=bool)
lst[0, 0] = True
rand_cells = DepthFirstSearch.random_cells(lst, (0, 1), w_h)
assert len(rand_cells) == 2
def test_next_cell(self) -> None:
coord = (5, 4)
x, y = coord
assert DepthFirstSearch.next_cell(x, y, "N") == (2, 3)
def test_reverse_path(self) -> None:
assert DepthFirstSearch.reverse_path("N") == "S"
+31
View File
@@ -0,0 +1,31 @@
import numpy
from amaz_lib.Cell import Cell
from amaz_lib.Maze import Maze
def test_maze_setter_getter() -> None:
maze = Maze(numpy.array([]))
test = numpy.array(
[
[Cell(value=6), Cell(value=8), Cell(value=11)],
[Cell(value=6), Cell(value=8), Cell(value=11)],
[Cell(value=6), Cell(value=8), Cell(value=11)],
]
)
maze.set_maze(test)
assert numpy.array_equal(maze.get_maze(), test) is True
def test_maze_str() -> None:
test = numpy.array(
[
[Cell(value=6), Cell(value=8), Cell(value=11)],
[Cell(value=6), Cell(value=8), Cell(value=11)],
[Cell(value=6), Cell(value=8), Cell(value=11)],
]
)
maze = Maze(test)
assert maze.__str__() == "68B\n68B\n68B\n"
+14
View File
@@ -0,0 +1,14 @@
import numpy
from amaz_lib.MazeGenerator import DepthFirstSearch
class TestMazeGenerator:
def test_generator(self) -> None:
w_h = (300, 300)
maze = numpy.array([])
generator = DepthFirstSearch().generator(*w_h)
for output in generator:
maze = output
assert maze.shape == w_h
+19
View File
@@ -0,0 +1,19 @@
from amaz_lib.Cell import Cell
import numpy as np
from amaz_lib import AStar, Maze, MazeSolver
def test_solver() -> None:
maze = Maze(
np.array(
[
[Cell(value=13), Cell(value=3), Cell(value=11)],
[Cell(value=9), Cell(value=4), Cell(value=6)],
[Cell(value=12), Cell(value=5), Cell(value=7)],
]
)
)
print(maze)
solver = AStar((1, 1), (3, 3))
res = solver.solve(maze)
assert res == "ESWSEE"
+78
View File
@@ -0,0 +1,78 @@
from parsing.Parsing import DataMaze
import pytest
class TestParsing:
def test_get_data_valid(self):
data = DataMaze.get_file_data("tests/test_txt/config_1.txt")
assert isinstance(data, str) is True
def test_file_error(self):
with pytest.raises(FileNotFoundError):
DataMaze.get_file_data("tete")
# def test_permission_error(self):
# with pytest.raises(PermissionError):
# DataMaze.get_file_data("tests/test_txt/error_1.txt")
def test_empty_file_error(self):
with pytest.raises(ValueError):
DataMaze.get_file_data("tests/test_txt/error_6.txt")
def test_transform_data_valid(self):
data = DataMaze.get_file_data("tests/test_txt/config_1.txt")
data_2 = DataMaze.transform_data(data)
assert isinstance(data_2, dict)
def test_transform__index_error(self):
with pytest.raises(IndexError):
DataMaze.transform_data("asdasdasdasdasdasda\nasdasdas=asdasd")
def test_key_data_error(self):
with pytest.raises(KeyError):
data = DataMaze.get_file_data("tests/test_txt/error_8.txt")
data2 = DataMaze.transform_data(data)
DataMaze.verif_key_data(data2)
def test_key_data_error_2(self):
with pytest.raises(KeyError):
data = DataMaze.get_file_data("tests/test_txt/error_9.txt")
data2 = DataMaze.transform_data(data)
DataMaze.verif_key_data(data2)
def test_convert_int(self):
with pytest.raises(ValueError):
data = DataMaze.get_file_data("tests/test_txt/error_2.txt")
data2 = DataMaze.transform_data(data)
DataMaze.convert_values(data2)
def test_tuple_error(self):
with pytest.raises(ValueError):
DataMaze.convert_tuple("0,3,5,5")
def test_tuple_error1(self):
with pytest.raises(AttributeError):
DataMaze.convert_tuple(None)
def test_bool_error(self):
with pytest.raises(ValueError):
DataMaze.convert_bool("Trueeee")
def test_valid_tuple(self):
assert DataMaze.convert_tuple("7534564654, 78") == (7534564654, 78)
def test_valid_bool(self):
assert DataMaze.convert_bool("False") is False
def test_valid_bool1(self):
assert DataMaze.convert_bool("True") is True
def test_data_maze(self):
data = DataMaze.get_data_maze("tests/test_txt/config_1.txt")
assert data["WIDTH"] == 200
assert data["HEIGHT"] == 100
assert data["ENTRY"] == (0, 0)
assert data["EXIT"] == (19, 14)
assert data["OUTPUT_FILE"] == "maze.txt"
assert data["PERFECT"] is True
+6
View File
@@ -0,0 +1,6 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
+6
View File
@@ -0,0 +1,6 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
+6
View File
@@ -0,0 +1,6 @@
WIDTH=caca
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
View File
+4
View File
@@ -0,0 +1,4 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
+7
View File
@@ -0,0 +1,7 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
PIPI=tut
Generated
+77
View File
@@ -20,6 +20,7 @@ dependencies = [
dev = [
{ name = "flake8" },
{ name = "mypy" },
{ name = "pytest" },
]
[package.metadata]
@@ -32,6 +33,7 @@ requires-dist = [
dev = [
{ name = "flake8", specifier = ">=7.3.0" },
{ name = "mypy", specifier = ">=1.19.1" },
{ name = "pytest", specifier = ">=9.0.2" },
]
[[package]]
@@ -43,6 +45,27 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "exceptiongroup"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
]
[[package]]
name = "flake8"
version = "7.3.0"
@@ -57,6 +80,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" },
]
[[package]]
name = "iniconfig"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
]
[[package]]
name = "librt"
version = "0.8.1"
@@ -353,6 +385,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/57/a7/b35835e278c18b85206834b3aa3abe68e77a98769c59233d1f6300284781/numpy-2.4.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4b42639cdde6d24e732ff823a3fa5b701d8acad89c4142bc1d0bd6dc85200ba5", size = 12504685, upload-time = "2026-03-09T07:58:50.525Z" },
]
[[package]]
name = "packaging"
version = "26.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
]
[[package]]
name = "pathspec"
version = "1.0.4"
@@ -362,6 +403,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" },
]
[[package]]
name = "pluggy"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]]
name = "pycodestyle"
version = "2.14.0"
@@ -513,6 +563,33 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" },
]
[[package]]
name = "pygments"
version = "2.19.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
]
[[package]]
name = "pytest"
version = "9.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "pygments" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
]
[[package]]
name = "tomli"
version = "2.4.0"