Browse Source

Refonte du code pour préciser les objectifs de chaque classe et séparer leurs tâches

les classes game et tube servent à décrire et modifier les données du modèle du jeu
la classe drawer s'occupe d'afficher le jeu dans la page web via les méthodes fournies par la librairie p5js
la classe controller s'occupe de la logique interne aux régles du jeu
la classe main sert à déclarer le controller ainsi que les méthodes appelées par la librairie p5js
master
Figg 7 months ago
parent
commit
e7ea88f832
8 changed files with 243 additions and 178 deletions
  1. 8
    7
      index.html
  2. 120
    38
      js/controller.js
  3. 25
    29
      js/drawer.js
  4. 0
    102
      js/game.js
  5. 0
    0
      js/lib/p5.min.js
  6. 16
    0
      js/main.js
  7. 67
    0
      js/model/game.js
  8. 7
    2
      js/model/tube.js

+ 8
- 7
index.html View File

@@ -4,13 +4,14 @@
4 4
 <head>
5 5
 	<meta charset="utf-8">
6 6
 	<meta name="viewport" content="width=device-width, initial-scale=1.0">
7
-	<title>p5.js example</title>
7
+	<title>Le jeu des tubes là</title>
8 8
 	<link href="./css/style.css" rel="stylesheet">
9
-	<script src="./js/p5.min.js"></script>
10
-	<script src="./js/tube.js"></script>
11
-	<script src="./js/game.js"></script>
9
+	<script src="./js/lib/p5.min.js"></script>
10
+	<script src="./js/model/tube.js"></script>
11
+	<script src="./js/model/game.js"></script>
12 12
 	<script src="./js/drawer.js"></script>
13 13
 	<script src="./js/controller.js"></script>
14
+	<script src="./js/main.js"></script>
14 15
 </head>
15 16
 
16 17
 <body>
@@ -28,10 +29,10 @@
28 29
 			<input type="number" size="5" id="padding" value="10">
29 30
 		</menuitem>
30 31
 		<menuitem>
31
-			<label>Tube Size</label>
32
-			<input type="number" size="5" id="tbSize" value="50">
32
+			<label>Tube Scale</label>
33
+			<input type="number" size="5" id="scale" value="50">
33 34
 		</menuitem>
34
-		<button type="button" onclick="newGame()">New game</button>
35
+		<button type="button" onclick="controller.initializeGame()">New game</button>
35 36
 	</menu>
36 37
 	<main oncontextmenu="return false;">
37 38
 	</main>

+ 120
- 38
js/controller.js View File

@@ -1,50 +1,132 @@
1
-function setup()
1
+class Controller
2 2
 {
3
-	newGame();
4
-}
3
+	#game;
4
+	#drawer;
5
+	#colorsBank = ['black','silver','gray','maroon','red','purple','fuchsia','green','lime','olive','yellow','navy','blue','teal','aqua'];
6
+	
7
+	constructor()
8
+	{
9
+		this.initializeGame();
10
+	}
11
+	
12
+	initializeGame() {
13
+		let params = this.gatherMenuValues();
14
+		
15
+		this.game = new Game(params.TUBESNUMBERS, params.TUBESLEVELS);
16
+		this.drawer = new Drawer(params.PADDING, params.SCALE);
17
+		
18
+		this.drawer.computeGameParams(params.TUBESNUMBERS, params.TUBESLEVELS);
19
+		
20
+		this.initializeColorTubes(params.TUBESLEVELS - 1);
21
+		
22
+		this.needUpdate = true;
23
+	}
5 24
 
