Skip to content

Commit c8ab93a

Browse files
théo dubthéo dub
théo dub
authored and
théo dub
committedMay 17, 2024
copy from my Gitea
0 parents  commit c8ab93a

25 files changed

+687
-0
lines changed
 

‎.DS_Store

6 KB
Binary file not shown.

‎.idea/.gitignore

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎.idea/aws.xml

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎.idea/misc.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎.idea/modules.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎.idea/tetris-optimizer.iml

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Tetris-optimizer
2+
Develop a program that receives only one argument, a path to a text file which will contain a list of tetrominoes and assemble them in order to create the smallest square possible.
3+
## Run
4+
```
5+
chmod +x test.sh
6+
./test.sh
7+
8+
or
9+
10+
go run . goodexample00.txt | cat -e
11+
```

‎board.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package main
2+
3+
import "fmt"
4+
5+
type board [][]byte
6+
7+
/*
8+
----------------------------------- MAKE BOARD ------------------------------------
9+
10+
The method "makeBoard" creates a new array of the given size filled with dots.
11+
12+
\----------------------------------------------------------------------------------
13+
*/
14+
func makeBoard(size int) board {
15+
res := make([][]byte, size)
16+
for i := range res {
17+
res[i] = make([]byte, size)
18+
for j := range res[i] {
19+
res[i][j] = dot
20+
}
21+
}
22+
return res
23+
}
24+
25+
/*
26+
-------------------------- PRINT ------------------------
27+
28+
The method "print" prints the board.
29+
30+
\--------------------------------------------------------
31+
*/
32+
func (b board) print() {
33+
for i := range b {
34+
fmt.Println(string(b[i]))
35+
}
36+
}
37+
38+
/*
39+
------------------------------------ CHECK ------------------------------------
40+
41+
The method "check" checks if a tetrimino can be placed in a specific
42+
position on the board.
43+
44+
\-------------------------------------------------------------------------------
45+
*/
46+
func (b board) check(i, j int, t tetrimino) bool {
47+
for l := range t {
48+
for x := range t[l] {
49+
if t[l][x] == hashTag {
50+
if i+l >= len(b) || j+x >= len(b) {
51+
return false
52+
}
53+
if b[i+l][j+x] != dot {
54+
return false
55+
}
56+
}
57+
}
58+
}
59+
return true
60+
}
61+
62+
/*
63+
------------------------------------ PUT ------------------------------------
64+
65+
The method "put" places a tetrimino in a specific position on the board.
66+
67+
\----------------------------------------------------------------------------
68+
*/
69+
func (b board) put(i, j, idx int, t tetrimino) {
70+
for y := range t {
71+
for x := range t[y] {
72+
if t[y][x] == hashTag {
73+
b[i+y][j+x] = byte(idx + 'A')
74+
}
75+
}
76+
}
77+
}
78+
79+
/*
80+
-------------------------------------- REMOVE ------------------------------------
81+
82+
The method "remove" removes a tetrimino from a specific position on the board.
83+
84+
\---------------------------------------------------------------------------------
85+
*/
86+
func (b board) remove(i, j int, t tetrimino) {
87+
for y := range t {
88+
for x := range t[y] {
89+
if t[y][x] == hashTag {
90+
b[i+y][j+x] = dot
91+
}
92+
}
93+
}
94+
}

‎examples/badexample.txt

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
...#
2+
...#
3+
...#
4+
...#
5+
....
6+
....
7+
....
8+
####
9+
10+
11+
.###
12+
...#
13+
....
14+
....
15+
16+
....
17+
..##
18+
.##.
19+
....

‎examples/badexample00.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
####
2+
...#
3+
....
4+
....

‎examples/badexample01.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
...#
2+
..#.
3+
.#..
4+
#...

‎examples/badexample02.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
...#
2+
...#
3+
#...
4+
#...

‎examples/badexample03.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
....
2+
....
3+
....
4+
....

‎examples/badexample04.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
..##
2+
....
3+
....
4+
##..

‎examples/goodexample00.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
....
2+
.##.
3+
.##.
4+
....

