Cyotek Development Bloghttps://devblog.cyotek.com/tag/2d/atom.xml2016-01-11T17:26:30ZRotating an array using C#urn:uuid:f85fc30f-d6e6-4b93-b0e6-d51cee6818b32015-12-24T10:06:49Z2015-12-24T10:06:49Z<p>I've recently been working on a number of small test programs
for the different sections which make up a game I'm planning on
writing. One of these test systems involved a series of
<a href="https://en.wikipedia.org/wiki/Polyomino" rel="external nofollow noopener">polyominoes</a> which I needed to rotate. Internally, the data
for these shapes are stored as a simple boolean array, which I
access as though <a href="/post/converting-2d-arrays-to-1d-and-accessing-as-either-2d-or-1d">it were two dimensions</a>.</p>
<p>One of the requirements was that the player needs to be able to
rotate these shapes at 90° intervals, and so there were two
ways I could have solved this</p>
<ul>
<li>Define pre-rotated versions of all shapes</li>
<li>Rotate the shapes on the fly</li>
</ul>
<p>Clearly, I went with option two otherwise there would be no need
for this article! I choose not to go with the pre-rotated
approach, as firstly I'm using a lot of shapes and creating up
to 4 versions of each of these is not really worthwhile, and
secondly I don't want to store them either, or have to care
which orientation is currently in use.</p>
<p>This article describes how to rotate a 2D array in fixed
90° intervals, and also how to rotate 1D arrays that
masquerade as 2D arrays.</p>
<blockquote>
<p>Note: The code in this article will only work with rectangle
arrays. I don't usually use jagged arrays, so this code has no
special provisions to work with them.</p>
</blockquote>
<figure class="screenshot" ><a href="https://images.cyotek.com/image/devblog/rotatearray.gif" class="gallery" title="A demonstration program rotating arrays representing tetrominoes" ><img src="https://images.cyotek.com/image/thumbnail/devblog/rotatearray.gif" alt="A demonstration program rotating arrays representing tetrominoes" decoding="async" loading="lazy" /></a><figcaption>A demonstration program rotating arrays representing tetrominoes</figcaption></figure><h2 id="creating-a-simple-sample">Creating a simple sample</h2>
<p>First up, we need an array to rotate. For the purposes of our
demo, we'll use the following array - note that the width and
the height of the array don't match.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">bool</span><span class="symbol">[</span><span class="symbol">,</span><span class="symbol">]</span> src<span class="symbol">;</span>

src <span class="symbol">=</span> <span class="keyword">new</span> <span class="keyword">bool</span><span class="symbol">[</span><span class="number">2</span><span class="symbol">,</span> <span class="number">3</span><span class="symbol">]</span><span class="symbol">;</span>

src<span class="symbol">[</span><span class="number">0</span><span class="symbol">,</span> <span class="number">0</span><span class="symbol">]</span> <span class="symbol">=</span> <span class="keyword">true</span><span class="symbol">;</span>
src<span class="symbol">[</span><span class="number">0</span><span class="symbol">,</span> <span class="number">1</span><span class="symbol">]</span> <span class="symbol">=</span> <span class="keyword">true</span><span class="symbol">;</span>
src<span class="symbol">[</span><span class="number">0</span><span class="symbol">,</span> <span class="number">2</span><span class="symbol">]</span> <span class="symbol">=</span> <span class="keyword">true</span><span class="symbol">;</span>
src<span class="symbol">[</span><span class="number">1</span><span class="symbol">,</span> <span class="number">2</span><span class="symbol">]</span> <span class="symbol">=</span> <span class="keyword">true</span><span class="symbol">;</span>
</pre>
</figure>
<p>We can visualize the contents of the array but dumping it in a
friendly fashion to the console</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> PrintArray<span class="symbol">(</span><span class="keyword">bool</span><span class="symbol">[</span><span class="symbol">,</span><span class="symbol">]</span> src<span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">int</span> width<span class="symbol">;</span>
 <span class="keyword">int</span> height<span class="symbol">;</span>

 width <span class="symbol">=</span> src<span class="symbol">.</span>GetUpperBound<span class="symbol">(</span><span class="number">0</span><span class="symbol">)</span><span class="symbol">;</span>
 height <span class="symbol">=</span> src<span class="symbol">.</span>GetUpperBound<span class="symbol">(</span><span class="number">1</span><span class="symbol">)</span><span class="symbol">;</span>

 <span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> row <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> row <span class="symbol">&lt;</span> height <span class="symbol">+</span> <span class="number">1</span><span class="symbol">;</span> row<span class="symbol">++</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> col <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> col <span class="symbol">&lt;</span> width <span class="symbol">+</span> <span class="number">1</span><span class="symbol">;</span> col<span class="symbol">++</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">char</span> c<span class="symbol">;</span>

 c <span class="symbol">=</span> src<span class="symbol">[</span>col<span class="symbol">,</span> row<span class="symbol">]</span> <span class="symbol">?</span> <span class="string">&#39;#&#39;</span> <span class="symbol">:</span> <span class="string">&#39;.&#39;</span><span class="symbol">;</span>

 Console<span class="symbol">.</span>Write<span class="symbol">(</span>c<span class="symbol">)</span><span class="symbol">;</span>
 <span class="symbol">}</span>

 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
 <span class="symbol">}</span>

 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