6
-function newGame() {
7
-	let params = gatherMenuValues();
25
+	gatherMenuValues()
26
+	{
27
+		let inputTubesNumbers = parseInt(document.getElementById("tbNumber").value);
28
+		let inputTubesLevels = parseInt(document.getElementById("tbLevel").value);
29
+		let inputScale = parseInt(document.getElementById("scale").value);
30
+		let inputPadding = parseInt(document.getElementById("padding").value);
31
+		
32
+		return {
33
+			TUBESNUMBERS: inputTubesNumbers,
34
+			TUBESLEVELS: inputTubesLevels,
35
+			SCALE: inputScale,
36
+			PADDING: inputPadding
37
+		};
38
+	}
8 39
 	
9
-	this.game = new Game(params.TUBESNUMBERS, params.TUBESLEVELS);
10
-	this.drawer = new Drawer(params.PADDING);
40
+	initializeColorTubes(LayersPerTube)
41
+	{
42
+		let nbTubes = this.game.tubesNumber() - 1;
43
+		let allColors = [];
44
+		
45
+		for (let i = 0; i < nbTubes; i++)
46
+		{
47
+			let coloridx = i % this.#colorsBank.length;
48
+			for (let times = 0; times < LayersPerTube; times++)
49
+			{
50
+				allColors.push(this.#colorsBank[coloridx]);
51
+			}
52
+		}
53
+		
54
+		for (let index = allColors.length - 1; index >= 0; index--) {
55
+			let randomIndex = Math.floor(Math.random() * (index + 1));
56
+			let tubeIndex = Math.floor(index / LayersPerTube);
57
+			
58
+			this.game.tubeAt(tubeIndex).addColorLayer(allColors[randomIndex]);
59
+			
60
+			allColors[randomIndex] = allColors[index];
61
+		}
62
+	}
11 63
 	
12
-	this.drawer.setTubesParams(params.TUBESNUMBERS, params.TUBESLEVELS, params.TUBESIZE);
64
+	clickTube(tubeIndex)
65
+	{
66
+		let _clickedTube = this.game.tubeAt(tubeIndex);
67
+		if (_clickedTube == null) return;
68
+		
69
+		if (_clickedTube == this.game.selectedTube())
70
+			this.game.unselectTube();
71
+		else if (this.canPourInto(this.game.selectedTube(), _clickedTube))
72
+		{
73
+			this.pourColorInto(this.game.selectedTube(), _clickedTube);
74
+			this.game.unselectTube();
75
+		}
76
+		else if (!_clickedTube.isEmpty())
77
+			this.game.selectTubeAt(tubeIndex);
78
+	}
13 79
 	
14
-	this.needUpdate = true;
15
-}
16
-
17
-function mousePressed(e) 
18
-{
19
-	let tubeId = this.drawer.getTubeIdAt(mouseX, mouseY);
80
+	canPourInto(sourceTube, targetTube)
81
+	{
82
+		return sourceTube != null && targetTube != null
83
+			&& sourceTube != targetTube
84
+			&& (targetTube.isEmpty() || sourceTube.peekTopColor() == targetTube.peekTopColor())
85
+			&& !targetTube.isFull();
86
+	}
20 87
 	
21
-	if (tubeId != -1)
88
+	pourColorInto(sourceTube, targetTube)
22 89
 	{
23
-		this.game.selectTube(tubeId);
90
+		while (this.canPourInto(sourceTube, targetTube))
91
+		{
92
+			targetTube.addColorLayer(sourceTube.removeColorLayer());
93
+		}
94
+		
95
+		this.checkTubeCompletion(sourceTube);
96
+		this.checkTubeCompletion(targetTube);
24 97
 	}
25 98
 	
26
-	this.needUpdate = true;
27
-}
28
-
29
-function gatherMenuValues()
30
-{
31
-	let inputTubesNumbers = parseInt(document.getElementById("tbNumber").value);
32
-	let inputTubesLevels = parseInt(document.getElementById("tbLevel").value);
33
-	let inputTubeSize = parseInt(document.getElementById("tbSize").value);
34
-	let inputPadding = parseInt(document.getElementById("padding").value);
35
-	
36
-	return {
37
-		TUBESNUMBERS: inputTubesNumbers,
38
-		TUBESLEVELS: inputTubesLevels,
39
-		TUBESIZE: inputTubeSize,
40
-		PADDING: inputPadding
41
-	};
42
-}
43
-function draw()
44
-{
45
-	if (!this.needUpdate) return;
99
+	checkTubeCompletion(tube)
100
+	{
101
+		if (tube.isComplete())
102
+		{
103
+			this.game.removeTube(tube);
104
+			this.checkGameCompletion();
105
+		}
106
+	}
46 107
 	
47
-	this.drawer.draw(this.game);
108
+	checkGameCompletion()
109
+	{
110
+		if (this.game.tubesNumber() == 1 && this.game.tubeAt(0).isEmpty())
111
+		{
112
+			this.game.clean();
113
+		}
114
+	}
115
+
116
+	mousePressed(e) 
117
+	{
118
+		let clickedTubeId = this.drawer.getTubeIdAt(mouseX, mouseY);
119
+		this.clickTube(clickedTubeId);
120
+		
121
+		this.needUpdate = true;
122
+	}
48 123
 	
49
-	this.needUpdate = false;
124
+	runLoop()
125
+	{
126
+		if (!this.needUpdate) return;
127
+		
128
+		this.drawer.draw(this.game);
129
+		
130
+		this.needUpdate = false;
131
+	}
50 132
 }

+ 25
- 29
js/drawer.js View File

@@ -1,64 +1,60 @@
1 1
 class Drawer
2 2
 {
3
-	#canvasWidth
4
-	#canvasHeight
3
+	#canvas;
5 4
 	
6
-	constructor(_padding)
5
+	constructor(_padding, _scale)
7 6
 	{
8 7
 		this.padding = _padding;
8
+		this.scale = _scale;
9 9
 		
10
-		createCanvas(0, 0);
10
+		this.#canvas = createCanvas(0, 0);
11 11
 	}
12 12
 	
13
-	setTubesParams(_tubesNumbers, _tubeLevels, _tubeSize)
13
+	computeGameParams(_tubesNumbers, _tubeLevels)
14 14
 	{
15
-		this.tubesNumbers = _tubesNumbers;
16
-		this.tubeLevels = _tubeLevels;
17
-		this.tubeSize = _tubeSize;
15
+		let canvasWidth = _tubesNumbers * (this.scale + this.padding) + this.padding;
16
+		let canvasHeight = 2 * this.padding + (_tubeLevels+1) * this.scale;
18 17
 		
19
-		this.#canvasWidth = this.tubesNumbers * (this.tubeSize + this.padding) + this.padding;
20
-		this.#canvasHeight = 2 * this.padding + (this.tubeLevels+1) * this.tubeSize;
21
-		
22
-		resizeCanvas(this.#canvasWidth, this.#canvasHeight);
18
+		resizeCanvas(canvasWidth, canvasHeight);
23 19
 	}
24 20
 	
25 21
 	draw(game)
26 22
 	{
27
-		let tubes = game.tubes;
28
-		let selectedTube = game.selectedTube;
29
-		
30
-		background('white');
23
+		background('orange');
31 24
 		
32
-		this.drawTubes(this.padding, this.padding+this.tubeSize, tubes, selectedTube);
25
+		this.drawTubes(this.padding, this.padding+this.scale, game);
33 26
 	}
34 27
 
35
-	drawTubes(x, y, tubes, selectedTube)
28
+	drawTubes(x, y, game)
36 29
 	{
37 30
 		let tubeX = x;
38 31
 		let tubeY = y;
39 32
 		let selectionOffset = 0;
40 33
 		
41
-		tubes.forEach(tube => {
42
-			selectionOffset = (tube == selectedTube ? this.tubeSize : 0);
34
+		for (let i = 0; i < game.tubesNumber(); i++)
35
+		{
36
+			let tube = game.tubeAt(i);
37
+			selectionOffset = (tube == game.selectedTube() ? this.scale : 0);
43 38
 			
44 39
 			this.drawTube(tubeX, tubeY - selectionOffset, tube);
45
-			tubeX += this.padding + this.tubeSize;
46
-		});
40
+			tubeX += this.padding + this.scale;
41
+		}
47 42
 	}
48 43
 
49 44
 	drawTube(x, y, tube)
50 45
 	{
46
+		let tubeLevels = tube.height();
51 47
 		
52
-		y += (this.tubeLevels-1) * this.tubeSize;
48
+		y += (tubeLevels-1) * this.scale;
53 49
 		
54
-		for(let i = 0; i < this.tubeLevels; i++)
50
+		for(let i = 0; i < tubeLevels; i++)
55 51
 		{
56 52
 			color = tube.getColorAtLevel(i);
57 53
 			color == null ? noFill() : fill(color);
58 54
 			
59 55
 			if (i >= 0)
60 56
 			{
61
-				rect(x, y - i * this.tubeSize, this.tubeSize);
57
+				rect(x, y - i * this.scale, this.scale);
62 58
 			}
63 59
 		}
64 60
 	}
@@ -67,15 +63,15 @@ class Drawer
67 63
 	{
68 64
 		if (!this.isInboundsCanvas(x,y)) return -1;
69 65
 		
70
-		let idWithPadding = (x - this.padding) / (this.tubeSize + this.padding);
71
-		return idWithPadding % 1 > 1 - (this.padding / (this.tubeSize + this.padding)) ? -1 : int(idWithPadding);
66
+		let idWithPadding = (x - this.padding) / (this.scale + this.padding);
67
+		return idWithPadding % 1 > 1 - (this.padding / (this.scale + this.padding)) ? -1 : int(idWithPadding);
72 68
 	}
73 69
 	
74 70
 	isInboundsCanvas(x, y)
75 71
 	{
76 72
 		return x >= this.padding
77 73
 			&& y >= this.padding
78
-			&& x < this.#canvasWidth - this.padding
79
-			&& y < this.#canvasHeight - this.padding;
74
+			&& x < this.#canvas.width - this.padding
75
+			&& y < this.#canvas.height - this.padding;
80 76
 	}
81 77
 }

+ 0
- 102
js/game.js View File

@@ -1,102 +0,0 @@
1
-class Game {
2
-	#colorsBank = ['black','silver','gray','maroon','red','purple','fuchsia','green','lime','olive','yellow','navy','blue','teal','aqua'];
3
-	
4
-	constructor(nbTubes, tubeLevel)
5
-	{
6
-		this.tubes = [];
7
-		this.selectedTube = null;
8
-		
9
-		for (let i = 0; i < nbTubes; i++)
10
-		{
11
-			this.tubes.push(new Tube(tubeLevel));
12
-		}
13
-		
14
-		this.initializeColorTubes(tubeLevel);
15
-	}
16
-	
17
-	/*	The goal is to have each tube filled with its own color. Thus, there
18
-		is (tubes minus one) different colors divided in (tubeLevel) layers
19
-		mixed in the tubes.
20
-		One tube is empty to allow movement.
21
-	*/
22
-	initializeColorTubes(tubeLevel)
23
-	{
24
-		let nbTubes = this.tubes.length - 1;
25
-		let allColors = [];
26
-		
27
-		for (let i = 0; i < nbTubes; i++)
28
-		{
29
-			let coloridx = i % this.#colorsBank.length;
30
-			for (let times = 0; times < tubeLevel-1; times++)
31
-			{
32
-				allColors.push(this.#colorsBank[coloridx]);
33
-			}
34
-		}
35
-		
36
-		for (let i = allColors.length - 1; i > 0; i--) {
37
-			let j = Math.floor(Math.random() * (i + 1));
38
-			let temp = allColors[i];
39
-			allColors[i] = allColors[j];
40
-			allColors[j] = temp;
41
-		}
42
-		
43
-		for (let index = 0; index < allColors.length; index++)
44
-		{
45
-			let tubeIndex = Math.floor(index/(tubeLevel-1));
46
-			this.tubes[tubeIndex].addColorLayer(allColors[index]);
47
-		}
48
-	}
49
-	
50
-	selectTube(tubeId)
51
-	{
52
-		let newSelectedTube = this.tubes[tubeId];
53
-		
54
-		if (this.selectedTube == newSelectedTube)
55
-			this.selectedTube = null;
56
-		else if (this.canPourInto(this.selectedTube, newSelectedTube))
57
-			this.pourColorInto(this.selectedTube, newSelectedTube);
58
-		else if (!newSelectedTube.isEmpty())
59
-			this.selectedTube = newSelectedTube;
60
-	}
61
-	
62
-	canPourInto(sourceTube, targetTube)
63
-	{
64
-		return sourceTube != null && targetTube != null
65
-			&& sourceTube != targetTube
66
-			&& (targetTube.isEmpty() || sourceTube.peekTopColor() == targetTube.peekTopColor())
67
-			&& !targetTube.isFull();
68
-	}
69
-	
70
-	pourColorInto(sourceTube, targetTube)
71
-	{
72
-		while (this.canPourInto(sourceTube, targetTube))
73
-		{
74
-			targetTube.addColorLayer(sourceTube.removeColorLayer());
75
-		}
76
-		
77
-		this.checkTubeCompletion(sourceTube);
78
-		this.checkTubeCompletion(targetTube);
79
-	}
80
-	
81
-	checkTubeCompletion(tube)
82
-	{
83
-		if (tube.isComplete()) 
84
-		{
85
-			let tubeIndex = this.tubes.indexOf(tube);
86
-			
87
-			this.tubes.splice(tubeIndex, 1);
88
-			
89
-			if (this.selectedTube == tube) this.selectedTube = null;
90
-			
91
-			this.checkGameCompletion();
92
-		}
93
-	}
94
-	
95
-	checkGameCompletion()
96
-	{
97
-		if (this.tubes.length == 1 && this.tubes[0].isEmpty())
98
-		{
99
-			this.tubes = [];
100
-		}
101
-	}
102
-}

js/p5.min.js → js/lib/p5.min.js View File


+ 16
- 0
js/main.js View File

@@ -0,0 +1,16 @@
1
+let controller;
2
+
3
+function setup()
4
+{
5
+	controller = new Controller();
6
+}
7
+
8
+function draw()
9
+{
10
+	controller.runLoop();
11
+}
12
+
13
+function mousePressed(e)
14
+{
15
+	controller.mousePressed(e);
16
+}

+ 67
- 0
js/model/game.js View File

@@ -0,0 +1,67 @@
1
+class Game {
2
+	#tubes;
3
+	#selectedTube;
4
+	
5
+	constructor(nbTubes, tubeLevel)
6
+	{
7
+		this.#tubes = [];
8
+		this.#selectedTube = null;
9
+		
10
+		for (let i = 0; i < nbTubes; i++)
11
+		{
12
+			this.#tubes.push(new Tube(tubeLevel));
13
+		}
14
+	}
15
+	
16
+	tubeAt(tubeIndex)
17
+	{
18
+		if (!this.isInRange(tubeIndex)) return null;
19
+		
20
+		return this.#tubes[tubeIndex];
21
+	}
22
+	
23
+	selectedTube()
24
+	{
25
+		return this.#selectedTube;
26
+	}
27
+	
28
+	selectTubeAt(index)
29
+	{
30
+		if (this.isInRange(index))
31
+		{
32
+			this.#selectedTube = this.#tubes[index];
33
+		}
34
+	}
35
+	
36
+	removeTube(tube)
37
+	{
38
+		let tubeIndex = this.#tubes.indexOf(tube);
39
+		
40
+		if (tubeIndex != -1)
41
+		{
42
+			let removed = this.#tubes.splice(tubeIndex, 1)[0];
43
+			if (removed = this.#selectedTube) this.unselectTube();
44
+		}
45
+	}
46
+	
47
+	clean()
48
+	{
49
+		this.#tubes = []
50
+		this.unselectTube();
51
+	}
52
+	
53
+	unselectTube()
54
+	{
55
+		this.#selectedTube = null;
56
+	}
57
+	
58
+	tubesNumber()
59
+	{
60
+		return this.#tubes.length;
61
+	}
62
+	
63
+	isInRange(index)
64
+	{
65
+		return index >= 0 && index < this.#tubes.length;
66
+	}
67
+}

js/tube.js → js/model/tube.js View File

@@ -28,6 +28,11 @@ class Tube {
28 28
 		this.#colors = [];
29 29
 	}
30 30
 	
31
+	height()
32
+	{
33
+		return this.#maxLevels;
34
+	}
35
+	
31 36
 	isFull()
32 37
 	{
33 38
 		return this.#colors.length == this.#maxLevels;
@@ -38,7 +43,7 @@ class Tube {
38 43
 		return this.#colors.length == 0;
39 44
 	}
40 45
 	
41
-	emptySpaceSize()
46
+	remainingSpace()
42 47
 	{
43 48
 		return this.#maxLevels - this.#colors.length;
44 49
 	}
@@ -59,7 +64,7 @@ class Tube {
59 64
 
60 65
 	isComplete()
61 66
 	{
62
-		if (this.emptySpaceSize() != 1) return false;
67
+		if (this.remainingSpace() != 1) return false;
63 68
 		
64 69
 		let reference = this.#colors[0];
65 70
 		

Loading…
Cancel
Save