‎examples/goodexample01.txt

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
...#
2+
...#
3+
...#
4+
...#
5+
6+
....
7+
....
8+
....
9+
####
10+
11+
.###
12+
...#
13+
....
14+
....
15+
16+
....
17+
..##
18+
.##.
19+
....

‎examples/goodexample02.txt

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
...#
2+
...#
3+
...#
4+
...#
5+
6+
....
7+
....
8+
....
9+
####
10+
11+
.###
12+
...#
13+
....
14+
....
15+
16+
....
17+
..##
18+
.##.
19+
....
20+
21+
....
22+
.##.
23+
.##.
24+
....
25+
26+
....
27+
....
28+
##..
29+
.##.
30+
31+
##..
32+
.#..
33+
.#..
34+
....
35+
36+
....
37+
###.
38+
.#..
39+
....

‎examples/goodexample03.txt

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
....
2+
.##.
3+
.##.
4+
....
5+
6+
...#
7+
...#
8+
...#
9+
...#
10+
11+
....
12+
..##
13+
.##.
14+
....
15+
16+
....
17+
.##.
18+
.##.
19+
....
20+
21+
....
22+
..#.
23+
.##.
24+
.#..
25+
26+
.###
27+
...#
28+
....
29+
....
30+
31+
##..
32+
.#..
33+
.#..
34+
....
35+
36+
....
37+
..##
38+
.##.
39+
....
40+
41+
##..
42+
.#..
43+
.#..
44+
....
45+
46+
.#..
47+
.##.
48+
..#.
49+
....
50+
51+
....
52+
###.
53+
.#..
54+
....

‎examples/hardexam.txt

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
....
2+
.##.
3+
.##.
4+
....
5+
6+
.#..
7+
.##.
8+
.#..
9+
....
10+
11+
....
12+
..##
13+
.##.
14+
....
15+
16+
....
17+
.##.
18+
.##.
19+
....
20+
21+
....
22+
..#.
23+
.##.
24+
.#..
25+
26+
.###
27+
...#
28+
....
29+
....
30+
31+
##..
32+
.#..
33+
.#..
34+
....
35+
36+
....
37+
.##.
38+
.##.
39+
....
40+
41+
....
42+
..##
43+
.##.
44+
....
45+
46+
##..
47+
.#..
48+
.#..
49+
....
50+
51+
.#..
52+
.##.
53+
..#.
54+
....
55+
56+
....
57+
###.
58+
.#..
59+
....

‎go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module tetris-optimizer
2+
3+
go 1.19

‎main.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
)
7+
8+
func main() {
9+
10+
// check if the Os Args format is valid
11+
if len(os.Args) != 2 {
12+
fmt.Println("Wrong Usage !")
13+
return
14+
}
15+
16+
// read file
17+
filePath := "examples/" + os.Args[1] // chemin d'accès au dossier "examples"
18+
data, err := os.ReadFile(filePath)
19+
if err != nil {
20+
fmt.Println("Erreur de format de fichier !")
21+
return
22+
}
23+
24+
// check pieces format
25+
ok, tetriminos := ValidationFile(data)
26+
if !ok {
27+
fmt.Println("Error! ")
28+
return
29+
}
30+
31+
// solve
32+
solution := Solve(tetriminos)
33+
34+
// print solution
35+
solution.print()
36+
}