<span class="symbol">}</span>

PrintArray<span class="symbol">(</span>src<span class="symbol">)</span><span class="symbol">;</span>
</pre>
</figure>
<p>All of which provides the following stunning output</p>
<figure class="lang-text highlight"><figcaption><span>text</span></figcaption><pre class="code">
#.
#.
##
</pre>
</figure>
<h2 id="rotating-the-array-clockwise">Rotating the array clockwise</h2>
<figure class="screenshot" ><a href="https://images.cyotek.com/image/devblog/rotatearray-1a.png" class="gallery" title="The original program used to test rotating an array" ><img src="https://images.cyotek.com/image/thumbnail/devblog/rotatearray-1a.png" alt="The original program used to test rotating an array" decoding="async" loading="lazy" /></a><figcaption>The original program used to test rotating an array</figcaption></figure>
<p>This function will rotate an array 90° clockwise</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">bool</span><span class="symbol">[</span><span class="symbol">,</span><span class="symbol">]</span> RotateArrayClockwise<span class="symbol">(</span><span class="keyword">bool</span><span class="symbol">[</span><span class="symbol">,</span><span class="symbol">]</span> src<span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">int</span> width<span class="symbol">;</span>
 <span class="keyword">int</span> height<span class="symbol">;</span>
 <span class="keyword">bool</span><span class="symbol">[</span><span class="symbol">,</span><span class="symbol">]</span> dst<span class="symbol">;</span>

 width <span class="symbol">=</span> src<span class="symbol">.</span>GetUpperBound<span class="symbol">(</span><span class="number">0</span><span class="symbol">)</span> <span class="symbol">+</span> <span class="number">1</span><span class="symbol">;</span>
 height <span class="symbol">=</span> src<span class="symbol">.</span>GetUpperBound<span class="symbol">(</span><span class="number">1</span><span class="symbol">)</span> <span class="symbol">+</span> <span class="number">1</span><span class="symbol">;</span>
 dst <span class="symbol">=</span> <span class="keyword">new</span> <span class="keyword">bool</span><span class="symbol">[</span>height<span class="symbol">,</span> width<span class="symbol">]</span><span class="symbol">;</span>

 <span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> row <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> row <span class="symbol">&lt;</span> height<span class="symbol">;</span> row<span class="symbol">++</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> col <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> col <span class="symbol">&lt;</span> width<span class="symbol">;</span> col<span class="symbol">++</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">int</span> newRow<span class="symbol">;</span>
 <span class="keyword">int</span> newCol<span class="symbol">;</span>

 newRow <span class="symbol">=</span> col<span class="symbol">;</span>
 newCol <span class="symbol">=</span> height <span class="symbol">-</span> <span class="symbol">(</span>row <span class="symbol">+</span> <span class="number">1</span><span class="symbol">)</span><span class="symbol">;</span>

 dst<span class="symbol">[</span>newCol<span class="symbol">,</span> newRow<span class="symbol">]</span> <span class="symbol">=</span> src<span class="symbol">[</span>col<span class="symbol">,</span> row<span class="symbol">]</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>

 <span class="keyword">return</span> dst<span class="symbol">;</span>
