-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#118 layouts with bitmask #121
base: main
Are you sure you want to change the base?
Changes from 4 commits
c49ce3f
2588180
a8d44a4
496f4f2
c9ca098
f616d96
2d5dd4d
8335a6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ contract RegenBingo is ERC721A, VRFV2WrapperConsumerBase { | |
//////////////////////////////////////////////////////////////*/ | ||
|
||
uint8 constant NUMBERS_COUNT = 90; | ||
uint256 constant LAYOUTS_COUNT = 3; | ||
uint256 constant LAYOUTS_COUNT = 10; | ||
uint256 constant ROWS_COUNT = 3; | ||
uint256 constant COLUMNS_COUNT = 9; | ||
uint32 constant VRF_CALLBACK_GAS_LIMIT = 100000; | ||
|
@@ -50,22 +50,18 @@ contract RegenBingo is ERC721A, VRFV2WrapperConsumerBase { | |
// lowest_available_number + (seed % possible_options) | ||
// Following these rules: https://en.wikipedia.org/wiki/Bingo_card#90-ball_bingo_cards | ||
// Using these as templates: https://www.scribd.com/document/325121782/1-90-British-Bingo-Cards | ||
uint8[2][COLUMNS_COUNT][ROWS_COUNT][LAYOUTS_COUNT] layouts = [ | ||
[ | ||
[[ 1, 9], [ 0, 0], [ 0, 0], [ 0, 0], [40, 5], [56, 4], [60,10], [77, 3], [ 0, 0]], | ||
[[ 0, 0], [ 0, 0], [ 0, 0], [30,10], [45, 5], [53, 3], [ 0, 0], [74, 3], [80, 6]], | ||
[[ 0, 0], [10,10], [20,10], [ 0, 0], [ 0, 0], [50, 3], [ 0, 0], [70, 4], [86, 5]] | ||
], | ||
[ | ||
[[ 6, 4], [10, 5], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [66, 4], [75, 5], [80,11]], | ||
[[ 0, 0], [ 0, 0], [25, 5], [30,10], [40,10], [50,10], [63, 3], [ 0, 0], [ 0, 0]], | ||
[[ 1, 5], [15, 5], [20, 5], [ 0, 0], [ 0, 0], [ 0, 0], [60, 3], [70, 5], [ 0, 0]] | ||
], | ||
[ | ||
[[ 1, 5], [ 0, 0], [25, 5], [ 0, 0], [ 0, 0], [50,10], [ 0, 0], [70, 5], [88, 3]], | ||
[[ 0, 0], [10,10], [20, 5], [30,10], [ 0, 0], [ 0, 0], [65, 5], [ 0, 0], [84, 4]], | ||
[[ 6, 4], [ 0, 0], [ 0, 0], [ 0, 0], [40,10], [ 0, 0], [60, 5], [75, 5], [80, 4]] | ||
] | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should not be any irrelevant comments in the code at any point. You better update them, but at the very least delete irrelevant comments. The comments above is irrelevant at this time. Since this is not a readable and understandable code, you must provide comments, at the very least add TODO comments. Please read the following source in full: https://stackoverflow.blog/2021/12/23/best-practices-for-writing-code-comments/
|
||
uint256[LAYOUTS_COUNT] public layouts = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no need for this to be public. Every public function adds bytecode deployment cost and pollutes the ABI. |
||
74531863127069656875678005463629317377624456585407760715211671503378212480908, | ||
84733770693983134393286414926143418191632064005497261285059935046721726341764, | ||
88892850850319190340242688960817664513518456655726863909825725454469825060928, | ||
85615516063282425514350087369392836674708439228389954229085207788303887704128, | ||
82025225875150254732266191914090518340421847287971611702527960659275601731648, | ||
81428084179800062446453646573230984879745244988152209000518516361294873969284, | ||
70657384472911031446975028864715540995046624405935865290481737135510018089024, | ||
96073477329873783590368928870704280664394527774970734350082854071566790058628, | ||
71254418773555781409572465841860736354607880829542776466442355105762863825540, | ||
81712411770574619635979783041230964642099925492660987369159605175257838198848 | ||
]; | ||
|
||
/*////////////////////////////////////////////////////////////// | ||
|
@@ -289,14 +285,18 @@ contract RegenBingo is ERC721A, VRFV2WrapperConsumerBase { | |
{ | ||
require(ownerOf(tokenId) != address(0), "Invalid card"); | ||
uint256 tokenSeed = _tokenSeed(tokenId); | ||
for (uint256 row = 0; row < ROWS_COUNT; row++) { | ||
for (uint256 column = 0; column < COLUMNS_COUNT; column++) { | ||
numberMatrix[row][column] = getNumberByCoordinates( | ||
tokenSeed, | ||
row, | ||
column | ||
); | ||
} | ||
uint256 layout = layouts[tokenSeed % LAYOUTS_COUNT]; | ||
|
||
for(uint256 i = 0; i < 15; i++) { | ||
uint256 row = layout % 4; // 2 bit | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "2 bits" etc. as they're plural. Make these comments more explanatory. |
||
layout /= 4; | ||
uint256 column = layout % 16; // 4 bit | ||
layout /= 16; | ||
uint256 floorNumber = layout % 128; // 7 bit | ||
layout /= 128; | ||
uint256 range = layout % 16; // 4 bit | ||
layout /= 16; | ||
numberMatrix[row][column] = uint8(floorNumber + tokenSeed % range); | ||
} | ||
} | ||
|
||
|
@@ -306,12 +306,13 @@ contract RegenBingo is ERC721A, VRFV2WrapperConsumerBase { | |
returns (bool[COLUMNS_COUNT][ROWS_COUNT] memory isDrawnMatrix) | ||
{ | ||
require(ownerOf(tokenId) != address(0), "Invalid card"); | ||
uint256 tokenSeed = _tokenSeed(tokenId); | ||
uint8[COLUMNS_COUNT][ROWS_COUNT] memory matrix = numberMatrix(tokenId); | ||
|
||
for (uint256 row = 0; row < ROWS_COUNT; row++) { | ||
for (uint256 column = 0; column < COLUMNS_COUNT; column++) { | ||
if ( | ||
isDrawn( | ||
getNumberByCoordinates(tokenSeed, row, column) | ||
matrix[row][column] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As this's shorter, inline the condition, please. |
||
) | ||
) { | ||
isDrawnMatrix[row][column] = true; | ||
|
@@ -336,19 +337,6 @@ contract RegenBingo is ERC721A, VRFV2WrapperConsumerBase { | |
} | ||
} | ||
|
||
function getNumberByCoordinates( | ||
uint256 tokenSeed, | ||
uint256 row, | ||
uint256 column | ||
) public view returns (uint8) { | ||
uint8[2][COLUMNS_COUNT][ROWS_COUNT] memory layout = layouts[tokenSeed % LAYOUTS_COUNT]; | ||
if (layout[row][column][0] == 0) { | ||
return 0; | ||
} else { | ||
return layout[row][column][0] + uint8(tokenSeed % layout[row][column][1]); | ||
} | ||
} | ||
|
||
function getDrawnNumbers() public view returns (uint8[] memory) { | ||
uint8[] memory drawnNumbers = new uint8[](drawnNumbersCount); | ||
for (uint8 i = 0; i < drawnNumbersCount; i++) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
import { BigNumber } from "ethers" | ||
import { keccak256, toUtf8Bytes } from "ethers/lib/utils" | ||
|
||
type Layout = number[][][] // 9 * 3 * 2 | ||
let nonce = 0 | ||
|
||
const generateNextRandom = (): number => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please give credit to the sources of codes, algorithms, and ideas you use. Not only here, but in general. |
||
nonce += 1 | ||
let a = nonce * 15485863 | ||
return (a * a * a % 2038074743) / 2038074743 | ||
} | ||
|
||
const isValidLayout = (layout : Layout) : Boolean => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Please rewrite it based on the following:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Followed this rules that are in the Regen Bingo Contract comments and checked for if any column has at least one number. |
||
|
||
let isValidRow = true | ||
let isValidColumn = true | ||
|
||
for(var i = 0; i < 9; i++) { | ||
let columnCount = 0 | ||
for(var j = 0; j < 3; j++) { | ||
if(layout && layout[i] && layout[i][j] && layout[i][j][0] && layout[i][j][0] != 0) { | ||
columnCount += 1 | ||
} | ||
} | ||
if(columnCount == 0) { | ||
isValidColumn = false | ||
} | ||
} | ||
|
||
for(var i = 0; i < 3; i++) { | ||
let rowCount = 0 | ||
for(var j = 0; j < 9; j++) { | ||
if(layout && layout[j] && layout[j][i] && layout[j][i][0] && layout[j][i][0] != 0) { | ||
rowCount += 1 | ||
} | ||
} | ||
if(rowCount != 5) { | ||
isValidRow = false | ||
} | ||
} | ||
|
||
return isValidColumn && isValidRow | ||
} | ||
|
||
|
||
const writeNumber = (number: Number): String => { | ||
if(number < 10) { | ||
return ' ' + String(number) | ||
} | ||
else { | ||
return String(number) | ||
} | ||
} | ||
|
||
|
||
function layoutWriter(layout: Layout){ | ||
console.log('[') | ||
for(var i = 0; i < 3; i++){ | ||
process.stdout.write(' [') | ||
for(var j = 0; j < 9; j++){ | ||
if(j < 8) { | ||
process.stdout.write('[' + writeNumber(layout[j][i][0]) + ',' + writeNumber(layout[j][i][1]) + '], ') | ||
} | ||
else { | ||
if(i < 2) { | ||
process.stdout.write('[' + writeNumber(layout[j][i][0]) + ',' + writeNumber(layout[j][i][1]) + ']],\n') | ||
} | ||
else { | ||
process.stdout.write('[' + writeNumber(layout[j][i][0]) + ',' + writeNumber(layout[j][i][1]) + ']]\n') | ||
} | ||
} | ||
} | ||
} | ||
console.log('],') | ||
} | ||
|
||
|
||
const generateLayout = (): Layout => { | ||
const layout = []; | ||
|
||
for(var i = 0; i < 9; i++) { | ||
const r = Math.floor(generateNextRandom() * 8) | ||
const rr = Math.floor(generateNextRandom() * 8) + 2; | ||
|
||
if (r == 0) { | ||
layout.push([[0, 0], [0, 0], [0, 0]]) | ||
} | ||
|
||
if (r == 1) { | ||
if (i == 0) { | ||
layout.push([[1, 9], [0, 0], [0, 0]]) | ||
} | ||
else { | ||
layout.push([[i * 10, 10 + Number(i == 8)], [0, 0], [0, 0]]) | ||
} | ||
} | ||
|
||
if (r == 2) { | ||
if (i == 0) { | ||
layout.push([[0, 0], [1, 9], [0, 0]]) | ||
} | ||
else { | ||
layout.push([[0, 0], [i * 10, 10 + Number(i == 8)], [0, 0]]) | ||
} | ||
} | ||
|
||
if (r == 3) { | ||
if (i == 0) { | ||
layout.push([[0, 0], [0, 0], [1, 9]]) | ||
} | ||
else { | ||
layout.push([[0, 0], [0, 0], [i * 10, 10 + Number(i == 8)]]) | ||
} | ||
} | ||
|
||
if (r == 4) { | ||
if (i == 0) { | ||
layout.push([[1, rr - 1], [rr, 10 - rr], [0, 0]]) | ||
} | ||
else { | ||
layout.push([[i * 10, rr], [i * 10 + rr, 10 - rr + Number(i == 8)], [0, 0]]) | ||
} | ||
} | ||
|
||
if (r == 5) { | ||
if (i == 0) { | ||
layout.push([[0, 0], [1, rr - 1], [rr, 10 - rr]]) | ||
} | ||
else { | ||
layout.push([[0, 0], [i * 10, rr ], [i * 10 + rr, 10 - rr + Number(i == 8)]]) | ||
} | ||
} | ||
|
||
if (r == 6) { | ||
if (i == 0) { | ||
layout.push([[1, rr - 1], [0, 0], [rr, 10 - rr]]) | ||
} | ||
else { | ||
layout.push([[i * 10, rr], [0, 0], [i * 10 + rr, 10 - rr + Number(i == 8)]]) | ||
} | ||
} | ||
|
||
if (r == 7) { | ||
if(i == 0) { | ||
layout.push([[1, 3], [4, 3], [7, 3]]) | ||
} | ||
else if(i == 8) { | ||
layout.push([[80, 4], [84, 4], [88, 3]]) | ||
} | ||
else { | ||
layout.push([[i * 10, 3], [i * 10 + 3, 3], [i * 10 + 6, 4]]) | ||
} | ||
} | ||
} | ||
return layout | ||
} | ||
|
||
const fixBitLength = (bits: String, len: number): String => { | ||
|
||
let fixedBits = bits.split('').reverse().join('') | ||
const numberOfZeroes = len - bits.length > 0 ? len - bits.length : 0 | ||
fixedBits += '0'.repeat(numberOfZeroes) | ||
return fixedBits | ||
} | ||
|
||
const generateBitsFromLayout = (layout: Layout): String => { | ||
let bits = '' | ||
|
||
for(var i = 0; i < 3; i++) { | ||
for(var j = 0; j < 9; j++) { | ||
if(layout && layout[j] && layout[j][i] && layout[j][i][0] && layout[j][i][0] != 0) { | ||
|
||
bits += fixBitLength(i.toString(2), 2) // first two bit is row number | ||
bits += fixBitLength(j.toString(2), 4) // four bit for column number | ||
bits += fixBitLength(layout[j][i][0].toString(2), 7) // seven bit for range start | ||
bits += fixBitLength(layout[j][i][1].toString(2), 4) // four bit for range | ||
|
||
} | ||
} | ||
} | ||
|
||
return bits.split('').reverse().join(''); | ||
} | ||
|
||
const generateBigNumberFromBits = (bits: String): BigNumber => { | ||
let number = BigNumber.from('1') // for leading zeroes | ||
|
||
for(var i = 0; i < bits.length; i++) { | ||
number = number.mul(2) | ||
if(bits[i] == '1') { | ||
number = number.add(1) | ||
} | ||
//console.log(bits[i] == '1') | ||
} | ||
|
||
return number | ||
} | ||
|
||
const generateCardFromLayout = (layout: BigNumber, tokenSeed: number): number[][] => { | ||
let card = [] | ||
for(var i = 0; i < 3; i++) { | ||
card.push([0,0,0,0,0,0,0,0,0]) | ||
} | ||
|
||
for(var i = 0; i < 15; i++) { | ||
const row = Number(layout.mod(4)) // 2 bit | ||
layout = layout.div(4) | ||
const column = Number(layout.mod(16)) // 4 bit | ||
layout = layout.div(16) | ||
const floorNumber = Number(layout.mod(128)) // 7 bit | ||
layout = layout.div(128) | ||
const range = Number(layout.mod(16)) // 4 bit | ||
layout = layout.div(16) | ||
card[row][column] = (floorNumber + tokenSeed % range) | ||
} | ||
|
||
return card | ||
} | ||
|
||
|
||
function main() { | ||
let counter = 0; | ||
const layouts: Array<Layout> = []; | ||
const bits: Array<String> = []; | ||
const numbers: Array<BigNumber> = []; | ||
console.log("Layouts: \n") | ||
|
||
while(counter < 10) { | ||
const layout: Layout = generateLayout() | ||
if(isValidLayout(layout) && !layouts?.includes(layout)) { | ||
layouts.push(layout) | ||
counter += 1 | ||
layoutWriter(layout) | ||
|
||
const bit: String = generateBitsFromLayout(layout) | ||
bits.push(bit) // first 17 character for last number (4 for range, 7 for range start, 4 for column, 2 for row) !reversed | ||
|
||
const layoutNumber: BigNumber = generateBigNumberFromBits(bit) | ||
numbers.push(layoutNumber) | ||
} | ||
} | ||
console.log("\nBinary forms of layouts: \n") | ||
|
||
bits.map((b) => { | ||
console.log(b, '\n') | ||
}) | ||
|
||
console.log("\nNumber forms of layouts: \n"); | ||
numbers.map((number) => { | ||
console.log(number.toString()) | ||
}) | ||
|
||
console.log('\nTest Card: \n', generateCardFromLayout(numbers[0], 128739456)) // layout, tokenSeed | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please print test cards for each layout. |
||
// console.log(Number(generateBigNumberFromBits("001"))) // expected 9 | ||
} | ||
|
||
main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this validate_layouts.
Read LAYOUTS_COUNT and layouts with hardhat-exposed. Compare the layouts with the hardhat script generated one. Lastly, print the layouts and example cards as I commented there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests for the layouts done in here