‎solver.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package main
2+
3+
/*
4+
----------------------------------- RECURSION ------------------------------------
5+
6+
The "recursion" function recursively places tetrominos on the board, searching
7+
for a valid position for each piece. If it finds a solution, it returns true; otherwise,
8+
it continues the search after removing the tetromino.
9+
10+
\----------------------------------------------------------------------------------
11+
*/
12+
func recursion(b board, array []tetrimino, idx int) bool {
13+
if idx == len(array) {
14+
return true
15+
}
16+
for i := range b {
17+
for j := range b[i] {
18+
if b.check(i, j, array[idx]) {
19+
b.put(i, j, idx, array[idx])
20+
if recursion(b, array, idx+1) {
21+
return true
22+
}
23+
b.remove(i, j, array[idx])
24+
}
25+
}
26+
}
27+
return false
28+
}
29+
30+
/*
31+
-------------------------------------- SOLVE ------------------------------------
32+
33+
The “solve” function takes an array of tetriminos and returns a board with the solution.
34+
It begins with a board of minimum size to fit all tetriminos, then uses the “recursion” function to place them.
35+
If successful, it returns the board; if not, it enlarges the board and retries until a solution is found.
36+
37+
\--------------------------------------------------------------------------------
38+
*/
39+
func Solve(array []tetrimino) board {
40+
var res board
41+
square := 2
42+
for square*square < len(array)*4 {
43+
square += 1
44+
}
45+
for done := false; !done; {
46+
res = makeBoard(square)
47+
done = recursion(res, array, 0)
48+
square += 1
49+
}
50+
return res
51+
}

‎test.sh

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/bash
2+
3+
go run . badexample00.txt | cat -e
4+
echo
5+
6+
go run . badexample01.txt | cat -e
7+
echo
8+
9+
go run . badexample02.txt | cat -e
10+
echo
11+
12+
go run . badexample03.txt | cat -e
13+
echo
14+
15+
go run . badexample04.txt | cat -e
16+
echo
17+
18+
go run . badexample.txt | cat -e
19+
echo
20+
21+
go run . goodexample00.txt | cat -e
22+
echo
23+
24+
go run . goodexample01.txt | cat -e
25+
echo
26+
27+
go run . goodexample02.txt | cat -e
28+
echo
29+
30+
go run . goodexample03.txt | cat -e
31+
echo
32+
33+
go run . hardexam.txt | cat -e
34+
echo

‎tetriminos.go

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package main
2+
3+
type tetrimino [4][]byte
4+
5+
var validUint16Map = map[uint16]bool{ // map of valid tetriminos
6+
0x8888: true,
7+
0xf000: true,
8+
0xcc00: true,
9+
0xe400: true,
10+
0x4c40: true,
11+
0x4e00: true,
12+
0x8c80: true,
13+
0x88c0: true,
14+
0xe800: true,
15+
0xc440: true,
16+
0x2e00: true,
17+
0x44c0: true,
18+
0x8e00: true,
19+
0xc880: true,
20+
0xe200: true,
21+
0x6c00: true,
22+
0x8c40: true,
23+
0xc600: true,
24+
0x4c80: true,
25+
}
26+
27+
/*
28+
----------------------------- IS EMPTY ROW -------------------------------
29+
30+
The method "isEmptyRow" checks if a row is empty by checking if all the cells
31+
in the row are empty.
32+
33+
\------------------------------------------------------------------------------
34+
*/
35+
36+
func (t tetrimino) isEmptyRow(row int) bool {
37+
res := true
38+
for i := 0; i < 4; i++ {
39+
res = res && t[row][i] == dot
40+
}
41+
return res
42+
}
43+
44+
/*
45+
---------------------------- IS EMPTY COLUMN --------------------------
46+
47+
The method "isEmptyColumn" works similarly but for columns.
48+
49+
\------------------------------------------------------------------------
50+
*/
51+
52+
func (t tetrimino) isEmptyColumn(column int) bool {
53+
res := true
54+
for i := 0; i < 4; i++ {
55+
res = res && t[i][column] == dot
56+
}
57+
return res
58+
}
59+
60+
/*
61+
------------------------------- TO UINT 16 -----------------------------
62+
63+
The method "toUint16" converts a tetrimino to a uint16 by iterating over each
64+
cell and using a bit shift operation to keep the state of each cell (filled or
65+
empty).
66+
67+
---------------------------------------------------------------------------
68+
*/
69+
70+
func (t tetrimino) toUint16() uint16 {
71+
var res uint16 = 0
72+
for i := 0; i < 4; i++ {
73+
for j := 0; j < 4; j++ {
74+
res <<= 1
75+
if t[i][j] == hashTag {
76+
res |= 1
77+
}
78+
}
79+
}
80+
return res
81+
}
82+
83+
/*
84+
--------------------------------- IS VALID --------------------------------
85+
86+
The method "isValid" uses the "validUint16Map" variable to check if a tetrimino
87+
is valid by using the uint16 value obtained by the "toUint16" method.
88+
89+
\--------------------------------------------------------------------------------
90+
*/
91+
92+
func (t tetrimino) isValid() bool {
93+
return validUint16Map[t.toUint16()]
94+
}
95+
96+
/*
97+
--------------------------------BLOCK TO TETRI ---------------------------
98+
99+
This function takes a byte array as input, converts it to a tetrimino, removes
100+
empty columns and rows, and returns the final tetrimino that only contains
101+
# or . characters.
102+
103+
--------------------------------------------------------------------------------
104+
*/
105+
func blocktoTetri(b []byte) tetrimino {
106+
in := tetrimino{b[0:4], b[5:9], b[10:14], b[15:19]}
107+
out := tetrimino{
108+
{dot, dot, dot, dot},
109+
{dot, dot, dot, dot},
110+
{dot, dot, dot, dot},
111+
{dot, dot, dot, dot},
112+
}
113+
y, x := 0, 0
114+
for in.isEmptyRow(y) {
115+
y++
116+
}
117+
for in.isEmptyColumn(x) {
118+
x++
119+
}
120+
for i := 0; i+y < 4; i++ {
121+
for j := 0; j+x < 4; j++ {
122+
out[i][j] = in[i+y][j+x]
123+
}
124+
}
125+
return out
126+
}