<span class="symbol">}</span>
</pre>
</figure>
<p>How does it work? First we get the width and height of the array
using the <code>GetUpperBound</code> method of the <code>Array</code> class. As arrays
are zero based, we add <code>1</code> to each of these results, otherwise
the new array will be too small to hold the data.</p>
<p>Next, we create a new array - with the width and height ready
previously swapped, allowing us to correctly handle non-square
arrays.</p>
<p>Finally, we loop through each row and each column. For each
entry, we calculate the new row and column, then assign the
value from the source array to the transposed location in the
destination array</p>
<ul>
<li>To calculate the new row, we simply set the row to the
existing column value</li>
<li>To calculate the new column, we take the current row, add one
to it, then subtract that value from the original array's
height</li>
</ul>
<p>If we now call <code>RotateArrayClockwise</code> using our source array,
we'll get the following output</p>
<figure class="lang-text highlight"><figcaption><span>text</span></figcaption><pre class="code">
###
#..
</pre>
</figure>
<p>Perfect!</p>
<h2 id="rotating-the-array-anti-clockwise">Rotating the array anti-clockwise</h2>
<p>Rotating the array anti-clockwise (or counter clockwise
depending on your terminology) uses most of the same code as
previous, but the calculation for the new row and column is
slightly different</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
newRow <span class="symbol">=</span> width <span class="symbol">-</span> <span class="symbol">(</span>col <span class="symbol">+</span> <span class="number">1</span><span class="symbol">)</span><span class="symbol">;</span>
newCol <span class="symbol">=</span> row<span class="symbol">;</span>
</pre>
</figure>
<ul>
<li>To calculate the new row we take the current column, add one
to it, then subtract that value from the original array's
width</li>
<li>The new column is the current row</li>
</ul>
<p>Using our trusty source array, this is what we get</p>
<figure class="lang-text highlight"><figcaption><span>text</span></figcaption><pre class="code">
..#
###
</pre>
</figure>
<h2 id="rotating-1d-arrays">Rotating 1D arrays</h2>
<p>Rotating a 1D array follows the same principles outlined above,
with the following differences</p>
<ul>
<li>As the array has only a single dimension, you cannot get the
width and the height automatically - you must know these in
advance</li>
<li>When calculating the new index position using <a href="https://en.wikipedia.org/wiki/Row-major_order" rel="external nofollow noopener">row-major
order</a> remember that as the width and the height have been
swapped, the calculation will be something similar to
<code>newIndex = newRow * height + newCol</code></li>
</ul>
<p>The following functions show how I rotate a 1D boolean array.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">public</span> Polyomino RotateAntiClockwise<span class="symbol">(</span><span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">return</span> <span class="keyword">this</span><span class="symbol">.</span>Rotate<span class="symbol">(</span><span class="keyword">false</span><span class="symbol">)</span><span class="symbol">;</span>
<span class="symbol">}</span>

<span class="keyword">public</span> Polyomino RotateClockwise<span class="symbol">(</span><span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">return</span> <span class="keyword">this</span><span class="symbol">.</span>Rotate<span class="symbol">(</span><span class="keyword">true</span><span class="symbol">)</span><span class="symbol">;</span>
<span class="symbol">}</span>

