Skip to content

Commit 74488a0

Browse files
committed
Add breakout design and fix getopt on macOS
New self-playing breakout demo with 3 rows of bricks, bouncing ball, and AI paddle. Colored mode with CGA palette via -C flag. Also fix getopt parsing for clock and breakout on macOS by including d: in design optstrings.
1 parent 027dd4d commit 74488a0

4 files changed

Lines changed: 220 additions & 2 deletions

File tree

pixelwall/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ OBJECTS = \
2424
design_life.o \
2525
design_cm5.o \
2626
design_text_arcade.o \
27-
design_clock.o
27+
design_clock.o \
28+
design_breakout.o
2829

2930
.PHONY: all
3031
all: $(PROGRAM)

pixelwall/design_breakout.c

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/*
2+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3+
Version 2, December 2004
4+
5+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
6+
7+
Everyone is permitted to copy and distribute verbatim or modified
8+
copies of this license document, and changing it is allowed as long
9+
as the name is changed.
10+
11+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
12+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
13+
14+
0. You just DO WHAT THE FUCK YOU WANT TO.
15+
*/
16+
17+
#include "pixelwall.h"
18+
19+
#define BRICK_ROWS 3
20+
#define BRICK_COLS 11
21+
#define PADDLE_ROW 14
22+
#define PADDLE_HALF 2
23+
24+
typedef struct {
25+
Color color;
26+
bool colorful;
27+
Color row_colors[BRICK_ROWS];
28+
Color ball_color;
29+
Color paddle_color;
30+
Pos ball;
31+
Pos direction;
32+
int paddle_x;
33+
bool bricks[BRICK_ROWS][BRICK_COLS];
34+
int bricks_remaining;
35+
} BreakoutData;
36+
37+
static void ResetBricks(BreakoutData *bd) {
38+
bd->bricks_remaining = BRICK_ROWS * BRICK_COLS;
39+
for (int r = 0; r < BRICK_ROWS; r++)
40+
for (int b = 0; b < BRICK_COLS; b++)
41+
bd->bricks[r][b] = true;
42+
}
43+
44+
static void ResetBall(BreakoutData *bd) {
45+
bd->ball = (Pos){11, 8};
46+
bd->direction = (Pos){(rand() % 2) ? 1 : -1, -1};
47+
}
48+
49+
// Get the left column of brick b (no gaps, all rows identical)
50+
static int BrickCol(int r, int b) {
51+
(void)r;
52+
return b * 2; // 0,2,4,6,8,10,12,14,16,18,20
53+
}
54+
55+
// Check if column col hits a brick in row r, return brick index or -1
56+
static int ColToBrick(int r, int col) {
57+
for (int b = 0; b < BRICK_COLS; b++) {
58+
int left = BrickCol(r, b);
59+
if (col == left || col == left + 1)
60+
return b;
61+
}
62+
return -1;
63+
}
64+
65+
static void PrintHelp() {
66+
printf(" -C Enable colored mode\n");
67+
printf(" -R <color> Brick row 1 color (default: 255,85,85)\n");
68+
printf(" -G <color> Brick row 2 color (default: 255,255,85)\n");
69+
printf(" -K <color> Brick row 3 color (default: 85,255,255)\n");
70+
printf(" -L <color> Ball color (default: 255,255,85)\n");
71+
printf(" -P <color> Paddle color (default: 255,255,255)\n");
72+
}
73+
74+
static void ParseOptions(BreakoutData *bd, int argc, char *argv[]) {
75+
int opt;
76+
optind = 1;
77+
while ((opt = getopt(argc, argv, ":d:CR:G:K:L:P:")) != -1) {
78+
switch (opt) {
79+
case 'C': bd->colorful = true; break;
80+
case 'R': bd->row_colors[0] = ParseColor(optarg); break;
81+
case 'G': bd->row_colors[1] = ParseColor(optarg); break;
82+
case 'K': bd->row_colors[2] = ParseColor(optarg); break;
83+
case 'L': bd->ball_color = ParseColor(optarg); break;
84+
case 'P': bd->paddle_color = ParseColor(optarg); break;
85+
}
86+
}
87+
}
88+
89+
static void *Create(Grid *grid, int argc, char *argv[]) {
90+
BreakoutData *bd = malloc(sizeof(BreakoutData));
91+
if (!bd) return NULL;
92+
93+
bd->color = GREEN;
94+
bd->colorful = false;
95+
// CGA palette colors (used when -c is enabled)
96+
bd->row_colors[0] = (Color){255, 85, 85, 255}; // CGA Light Red
97+
bd->row_colors[1] = (Color){255, 255, 85, 255}; // CGA Yellow
98+
bd->row_colors[2] = (Color){85, 255, 255, 255}; // CGA Light Cyan
99+
bd->ball_color = (Color){255, 255, 85, 255}; // CGA Yellow
100+
bd->paddle_color = (Color){255, 255, 255, 255}; // White
101+
102+
ParseOptions(bd, argc, argv);
103+
ResetBricks(bd);
104+
105+
srand(time(NULL));
106+
ResetBall(bd);
107+
bd->paddle_x = 11;
108+
109+
return bd;
110+
}
111+
112+
static void UpdateFrame(Grid *grid, void *data) {
113+
BreakoutData *bd = (BreakoutData *)data;
114+
Color bg = grid->conf.backgroundColor;
115+
116+
GridFillColor(grid, bg);
117+
118+
// Move ball
119+
int nx = bd->ball.x + bd->direction.x;
120+
int ny = bd->ball.y + bd->direction.y;
121+
122+
// Wall bounce left/right
123+
if (nx < 0 || nx > 21) {
124+
bd->direction.x *= -1;
125+
nx = bd->ball.x + bd->direction.x;
126+
}
127+
128+
// Wall bounce top
129+
if (ny < 0) {
130+
bd->direction.y *= -1;
131+
ny = bd->ball.y + bd->direction.y;
132+
}
133+
134+
// Brick collision: check if new position hits a brick
135+
if (ny >= 0 && ny < BRICK_ROWS) {
136+
int b = ColToBrick(ny, nx);
137+
if (b >= 0 && bd->bricks[ny][b]) {
138+
bd->bricks[ny][b] = false;
139+
bd->bricks_remaining--;
140+
bd->direction.y *= -1;
141+
ny = bd->ball.y + bd->direction.y;
142+
}
143+
}
144+
145+
// Paddle collision
146+
if (ny == PADDLE_ROW) {
147+
if (nx >= bd->paddle_x - PADDLE_HALF && nx <= bd->paddle_x + PADDLE_HALF) {
148+
bd->direction.y = -1;
149+
ny = bd->ball.y + bd->direction.y;
150+
}
151+
}
152+
153+
// Ball lost below paddle
154+
if (ny > PADDLE_ROW) {
155+
ResetBall(bd);
156+
nx = bd->ball.x;
157+
ny = bd->ball.y;
158+
} else {
159+
bd->ball.x = nx;
160+
bd->ball.y = ny;
161+
}
162+
163+
// Safety clamp
164+
if (bd->ball.x < 0) bd->ball.x = 0;
165+
if (bd->ball.x > 21) bd->ball.x = 21;
166+
if (bd->ball.y < 0) bd->ball.y = 0;
167+
if (bd->ball.y > PADDLE_ROW) bd->ball.y = PADDLE_ROW;
168+
169+
// AI paddle: move toward ball with slight randomness
170+
int jitter = (rand() % 3) - 1;
171+
int target = bd->ball.x + jitter;
172+
if (bd->paddle_x < target) bd->paddle_x++;
173+
if (bd->paddle_x > target) bd->paddle_x--;
174+
if (bd->paddle_x < PADDLE_HALF) bd->paddle_x = PADDLE_HALF;
175+
if (bd->paddle_x > 21 - PADDLE_HALF) bd->paddle_x = 21 - PADDLE_HALF;
176+
177+
// Draw bricks
178+
for (int r = 0; r < BRICK_ROWS; r++) {
179+
Color bc = bd->colorful ? bd->row_colors[r] : bd->color;
180+
for (int b = 0; b < BRICK_COLS; b++) {
181+
if (bd->bricks[r][b]) {
182+
int left = BrickCol(r, b);
183+
GridSetColor(grid, (Pos){left, r}, bc);
184+
GridSetColor(grid, (Pos){left + 1, r}, bc);
185+
}
186+
}
187+
}
188+
189+
// Draw paddle
190+
Color pc = bd->colorful ? bd->paddle_color : bd->color;
191+
for (int i = -PADDLE_HALF; i <= PADDLE_HALF; i++) {
192+
GridSetColor(grid, (Pos){bd->paddle_x + i, PADDLE_ROW}, pc);
193+
}
194+
195+
// Draw ball
196+
Color blc = bd->colorful ? bd->ball_color : bd->color;
197+
GridSetColor(grid, (Pos){bd->ball.x, bd->ball.y}, blc);
198+
199+
// Reset if all bricks destroyed
200+
if (bd->bricks_remaining == 0) {
201+
ResetBricks(bd);
202+
}
203+
}
204+
205+
static void Destroy(void *data) {
206+
free(data);
207+
}
208+
209+
Design breakoutDesign = {
210+
.name = "breakout",
211+
.PrintHelp = PrintHelp,
212+
.Create = Create,
213+
.UpdateFrame = UpdateFrame,
214+
.Destroy = Destroy,
215+
};

pixelwall/design_clock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static ClockConf defaultClockConf = {
5757
static void ParseOptions(ClockConf *conf, int argc, char *argv[]) {
5858
int opt;
5959
optind = 1;
60-
while ((opt = getopt(argc, argv, ":T:S:")) != -1) {
60+
while ((opt = getopt(argc, argv, ":d:T:S:")) != -1) {
6161
switch (opt) {
6262
case 'T': conf->digitColor = ParseColor(optarg); break;
6363
case 'S': conf->markerColor = ParseColor(optarg); break;

pixelwall/designs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern Design lifeDesign;
2626
extern Design cm5Design;
2727
extern Design arcadeDesign;
2828
extern Design clockDesign;
29+
extern Design breakoutDesign;
2930

3031
Design *designs[] = {
3132
&snakeDesign,
@@ -36,4 +37,5 @@ Design *designs[] = {
3637
&cm5Design,
3738
&arcadeDesign,
3839
&clockDesign,
40+
&breakoutDesign,
3941
};

0 commit comments

Comments
 (0)