‎validation.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package main
2+
3+
const blockSize = 20
4+
const dot = '.'
5+
const hashTag = '#'
6+
const newLine = '\n'
7+
8+
/*
9+
-------------------------------------- IS VALID BLOCK ---------------------------
10+
11+
The "isValidBlock" function checks a byte array "data" for validity, using a loop
12+
for each byte and a "switch" statement to classify characters as dots ('.'),
13+
hashtags ('#'), or line breaks ('\n'). It counts dots and hashtags,
14+
verifies the regularity of line breaks, and returns true if the conditions of
15+
12 dots and 4 hashtags are met, otherwise false.
16+
17+
--------------------------------------------------------------------------------
18+
*/
19+
20+
func isValidBlock(data []byte) bool {
21+
numDots, numHashtags := 0, 0
22+
for i := range data {
23+
switch data[i] {
24+
case dot:
25+
numDots++
26+
case hashTag:
27+
numHashtags++
28+
case newLine:
29+
if i%5 != 4 {
30+
return false
31+
}
32+
default:
33+
return false
34+
}
35+
}
36+
return numDots == 12 && numHashtags == 4
37+
}
38+
39+
/*
40+
-------------------------------------- VALIDATION FILE ---------------------------
41+
42+
The “ValidationFile” function checks a byte array “data” for valid tetriminos using a loop
43+
to process each 20-byte block with the “isValidBlock” function. It converts valid blocks to tetriminos,
44+
checks them with “isValid”, and adds to the “res” array if successful.
45+
The function returns a boolean “ok” indicating overall success and the “res” array,
46+
breaking early if any block fails validation.
47+
48+
--------------------------------------------------------------------------------
49+
*/
50+
51+
func ValidationFile(data []byte) (ok bool, res []tetrimino) {
52+
for i := 0; i < len(data); {
53+
if i+blockSize > len(data) {
54+
break
55+
}
56+
if !isValidBlock(data[i : i+blockSize]) {
57+
break
58+
}
59+
t := blocktoTetri(data[i : i+blockSize])
60+
if !t.isValid() {
61+
break
62+
}
63+
res = append(res, t)
64+
i += blockSize
65+
if i == len(data) {
66+
ok = true
67+
break
68+
}
69+
if data[i] != '\n' {
70+
break
71+
}
72+
i += 1
73+
}
74+
return ok, res
75+
}

0 commit comments

Comments
 (0)
Please sign in to comment.