<span class="keyword">private</span> Polyomino Rotate<span class="symbol">(</span><span class="keyword">bool</span> clockwise<span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">byte</span> width<span class="symbol">;</span>
 <span class="keyword">byte</span> height<span class="symbol">;</span>
 <span class="keyword">bool</span><span class="symbol">[</span><span class="symbol">]</span> result<span class="symbol">;</span>
 <span class="keyword">bool</span><span class="symbol">[</span><span class="symbol">]</span> matrix<span class="symbol">;</span>

 matrix <span class="symbol">=</span> <span class="keyword">this</span><span class="symbol">.</span>Matrix<span class="symbol">;</span>
 width <span class="symbol">=</span> <span class="keyword">this</span><span class="symbol">.</span>Width<span class="symbol">;</span>
 height <span class="symbol">=</span> <span class="keyword">this</span><span class="symbol">.</span>Height<span class="symbol">;</span>
 result <span class="symbol">=</span> <span class="keyword">new</span> <span class="keyword">bool</span><span class="symbol">[</span>matrix<span class="symbol">.</span>Length<span class="symbol">]</span><span class="symbol">;</span>

 <span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> row <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> row <span class="symbol">&lt;</span> height<span class="symbol">;</span> row<span class="symbol">++</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> col <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> col <span class="symbol">&lt;</span> width<span class="symbol">;</span> col<span class="symbol">++</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">int</span> index<span class="symbol">;</span>

 index <span class="symbol">=</span> row <span class="symbol">*</span> width <span class="symbol">+</span> col<span class="symbol">;</span>

 <span class="keyword">if</span> <span class="symbol">(</span>matrix<span class="symbol">[</span>index<span class="symbol">]</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">int</span> newRow<span class="symbol">;</span>
 <span class="keyword">int</span> newCol<span class="symbol">;</span>
 <span class="keyword">int</span> newIndex<span class="symbol">;</span>

 <span class="keyword">if</span> <span class="symbol">(</span>clockwise<span class="symbol">)</span>
 <span class="symbol">{</span>
 newRow <span class="symbol">=</span> col<span class="symbol">;</span>
 newCol <span class="symbol">=</span> height <span class="symbol">-</span> <span class="symbol">(</span>row <span class="symbol">+</span> <span class="number">1</span><span class="symbol">)</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="keyword">else</span>
 <span class="symbol">{</span>
 newRow <span class="symbol">=</span> width <span class="symbol">-</span> <span class="symbol">(</span>col <span class="symbol">+</span> <span class="number">1</span><span class="symbol">)</span><span class="symbol">;</span>
 newCol <span class="symbol">=</span> row<span class="symbol">;</span>
 <span class="symbol">}</span>

 newIndex <span class="symbol">=</span> newRow <span class="symbol">*</span> height <span class="symbol">+</span> newCol<span class="symbol">;</span>

 result<span class="symbol">[</span>newIndex<span class="symbol">]</span> <span class="symbol">=</span> <span class="keyword">true</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>

 <span class="keyword">return</span> <span class="keyword">new</span> Polyomino<span class="symbol">(</span>result<span class="symbol">,</span> height<span class="symbol">,</span> width<span class="symbol">)</span><span class="symbol">;</span>
<span class="symbol">}</span>
</pre>
</figure>
<h2 id="update-history">Update History</h2>
<ul>
<li>2015-12-24 - First published</li>
<li>2020-11-21 - Updated formatting</li>
</ul>

<p><small>
All content <a href="https://devblog.cyotek.com/copyright-and-trademarks">Copyright (c) by Cyotek Ltd</a> or its respective writers. Permission to reproduce news and web log entries and other RSS feed content in unmodified form without notice is granted provided they are not used to endorse or promote any products or opinions (other than what was expressed by the author) and without taking them out of context. Written permission from the copyright owner must be obtained for everything else.<br />Original URL of this content is https://devblog.cyotek.com/post/rotating-an-array-using-csharp .
</small></p>Richard Mosshttps://www.cyotek.com/richard.moss@cyotek.comConverting 2D arrays to 1D and accessing as either 2D or 1Durn:uuid:e8bd0586-1437-4700-a355-cd4b7dd309212016-01-11T17:26:30Z2012-04-11T09:29:13Z<p>While working on a recent gaming project, I was originally using
2D arrays to store information relating to the different levels
in the game. But when it came to loop through the contents of
these levels, it wasn't as straightforward to do a simple
<code>foreach</code> loop due to the multiple dimensions.</p>
<p>Instead, I changed the code so that the 2D data was stored in a
single dimension array. By using <a href="http://en.wikipedia.org/wiki/Row-major_order" rel="external nofollow noopener">row-major order</a> you can
calculate any position in 2D space and map it into the 1D array.
This then allows you to continue accessing the data using 2D
co-ordinates, but opens up 1D access too.</p>
<h2 id="defining-your-array">Defining your array</h2>
<p>Given the size of your 2D array, the 1D creation code is
trivial:</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
T<span class="symbol">[</span><span class="symbol">]</span> items <span class="symbol">=</span> <span class="keyword">new</span> T<span class="symbol">[</span>width <span class="symbol">*</span> height<span class="symbol">]</span><span class="symbol">;</span>
</pre>
</figure>
<h2 id="converting-2d-co-ordinates-into-1d-index">Converting 2D co-ordinates into 1D index</h2>
<p>Once your have your array, converting a 2D co-ordinate such as
<code>3, 4</code> into the correct index of your 1D array using row-major
order using the following formula:</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
y <span class="symbol">*</span> width <span class="symbol">+</span> x
</pre>
</figure>
<h2 id="converting-1d-index-into-2d-co-ordinates">Converting 1D index into 2D co-ordinates</h2>
<p>The calculation to convert a 1D index into a 2D co-ordinate is
fairly straightforward:</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
y <span class="symbol">=</span> index <span class="symbol">/</span> width<span class="symbol">;</span>
x <span class="symbol">=</span> index <span class="symbol">%</span> width<span class="symbol">;</span>
</pre>
</figure>
<h2 id="putting-it-together-the-arraymapt-class">Putting it together - the ArrayMap&lt;T&gt; class</h2>
<p>To avoid constantly having to repeat the calculations, I created
a generic <code>ArrayMap</code> class that I could use to store any data
type in a 1D array, and access the values using either indexes
or co-ordinates, as well as adding enumerable support. The class
is very straightforward to use:</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
ArrayMap<span class="symbol">&lt;</span><span class="keyword">int</span><span class="symbol">&gt;</span> grid<span class="symbol">;</span>
Size size<span class="symbol">;</span>
<span class="keyword">int</span> value<span class="symbol">;</span>

size <span class="symbol">=</span> <span class="keyword">new</span> Size<span class="symbol">(</span><span class="number">10</span><span class="symbol">,</span> <span class="number">10</span><span class="symbol">)</span><span class="symbol">;</span>
value <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span>
grid <span class="symbol">=</span> <span class="keyword">new</span> ArrayMap<span class="symbol">&lt;</span><span class="keyword">int</span><span class="symbol">&gt;</span><span class="symbol">(</span>size<span class="symbol">)</span><span class="symbol">;</span>

<span class="comment">// set values via 2D co-ordinates</span>
<span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> y <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> y <span class="symbol">&lt;</span> size<span class="symbol">.</span>Height<span class="symbol">;</span> y<span class="symbol">++</span><span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> x <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> x <span class="symbol">&lt;</span> size<span class="symbol">.</span>Width<span class="symbol">;</span> x<span class="symbol">++</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 grid<span class="symbol">[</span>x<span class="symbol">,</span> y<span class="symbol">]</span> <span class="symbol">=</span> value<span class="symbol">;</span>
 value<span class="symbol">++</span><span class="symbol">;</span>
 <span class="symbol">}</span>
<span class="symbol">}</span>

