how can I code this?

Hello everyone, A friend has given me this scenerio

"Imagine a grid of pixels, all can be one of three colours, say blue, red and green, You start with every pixel having a random colour of those 3. The colours evolve in time steps according to very simple rule, namely: The colour of the after the time step depends on it's 4 immediate neighbors. And the colours have cyclic relationship, say blue beats red, red beats green and green beats blue. Like rock, paper, scissors So for example, if the pixel is red and it has a blue neighbor, it will become blue next turn? The question is, what is the outcome for this system? What does the time evolution looks like?"

I know memory addresses, I know loops and statements and I know arrays but I have no idea how to code something like that? Any help or what syntax I should use?
closed account (Dy7SLyTq)
should be simple enough with sdl or sfml.
When you said final outcome, I was thinking " when all pixels become the same color ", but this can never happen because the colours are cyclic as mentioned.

So outcome will depend totally on the starting colours.
You can use this simple header:

http://www.cplusplus.com/articles/Eyhv0pDG/

I've found it extremely helpful... and I'm actually thinking about writing your program!! It looks like it would be fun to watch... All the colors changing based on awsomness... my god I want to write it!!


well, first, you will want to set up a grid, or buffer, to hold your "colors". How you rstore your colors is up to you. You will also need to fill this buffer randomly and display it.

Second, you will have to be able to take one element of this buffer, and be able to get any of it's nieghbors. Depending on the buffer width (which will also depend on your console width. I suggest you make the width variable), you will need to calculate this.

third: simple switch statements to take action.
Thanks everyone, I'm trying to wrap my head around the idea. I'm just trying to figure out how to get one color to see the one next to it and do something about it. Like IF neighboring color is BLUE change color. But I don't know.

Another problem is when learning...I cant find a medium between the basics and writing actual guis with running bools and compensating for every scenerio that leaves me basically watching them mindlessly.
Last edited on
Yes, that's interesting. This is my first attempt:
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <stdafx.h>
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>

#include <string.h>
#include <stdlib.h>
#include <time.h>

using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")

HWND                hWnd;

const int upd_time = 10;

const int size = 5;
const int h = 50;
const int w = 50;
const int count = h * w;

int rgb_map[count]; // 0 = red, 1 = green, 2 = blue

const int change_map[] = { 1, 2, 0 }; // red -> green, green -> blue, blue -> red

VOID OnPaint(HDC hdc)
{
  Graphics graphics(hdc);
  for(int i = 0; i < count; ++i)
  {
    SolidBrush solidBrush(Color((0 == rgb_map[i]) ? 255 : 0
      , (1 == rgb_map[i]) ? 255 : 0
      , (2 == rgb_map[i]) ? 255 : 0));

    graphics.FillRectangle(&solidBrush
      , (i % w) * size, (i / w) * size, size, size);
  }
}

void OnTimer() // Here the color changes (the rest is more or less windows stuff)
{
  int choose_map[count];
  int choose_count = count;

  for(int c = 0; c < choose_count; ++c)
  {
    choose_map[c] = c;
  }

  while(choose_count > 0)
  {
    const int sel_idx = choose_map[rand() % choose_count];
    --choose_count;
    choose_map[sel_idx] = choose_map[choose_count];
    
    const int x = (sel_idx % w);
    const int y = (sel_idx / w);
    const int env_idx[] =
    {
      y * w + x - 1
      , y * w + x + 1
      , (y - 1) * w + x
      , (y + 1) * w + x
    };
    const int env_count = sizeof(env_idx) / sizeof(*env_idx);
    for(int i = 0; i < env_count; ++i)
    {
      if(env_idx[i] < 0)
        ;
      else if(env_idx[i] < count)
      {
        if(change_map[rgb_map[sel_idx]] == rgb_map[env_idx[i]])
          rgb_map[env_idx[i]] = rgb_map[sel_idx];
      }
    }
  }
  InvalidateRect(hWnd, NULL, false);
}

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
  MSG                 msg;
  WNDCLASS            wndClass;
  GdiplusStartupInput gdiplusStartupInput;
  ULONG_PTR           gdiplusToken;

  srand (time(NULL));

  for(int i = 0; i < count; ++i)
  {
    rgb_map[i] = rand() % 3;
  }

  // Initialize GDI+.
  GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
   
  wndClass.style          = CS_HREDRAW | CS_VREDRAW;
  wndClass.lpfnWndProc    = WndProc;
  wndClass.cbClsExtra     = 0;
  wndClass.cbWndExtra     = 0;
  wndClass.hInstance      = hInstance;
  wndClass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
  wndClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  wndClass.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
  wndClass.lpszMenuName   = NULL;
  wndClass.lpszClassName  = TEXT("ColorGame");
   
  RegisterClass(&wndClass);
   
  hWnd = CreateWindow(
    TEXT("ColorGame"),   // window class name
    TEXT("Color Game"),  // window caption
    WS_OVERLAPPEDWINDOW,      // window style
    CW_USEDEFAULT,            // initial x position
    CW_USEDEFAULT,            // initial y position
    CW_USEDEFAULT,            // initial x size
    CW_USEDEFAULT,            // initial y size
    NULL,                     // parent window handle
    NULL,                     // window menu handle
    hInstance,                // program instance handle
    NULL);                    // creation parameters
	  
  ShowWindow(hWnd, iCmdShow);
  UpdateWindow(hWnd);

  SetTimer(hWnd, 1, upd_time, (TIMERPROC) NULL);

  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
   
  GdiplusShutdown(gdiplusToken);
  return msg.wParam;
}  // WinMain

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, 
   WPARAM wParam, LPARAM lParam)
{
  HDC          hdc;
  PAINTSTRUCT  ps;
   
  switch(message)
  {
  case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    OnPaint(hdc);
    EndPaint(hWnd, &ps);
    return 0;

  case WM_TIMER:
    OnTimer();
    return 0;

  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  default:
    return DefWindowProc(hWnd, message, wParam, lParam);
  }
} // WndProc 
[EDIT]somewhat improved with height and width

