This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
KingofGamesYami's profile picture

Using bits to store data

Started by KingofGamesYami, 15 September 2014 - 02:08 PM
KingofGamesYami #1
Posted 15 September 2014 - 04:08 PM
1) CC has 16 colors
2) 4 binary characters produce 16 combinations
3) There are two active colors: Text and Background

Therefore, I should be able to store color data in a single byte. How would I do this, outside of writing to a file? Is it even possible?
theoriginalbit #2
Posted 15 September 2014 - 04:30 PM
Of course it is possible, and I have done this several times in the past for many purposes. The basics you must understand is that the Minecraft/ComputerCraft colours have 1 bit per colour as they're a 2x. Therefore using knowledge of math we know that a log2(x) will reverse this to get back to a number, in this case hopefully 0—15 unless we've been given an invalid colour (which you should check for btw). Lua doesn't have a built in log2 function, but it can be done like so

local function log2( num )
  return math.log( num ) / math.log( 2 )
end
once we have these two numbers we must combine them, the simplest way of doing this is by performing a bit shift of one of the colours, lets just pick the text colour, and then using a Bitwise OR to combine them.

local function byteFromColors( fg, bg )
  --# convert to 0-15 (the 4 low bits range)
  fg = log2( fg )
  bg = log2( bg )
  --# make one of the colours be in the 4 high bits range by shifting it left 4 places
  fg = bit.blshift( fg, 4 )
  --# combine the two colours with a bitwise OR
  return bit.bor( fg, bg )
end
in order to get the colours back from the byte we just do the inverse, we apply a Bitwise AND (bitmask) to the byte to extract each of the high and low bits, then apply them back to a colour with 2x.

local function colorsFromByte( byte )
  --# extract the 4 high bits from the byte
  local low = bit.band(b,15)
  --# extract the 4 low bits from the byte
  local high = bit.brshift(b,4)
  --# turn them back into the colours
  return 2^high, 2^low
end
to further understand the above code examples make sure to read up on Bitwise Operations, particularly OR and AND. And if you have any questions, feel free to ask.

EDIT: oh, I would like to just point out that it is possible to store (and read) anything you want within binary data. That is how the Note program is able to read the NBS file for MoarPeripherals (I had to write a LittleEndian to BigEndian converter for that). I have even written code to reduce file sizes of save files, take a look at PokeCC, I was able to reduce the save file size from 15KB to 838 bytes by simply 'compressing' the data into a byte.
Edited on 15 September 2014 - 02:36 PM
Lignum #3
Posted 15 September 2014 - 04:47 PM
Yes, this is possible with bit operations.

local function unify(bgColour, fgColour)
  local bg = math.log(bgColour)/math.log(2) --# Convert the powers of two to simpler numbers.
  local fg = math.log(fgColour)/math.log(2) --# I.e: 8192 -> 13

  --# OR combines the numbers. The left shift is used so that the numbers can be "merged".
  --# Example with blue (1011) and green (1101):
  --#
  --#   00001011
  --#   11010000		  <-- This is why we're shifting.
  --# OR
  --# ----------------
  --#   11011011
  --#
  --# The OR operator will take two bits and give you 1 if at least one of them is 1.

  local field = bit.bor(bg, bit.blshift(fg, 4))
  return field
end

local function extractColours(bitfield)
  --# Reverse the process...
  local bg = 2^(bit.band(bitfield, 0xF))
  local fg = 2^(bit.brshift(bitfield, 4))
  return bg, fg
end

local result = unify(colours.blue, colours.green)
print("Unified: ", result)

local bg, fg = extractColours(result)
print("BG: ", bg)
print("FG: ", fg)

EDIT: Ninja'd
Edited on 15 September 2014 - 02:47 PM