<span class="comment">// get values via 2D co-ordinates</span>
Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>grid<span class="symbol">[</span><span class="number">9</span><span class="symbol">,</span> <span class="number">0</span><span class="symbol">]</span><span class="symbol">)</span><span class="symbol">;</span> <span class="comment">// 9</span>
Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>grid<span class="symbol">[</span><span class="number">0</span><span class="symbol">,</span> <span class="number">9</span><span class="symbol">]</span><span class="symbol">)</span><span class="symbol">;</span> <span class="comment">// 90</span>
Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>grid<span class="symbol">[</span><span class="number">9</span><span class="symbol">,</span> <span class="number">9</span><span class="symbol">]</span><span class="symbol">)</span><span class="symbol">;</span> <span class="comment">// 99</span>

<span class="comment">// set values via indexes</span>
<span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> i <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> i <span class="symbol">&lt;</span> grid<span class="symbol">.</span>Count<span class="symbol">;</span> i<span class="symbol">++</span><span class="symbol">)</span>
 grid<span class="symbol">[</span>i<span class="symbol">]</span> <span class="symbol">=</span> i<span class="symbol">;</span>

<span class="comment">// get values via index</span>
Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>grid<span class="symbol">[</span><span class="number">9</span><span class="symbol">]</span><span class="symbol">)</span><span class="symbol">;</span> <span class="comment">// 9</span>
Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>grid<span class="symbol">[</span><span class="number">90</span><span class="symbol">]</span><span class="symbol">)</span><span class="symbol">;</span> <span class="comment">// 90</span>
Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>grid<span class="symbol">[</span><span class="number">99</span><span class="symbol">]</span><span class="symbol">)</span><span class="symbol">;</span> <span class="comment">// 99</span>