It's somehow hypnotizing...
Last edited on
> I'm just trying to figure out how to get one color to see the one next to it and do something about it.
> Like IF neighboring color is BLUE change color. But I don't know.

If the colour is grid[i][j], the four neighbouring colours are:
grid[i-1][j] grid[i+1][j] grid[i][j-1] grid[i][j+i]

(Pixels on the corners would have just two neighbours; ones on the edges would have three).


> Another problem is when learning...
> I cant find a medium between the basics and writing actual guis

If you have mastered the principles of programming, learning how to use a library is painless. To learn programming, a gui or graphics library is not a pre-requisite.

For instance, the programming logic for this problem does not require any gui; with stdin and stdout, it would look something like this.

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <iostream>
#include <random>
#include <ctime>
#include <vector>
#include <algorithm>
#include <iterator>

enum colour_t { GREEN=0, RED=1, BLUE=2, BORDER_COLOUR = -1 };

// blue beats red, red beats green and green beats blue
bool less( colour_t pixel, colour_t neighbour )
{
    if( neighbour == BORDER_COLOUR ) return false ;
    else return (neighbour-pixel) == 1 || (neighbour-pixel) == -2 ;
}

std::ostream& operator<< ( std::ostream& stm, colour_t c )
{
    static constexpr char names[] = { '+', 'G', 'R', 'B' } ;
    return stm << names[c+1] ;
}

colour_t random_colour()
{
    static constexpr colour_t clrs[] = { GREEN, RED, BLUE } ;
    static std::mt19937 eng( std::time(nullptr) ) ;
    static std::uniform_int_distribution<int> dist(0,2) ;
    return clrs[ dist(eng) ] ;
}

using grid_type = std::vector< std::vector<colour_t> > ;

std::ostream& operator<< ( std::ostream& stm, const grid_type& grid )
{
    for( auto& row : grid )
    {
        for( auto c : row ) std::cout << c ;
        stm << '\n' ;
    }
    return stm ;
}

colour_t next( const grid_type& grid, std::size_t i, std::size_t j )
{
    colour_t clr = grid[i][j] ;
    if( clr == BORDER_COLOUR ) return BORDER_COLOUR ;
    else
    {
        for( int k : { j-1, j+1 } )
            if( less( clr, grid[i][k] ) ) return grid[i][k] ;
        for( int k : { i-1, i+1 } )
            if( less( clr, grid[k][j] ) ) return grid[k][j] ;
    }
    return clr ;
}

grid_type& transform( grid_type& grid )
{
    const auto cpy = grid ;

    for( std::size_t i = 0 ; i < grid.size() ; ++i )
        for( std::size_t j = 0 ; j < grid[i].size() ; ++j )
            grid[i][j] = next( cpy, i, j ) ;

    return grid ;
}

grid_type make_grid( std::size_t rows, std::size_t cols )
{
    rows += 2 ;
    cols += 2 ;

    grid_type grid(rows) ;
    for( auto& row : grid )
    {
        std::generate_n( std::back_inserter(row), cols, random_colour ) ;
        row.front() = row.back() = BORDER_COLOUR ;
    }
    std::fill_n( std::begin( grid.front() ), cols, BORDER_COLOUR ) ;
    std::fill_n( std::begin( grid.back() ), cols, BORDER_COLOUR ) ;

    return grid ;
}

int main()
{
    std::size_t rows ; std::cout << "rows? " ; std::cin >> rows ;
    std::size_t cols ; std::cout << "cols? " ; std::cin >> cols ;

    grid_type grid = make_grid( rows, cols ) ;
    std::vector< grid_type > gens ;

    while( std::find( gens.rbegin(), gens.rend(), grid ) == gens.rend() )
    {
        std::cout << grid << '\n' ;
        gens.push_back(grid) ;
        transform(grid) ;
    }

    const auto rbegin = gens.rbegin() ;
    std::cout << "cycle of length "
               << std::find( rbegin, gens.rend(), grid ) - rbegin + 1 << '\n' ;
}

http://ideone.com/rTIxac

Once you have got this much working (tested, debugged etc.), if you so feel you can then undertake the slightly tedious and repetitive (and from a purely "learning to program in C++" perspective, largely fruitless) task of using a gui library to display the results.
@op

Well, if you want to see a nieghbor, think about it. A line of X width. You know that that element +/- 1 is 2 of it's nieghbors, so now you just need the top and bottom nieghbors. To do this, you can add the value of the current elements index to the width of a line (number of characters in a line) subract 1 (because we want to start from 0, not one), and if that is less than the total size of the container, then we have that element.

Another way is to use a 2d container. a vector would work, and that's even easier. To find the top and bottom, just go to the next 'lines' and reference the same index as the color you're working on.

....0..1...2..3..4...5
0 [x][x][x][x][x][x]
1 [x][x][x][x][x][x]
2 [x][x][x][x][x][x]

Think about it.
Topic archived. No new replies allowed.