<span class="comment">// enumerate items</span>
<span class="keyword">foreach</span> <span class="symbol">(</span><span class="keyword">int</span> i <span class="keyword">in</span> grid<span class="symbol">)</span>
 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>i<span class="symbol">)</span><span class="symbol">;</span>

<span class="comment">// get index</span>
Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>grid<span class="symbol">.</span>GetItemIndex<span class="symbol">(</span><span class="number">9</span><span class="symbol">,</span> <span class="number">9</span><span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span> <span class="comment">// 99</span>

<span class="comment">// get location</span>
Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span>grid<span class="symbol">.</span>GetItemLocation<span class="symbol">(</span><span class="number">99</span><span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span> <span class="comment">// 9,9</span>
</pre>
</figure>
<p>Below is the full source to the class.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">using</span> System<span class="symbol">;</span>
<span class="keyword">using</span> System<span class="symbol">.</span>Collections<span class="symbol">;</span>
<span class="keyword">using</span> System<span class="symbol">.</span>Collections<span class="symbol">.</span>Generic<span class="symbol">;</span>

<span class="keyword">namespace</span> BinaryRealms<span class="symbol">.</span>Engine
<span class="symbol">{</span>
 <span class="keyword">public</span> <span class="keyword">class</span> ArrayMap<span class="symbol">&lt;</span>T<span class="symbol">&gt;</span> <span class="symbol">:</span> IEnumerable<span class="symbol">&lt;</span>T<span class="symbol">&gt;</span>
 <span class="symbol">{</span>
 <span class="keyword">private</span> T<span class="symbol">[</span><span class="symbol">]</span> _items<span class="symbol">;</span>
 <span class="keyword">private</span> Size _size<span class="symbol">;</span>

 <span class="keyword">public</span> ArrayMap<span class="symbol">(</span><span class="symbol">)</span>
 <span class="symbol">{</span> <span class="symbol">}</span>

 <span class="keyword">public</span> ArrayMap<span class="symbol">(</span><span class="keyword">int</span> width<span class="symbol">,</span> <span class="keyword">int</span> height<span class="symbol">)</span>
 <span class="symbol">:</span> <span class="keyword">this</span><span class="symbol">(</span><span class="keyword">new</span> Size<span class="symbol">(</span>width<span class="symbol">,</span> height<span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span> <span class="symbol">}</span>

 <span class="keyword">public</span> ArrayMap<span class="symbol">(</span>Size size<span class="symbol">)</span>
 <span class="symbol">:</span> <span class="keyword">this</span><span class="symbol">(</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">this</span><span class="symbol">.</span>Size <span class="symbol">=</span> size<span class="symbol">;</span>
 <span class="symbol">}</span>

 <span class="keyword">public</span> IEnumerator<span class="symbol">&lt;</span>T<span class="symbol">&gt;</span> GetEnumerator<span class="symbol">(</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">foreach</span> <span class="symbol">(</span>T item <span class="keyword">in</span> _items<span class="symbol">)</span>
 <span class="keyword">yield</span> <span class="keyword">return</span> item<span class="symbol">;</span>
 <span class="symbol">}</span>

 <span class="keyword">public</span> <span class="keyword">int</span> GetItemIndex<span class="symbol">(</span><span class="keyword">int</span> x<span class="symbol">,</span> <span class="keyword">int</span> y<span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">if</span> <span class="symbol">(</span>x <span class="symbol">&lt;</span> <span class="number">0</span> <span class="symbol">||</span> x <span class="symbol">&gt;=</span> <span class="keyword">this</span><span class="symbol">.</span>Size<span class="symbol">.</span>Width<span class="symbol">)</span>
 <span class="keyword">throw</span> <span class="keyword">new</span> IndexOutOfRangeException<span class="symbol">(</span><span class="string">&quot;X is out of range&quot;</span><span class="symbol">)</span><span class="symbol">;</span>
 <span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span>y <span class="symbol">&lt;</span> <span class="number">0</span> <span class="symbol">||</span> y <span class="symbol">&gt;=</span> <span class="keyword">this</span><span class="symbol">.</span>Size<span class="symbol">.</span>Height<span class="symbol">)</span>
 <span class="keyword">throw</span> <span class="keyword">new</span> IndexOutOfRangeException<span class="symbol">(</span><span class="string">&quot;Y is out of range&quot;</span><span class="symbol">)</span><span class="symbol">;</span>

 <span class="keyword">return</span> y <span class="symbol">*</span> <span class="keyword">this</span><span class="symbol">.</span>Size<span class="symbol">.</span>Width <span class="symbol">+</span> x<span class="symbol">;</span>
 <span class="symbol">}</span>

 <span class="keyword">public</span> <span class="keyword">int</span> GetItemIndex<span class="symbol">(</span>Point point<span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">return</span> <span class="keyword">this</span><span class="symbol">.</span>GetItemIndex<span class="symbol">(</span>point<span class="symbol">.</span>X<span class="symbol">,</span> point<span class="symbol">.</span>Y<span class="symbol">)</span><span class="symbol">;</span>
 <span class="symbol">}</span>

 <span class="keyword">public</span> Point GetItemLocation<span class="symbol">(</span><span class="keyword">int</span> index<span class="symbol">)</span>
 <span class="symbol">{</span>
 Point point<span class="symbol">;</span>

 <span class="keyword">if</span> <span class="symbol">(</span>index <span class="symbol">&lt;</span> <span class="number">0</span> <span class="symbol">||</span> index <span class="symbol">&gt;=</span> _items<span class="symbol">.</span>Length<span class="symbol">)</span>
 <span class="keyword">throw</span> <span class="keyword">new</span> IndexOutOfRangeException<span class="symbol">(</span><span class="string">&quot;Index is out of range&quot;</span><span class="symbol">)</span><span class="symbol">;</span>

 point <span class="symbol">=</span> <span class="keyword">new</span> Point<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
 point<span class="symbol">.</span>Y <span class="symbol">=</span> index <span class="symbol">/</span> <span class="keyword">this</span><span class="symbol">.</span>Size<span class="symbol">.</span>Width<span class="symbol">;</span>
 point<span class="symbol">.</span>X <span class="symbol">=</span> index <span class="symbol">%</span> <span class="keyword">this</span><span class="symbol">.</span>Size<span class="symbol">.</span>Width<span class="symbol">;</span>

 <span class="keyword">return</span> point<span class="symbol">;</span>
 <span class="symbol">}</span>

 <span class="keyword">public</span> <span class="keyword">int</span> Count
 <span class="symbol">{</span> <span class="keyword">get</span> <span class="symbol">{</span> <span class="keyword">return</span> _items<span class="symbol">.</span>Length<span class="symbol">;</span> <span class="symbol">}</span> <span class="symbol">}</span>

 <span class="keyword">public</span> Size Size
 <span class="symbol">{</span>
 <span class="keyword">get</span> <span class="symbol">{</span> <span class="keyword">return</span> _size<span class="symbol">;</span> <span class="symbol">}</span>
 <span class="keyword">set</span>
 <span class="symbol">{</span>
 _size <span class="symbol">=</span> value<span class="symbol">;</span>
 _items <span class="symbol">=</span> <span class="keyword">new</span> T<span class="symbol">[</span>_size<span class="symbol">.</span>Width <span class="symbol">*</span> _size<span class="symbol">.</span>Height<span class="symbol">]</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>

 <span class="keyword">public</span> T <span class="keyword">this</span><span class="symbol">[</span>Point location<span class="symbol">]</span>
 <span class="symbol">{</span>
 <span class="keyword">get</span> <span class="symbol">{</span> <span class="keyword">return</span> <span class="keyword">this</span><span class="symbol">[</span>location<span class="symbol">.</span>X<span class="symbol">,</span> location<span class="symbol">.</span>Y<span class="symbol">]</span><span class="symbol">;</span> <span class="symbol">}</span>
 <span class="keyword">set</span> <span class="symbol">{</span> <span class="keyword">this</span><span class="symbol">[</span>location<span class="symbol">.</span>X<span class="symbol">,</span> location<span class="symbol">.</span>Y<span class="symbol">]</span> <span class="symbol">=</span> value<span class="symbol">;</span> <span class="symbol">}</span>
 <span class="symbol">}</span>

 <span class="keyword">public</span> T <span class="keyword">this</span><span class="symbol">[</span><span class="keyword">int</span> x<span class="symbol">,</span> <span class="keyword">int</span> y<span class="symbol">]</span>
 <span class="symbol">{</span>
 <span class="keyword">get</span> <span class="symbol">{</span> <span class="keyword">return</span> <span class="keyword">this</span><span class="symbol">[</span><span class="keyword">this</span><span class="symbol">.</span>GetItemIndex<span class="symbol">(</span>x<span class="symbol">,</span> y<span class="symbol">)</span><span class="symbol">]</span><span class="symbol">;</span> <span class="symbol">}</span>
 <span class="keyword">set</span> <span class="symbol">{</span> <span class="keyword">this</span><span class="symbol">[</span><span class="keyword">this</span><span class="symbol">.</span>GetItemIndex<span class="symbol">(</span>x<span class="symbol">,</span> y<span class="symbol">)</span><span class="symbol">]</span> <span class="symbol">=</span> value<span class="symbol">;</span> <span class="symbol">}</span>
 <span class="symbol">}</span>

 <span class="keyword">public</span> T <span class="keyword">this</span><span class="symbol">[</span><span class="keyword">int</span> index<span class="symbol">]</span>
 <span class="symbol">{</span>
 <span class="keyword">get</span> <span class="symbol">{</span> <span class="keyword">return</span> _items<span class="symbol">[</span>index<span class="symbol">]</span><span class="symbol">;</span> <span class="symbol">}</span>
 <span class="keyword">set</span> <span class="symbol">{</span> _items<span class="symbol">[</span>index<span class="symbol">]</span> <span class="symbol">=</span> value<span class="symbol">;</span> <span class="symbol">}</span>
 <span class="symbol">}</span>

 IEnumerator IEnumerable<span class="symbol">.</span>GetEnumerator<span class="symbol">(</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">return</span> <span class="keyword">this</span><span class="symbol">.</span>GetEnumerator<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
<span class="symbol">}</span>
</pre>
</figure>
<p>Currently I'm using this class without any problems, but if you
spot any errors or think it could do with anything else, please
let me know!</p>
<h2 id="update-history">Update History</h2>
<ul>
<li>2012-04-11 - First published</li>
<li>2020-11-21 - Updated formatting</li>
</ul>

<p><small>
All content <a href="https://devblog.cyotek.com/copyright-and-trademarks">Copyright (c) by Cyotek Ltd</a> or its respective writers. Permission to reproduce news and web log entries and other RSS feed content in unmodified form without notice is granted provided they are not used to endorse or promote any products or opinions (other than what was expressed by the author) and without taking them out of context. Written permission from the copyright owner must be obtained for everything else.<br />Original URL of this content is https://devblog.cyotek.com/post/converting-2d-arrays-to-1d-and-accessing-as-either-2d-or-1d .
</small></p>Richard Mosshttps://www.cyotek.com/richard.moss@cyotek.com