Hope doing well
I want to do the following activities in solidity code below but dont know how, please advise.
Thanks with regards
Syed
QUERY:_
Emit an event ScoreChanged with two arguments: int amount (equal to the value that was sent) and bool direction (true for up function and false for down)
Emit an event GameEnded after gameOver is switched to true
CODE:
pragma solidity ^0.4.17;
contract TugOfWar {
int public score = 0;
int constant endAt = 1 ether;
bool public gameOver = false;
function up() external payable {
require(msg.value > 0);
require(!gameOver);
int value = int(msg.value);
score += value;
checkIfGameOver();
}
function down() external payable {
require(msg.value > 0);
require(!gameOver);
int value = int(msg.value);
score -= value;
checkIfGameOver();
}
function checkIfGameOver() internal {
if(score >= endAt || score <= endAt * -1) {
gameOver = true;
}
}
}
You can define events in the contract by:
event ScoreChanged(uint amount, bool up);
event GameEnded(bool up); // where 'up' indicates which side won.
to emit the events you write:
emit ScoreChanged(msg.value, true); // where the second argument indicates the direction
you could to this right after you increment or decrement the score.
and when the game has ended:
emit GameEnded(true); // where the argument indicates which side has won.
Related
I want to generate 10000 random numbers by using chainlink VRF V2,but the max NUM_WORDS is 500 in one request,and it fails every time!
What should I do?
My account has enough LINK,but what I have done below does't work!
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "#chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "#chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
contract VRFCoordinatorTest is VRFConsumerBaseV2 {
// Chainlink VRF Variables
address vrfCoordinatorV2 = 0x6168499c0cFfCaCD319c818142124B7A15E857ab;
uint64 subscriptionId = 14422;
bytes32 gasLane = 0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc;
uint32 public callbackGasLimit = 2500000; //already max gaslimit
//network coordinator
VRFCoordinatorV2Interface private immutable _vrfCoordinator;
// The default is 3, but you can set this higher.
uint16 public REQUEST_CONFIRMATIONS = 10;
// retrieve NUM_WORDS random values in one request.
uint32 public NUM_WORDS = 500;
//keep the randomWords from fulfillRandomWords() function.
uint256[][] public _randomWords = new uint256[][](0);
//uint256[] public _randomWords;
event RequestedRandomWords(uint256 requestId ,address requester);
constructor() VRFConsumerBaseV2(vrfCoordinatorV2) {
_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
}
function fulfillRandomWords(uint256, uint256[] memory randomWords) internal override{
_randomWords.push(randomWords);
// _randomWords = randomWords;
}
function requestRandomWords()public{
uint256 requestId = _vrfCoordinator.requestRandomWords(
gasLane,
subscriptionId,
REQUEST_CONFIRMATIONS,
callbackGasLimit,
NUM_WORDS
);
emit RequestedRandomWords(requestId, msg.sender);
}
function set_REQUEST_CONFIRMATIONS(uint16 comf)public{
REQUEST_CONFIRMATIONS = comf;
}
function set_NUM_WORDS(uint32 num)public{
NUM_WORDS = num;
}
function set_gasLimit(uint32 gasl) public{
callbackGasLimit = gasl;
}
function getMaxLengthAndNum()public view returns(uint256,uint256){
uint256 lth = _randomWords.length;
uint256[] memory tmpArray = _randomWords[lth-1];
uint256 lastNum = tmpArray[tmpArray.length-1];
//uint256 maxNum = _randomWords[_randomWords.length-1];
return (lth,lastNum);
}
}
I see that you are testing on Rinkeby. I advise you to test on Goerli. Rinkeby is marked as deprecated (cf. https://docs.chain.link/docs/vrf/v2/supported-networks/).
I've tested your contract and remarked that fulfillRandomWords runs out of gas. In fact, The maximum number of random words that can be received per request is 500, and the maximum gas limit supported for your callback function is 2,500,000. Therefore, you must ensure that the callback function will not run out of gas (meaning: your callback function cannot consume more than 2,500,000 of gas).
In your example, you are trying to store 500 random words. Setting a value from non-zero to zero takes about 20,000 of gas (cf. Ethereum yellow paper Appendix H). With 2,500,000 of gas, you can store up to 125 words. And that’s why the attached contract will not work with NUM_WORDS=500 (fulfillRandomWords runs out of gas).
If you want to store 10001 random values, I’d suggest making multiple requests. For instance: inside requestRandomWords you can loop over
vrfCoordinator.requestRandomWords multiple times (e.g.: with NUM_WORDS=100 for 100 runs. and 1 for the last run).
Your callback function will be called multiple times (=number of requestIds) so make sure to implement a logic that waits for all the requests to be fulfilled (e.g., you can update a state variable s_requestsFulfilled
each time a request is fulfilled).
Here is an example that you can test on Goerli, I modified your example (Important remark: this is a non-audited code with hardcoded values. Do not use it as a reference for production code. Please test it/change it according to your needs)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "#chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "#chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
contract VRFCoordinatorTest_2 is VRFConsumerBaseV2 {
// Chainlink VRF Variables
address vrfCoordinatorV2 = 0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D;
uint64 subscriptionId = 443;
bytes32 gasLane = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;
uint32 public callbackGasLimit = 2500000; //already max gaslimit
uint256 public requestsFulfilled = 0; // count number of request fulfilled
//network coordinator
VRFCoordinatorV2Interface private immutable _vrfCoordinator;
// The default is 3, but you can set this higher.
uint16 public REQUEST_CONFIRMATIONS = 3;
//keep the randomWords from fulfillRandomWords() function.
struct RequestStatus {
bool fulfilled; // whether the request has been successfully fulfilled
bool exists; // whether a requestId exists
uint256[] randomWords;
}
mapping(uint256 => RequestStatus) public s_requests;
uint256[] public requestIds;
//uint256[] public _randomWords;
event ReceivedRandomWords(uint256 requestId ,uint256[] randomWords);
event RequestedRandomWords(uint256 requestId ,address requester);
event AllRequestsFulfilled();
constructor() VRFConsumerBaseV2(vrfCoordinatorV2) {
_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
}
function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override{
require(s_requests[_requestId].exists, 'request not found');
require(!s_requests[_requestId].fulfilled, 'request already fulfilled');
requestsFulfilled++;
s_requests[_requestId].fulfilled = true;
s_requests[_requestId].randomWords = _randomWords;
emit ReceivedRandomWords(_requestId,_randomWords);
if(requestsFulfilled==101){
emit AllRequestsFulfilled();
}
}
function requestRandomWords()public{
uint32 numWords = 100;
for(uint256 i=0;i<101;i++){
if(i==100){
numWords=1;
}
uint256 requestId = _vrfCoordinator.requestRandomWords(
gasLane,
subscriptionId,
REQUEST_CONFIRMATIONS,
callbackGasLimit,
numWords
);
s_requests[requestId]=RequestStatus({randomWords: new uint256[](0), exists: true, fulfilled: false});
requestIds.push(requestId);
emit RequestedRandomWords(requestId, msg.sender);
}
}
function getRequestStatus(uint256 requestId) external view returns (bool fulfilled, uint256[] memory randomWords) {
require(s_requests[requestId].exists, 'request not found');
RequestStatus memory request = s_requests[requestId];
return (request.fulfilled, request.randomWords);
}
function getRandomWordsAt(uint256 requestId,uint32 index) external view returns (uint256) {
require(s_requests[requestId].exists, 'request not found');
RequestStatus memory request = s_requests[requestId];
return request.randomWords[index];
}
function getRequestIdsLength() external view returns (uint256){
return requestIds.length;
}
function getRandomWords(uint256 requestId) external view returns (uint256[] memory){
require(s_requests[requestId].exists, 'request not found');
return s_requests[requestId].randomWords;
}
}
I am using code like this on a particle electron to report pulse counts from a flow meter on my kegerator to the particle cloud:
void meterInterrupt(void) {
detachInterrupt(pin);
ticks++;
cloudPending = 1;
attachInterrupt(pin, meterInterrupt, FALLING);
}
void publishStatus() {
if (!cloudPending) {
return;
}
cloudPending = 0;
getStatus(&statusMessage);
// status message contains number of ticks since last publish
bool published = Particle.publish("Ticks", statusMessage, PRIVATE);
if (published) {
resetMeters();
lastPublish = millis();
}
}
void loop() {
if ((millis() - lastPublish) >= 1000) {
publishStatus();
}
}
When I curl the event log into my terminal, I see two events for the first publish like so:
event: Ticks
data: {"data":"ticks:1","ttl":60,"published_at":"2018-07-03T22:35:01.008Z","coreid":"420052000351353337353037"}
event: hook-sent/Ticks
data: {"data":"","ttl":60,"published_at":"2018-07-03T22:35:01.130Z","coreid":"particle-internal"}
event: Ticks
data: {"data":"ticks:46","ttl":60,"published_at":"2018-07-03T22:35:01.193Z","coreid":"420052000351353337353037"}
event: hook-sent/Ticks
data: {"data":"","ttl":60,"published_at":"2018-07-03T22:35:01.303Z","coreid":"particle-internal"}
I don't see how this could happen. Why didn't it just report "ticks:47"? What am I missing?
UPDATE:
I did some further testing and noticed that Particle.publish is returning false the first time when it is actually completing successfully. Is this a timeout issue? The time difference between these publishes is only about 200ms.
OK, This is at least a partial answer.
It appears that Particle.publish is asynchronous. It returns the promise of an answer that starts out as false only eventually becomes true when/if the action is actually completed. If I wait an indeterminate amount of time (say delay(10)) after Particle.publish and before checking the return code, the return value will indicate the actual success or failure of the publish. My code cannot work because the ticks that are counted while I wait will be deleted when I reset the meters. WITH_ACK gives me the same behavior.
I will have to modify my code such that no ticks are lost during the long running Particle.publish . I am thinking that each statusMessage should go onto a list until it is ack'ed by the server.
FINAL ANSWER:
I modified the code to close the window during which I can receive ticks that will then be wiped out when I reset the counters. I do this by capturing the ticks into an array and then resetting the tick counter (meter). I am using a library called PublishQueueAsyncRK (cudos to rickkas7 This library is great!) so I can just fire it and forget it. Check it out on github.
void publishStatus() {
unsigned int counters[NUM_METERS];
unsigned int pending;
for (int i = 0; i < NUM_METERS; i++) {
meter_t *meter = &meters[i];
counters[i] = meter->ticks;
pending += counters[i];
resetMeter(i);
}
if (pending) {
String statusReport;
for (int i = 0; i < NUM_METERS; i++) {
statusReport.concat(String::format("%i:%u|", i+1, counters[i]));
}
publishReport(statusReport);
lastPublished = millis();
}
}
void publishReport(String report) {
if (report != "") {
publishQueue.publish("PourLittleTicks", report, PRIVATE);
}
}
void loop() {
if ((millis() - lastPublished) >= PUBLISH_INTERVAL) {
publishStatus();
}
}
I have a function (lets call it function A) that 0 to many threads can access it (at the same time, no shared resources). At any given time, the user can use to stop the process. The stop functionality needs to make sure that there are threads accessing function A, so that a graceful shutdown can be performed. Is there a native procedure to do so?
What I was going to do is have an InterlockedIncrement an integer everytime function A is called (and a corresponding InterlockedDecrement on said integer when function A exists). When an InterlockedDecrement takes place, it checks the value of the integer, if it's set to zero, a event is set to signalled. If the value is not zero, the event is set to nonsignalled.
This makes sense in my mind, but I'm curious whether there is a more native structure / functionality adapted to do so.
I still have to thing about the fact the "stop" function may get starved (in the sense, the said integer may never be set to zero). A sidenote: when the stop event takes place, the InterlockedIncrement process shall be stopped, to reduce said starvation.
what you need and want implement is called Run-Down Protection. unfortunately it supported only in kernel mode, but not hard implement it yourself in user mode too.
the simplest implementation is next:
HANDLE ghStopEvent;
LONG gLockCount = 1;
BOOLEAN bStop = FALSE;
void unlock()
{
if (!InterlockedDecrement(&gLockCount)) SetEvent(ghStopEvent);
}
BOOL lock()
{
LONG Value = gLockCount, NewValue;
for ( ; !bStop && Value; Value = NewValue)
{
NewValue = InterlockedCompareExchange(&gLockCount, Value + 1, Value);
if (NewValue == Value) return TRUE;
}
return FALSE;
}
void funcA();
void UseA()
{
if (lock())
{
funcA();
unlock();
}
}
and when you want begin rundown - once call
bStop = TRUE; unlock();
how you can see lock function is interlocked increment gLockCount on 1 but only if it not 0.
in kernel mode you can call instead
EX_RUNDOWN_REF gRunRef;
void UseA()
{
if (ExAcquireRundownProtection(&gRunRef))
{
funcA();
ExReleaseRundownProtection(&gRunRef)
}
}
and on place final unlock - ExWaitForRundownProtectionRelease
some more complex and scalable implementation of rundown-protection:
#define RUNDOWN_INIT_VALUE 0x80000000
#define RUNDOWN_COMPLETE_VALUE 0
class __declspec(novtable) RUNDOWN_REF
{
LONG _LockCount;
protected:
virtual void RundownCompleted() = 0;
public:
BOOL IsRundownBegin()
{
return 0 <= _LockCount;
}
void Reinit()
{
if (InterlockedCompareExchange(&_LockCount, RUNDOWN_INIT_VALUE, RUNDOWN_COMPLETE_VALUE) != RUNDOWN_COMPLETE_VALUE)
{
__debugbreak();
}
}
RUNDOWN_REF()
{
_LockCount = RUNDOWN_INIT_VALUE;
}
BOOL AcquireRundownProtection()
{
LONG Value = _LockCount, NewValue;
for ( ; Value < 0; Value = NewValue)
{
NewValue = InterlockedCompareExchange(&_LockCount, Value + 1, Value);
if (NewValue == Value) return TRUE;
}
return FALSE;
}
void ReleaseRundownProtection()
{
if (RUNDOWN_COMPLETE_VALUE == InterlockedDecrement(&_LockCount))
{
RundownCompleted();
}
}
void BeginRundown()
{
if (AcquireRundownProtection())
{
_interlockedbittestandreset(&_LockCount, 31);
ReleaseRundownProtection();
}
}
};
and use it like:
class MY_RUNDOWN_REF : public RUNDOWN_REF
{
HANDLE _hEvent;
virtual void RundownCompleted()
{
SetEvent(_hEvent);
}
// ...
} gRunRef;
void UseA()
{
if (gRunRef.AcquireRundownProtection())
{
funcA();
gRunRef.ReleaseRundownProtection();
}
}
and when you want stop:
gRunRef.BeginRundown();// can be safe called multiple times
// wait on gRunRef._hEvent here
interesting that in kernel exist else one (more old - from win2000, when rundown protection from xp) api Remove Locks. it do almost the same. different only in internal implementation and usage. with remove locks code will be look like this:
IO_REMOVE_LOCK gLock;
void UseA()
{
if (0 <= IoAcquireRemoveLock(&gLock, 0))
{
funcA();
IoReleaseRemoveLock(&gLock, 0);
}
}
and when we want stop - call
IoAcquireRemoveLock(&gLock, 0);
IoReleaseRemoveLockAndWait(&gLock, 0);
my first code spinet by implementation near remove locks implementation, when second near rundown-protection implementation. but by sense both do the same
I'm trying to build a ping pong game with Processing language. For this two-player game I have two controllers at each end of the 'table'. I coded the movements of the players (up and down) by binding them to the keys:
- w and s for player 1
- o and l for player 2
Although this works when I press them one at a time, I cannot figure out how to make them move simultaneously, as in pressing both w and o at the same time.
Here is my code:
int x=535;
int y=350;
int dx=5;
int dy=5;
int pX=10;
int pY=520;
int pX1=1870;
int pY1=520;
int pS=5;
void setup() {
size(1920,1080);
}
void draw() {
background(0);
rect(960,0,5,1080);
rect(pX,pY,40,150);
rect(pX1,pY1,40,150);
ellipse(x,y,50,50);
x=x+dx;
y=y+dy;
bounce();
move();
move1();
}
void bounce(){
if(x>=1920 || x<=0){
dx=-dx;
}
if(y>1080 || y<0){
dy=-dy;
}
}
void move(){
if(keyPressed){
if(key == 's'){
pY+=pS;
}else if (key == 'w'){
pY-=pS;
}
}
}
void move1() {
if(keyPressed){
if(key == 'l'){
pY1+=pS;
}else if (key == 'o'){
pY1-=pS;
}
}
}
What you want to do is create a boolean value for each key you care about. Then in the keyPressed() function, you set the corresponding variable to true, and in the keyReleased() function, you set the corresponding variable to false. Then in your draw() function, you check the variables to determine which keys are pressed.
Shameless self-promotion: I wrote a tutorial on getting user input available here. Check out the Handling Multiple Keys section.
I would like to know how can I detect the press of a key or release of a key in a while loop in SDL. Now, I know you can get the events with SDL like OnKeyPressed, OnKeyReleased, OnKeyHit, etc, but I want to know how to build functions like 'KeyPressed' that returns a boolean, instead of being an event. Example:
while not KeyHit( KEY_ESC )
{
//Code here
}
I know you have already selected an answer.. but here is some actual code of how I typically do it with one array. :)
first define this somewhere.
bool KEYS[322]; // 322 is the number of SDLK_DOWN events
for(int i = 0; i < 322; i++) { // init them all to false
KEYS[i] = false;
}
SDL_EnableKeyRepeat(0,0); // you can configure this how you want, but it makes it nice for when you want to register a key continuously being held down
Then later, create a keyboard() function which will register keyboard input
void keyboard() {
// message processing loop
SDL_Event event;
while (SDL_PollEvent(&event)) {
// check for messages
switch (event.type) {
// exit if the window is closed
case SDL_QUIT:
game_state = 0; // set game state to done,(do what you want here)
break;
// check for keypresses
case SDL_KEYDOWN:
KEYS[event.key.keysym.sym] = true;
break;
case SDL_KEYUP:
KEYS[event.key.keysym.sym] = false;
break;
default:
break;
}
} // end of message processing
}
Then when you actually want to use the keyboard input i.e. a handleInput() function, it may look something like this:
void handleInput() {
if(KEYS[SDLK_LEFT]) { // move left
if(player->x - player->speed >= 0) {
player->x -= player->speed;
}
}
if(KEYS[SDLK_RIGHT]) { // move right
if(player->x + player->speed <= screen->w) {
player->x += player->speed;
}
}
if(KEYS[SDLK_UP]) { // move up
if(player->y - player->speed >= 0) {
player->y -= player->speed;
}
}
if(KEYS[SDLK_DOWN]) { // move down
if(player->y + player->speed <= screen->h) {
player->y += player->speed;
}
}
if(KEYS[SDLK_s]) { // shoot
if(SDL_GetTicks() - player->lastShot > player->shotDelay) {
shootbeam(player->beam);
}
}
if(KEYS[SDLK_q]) {
if(player->beam == PLAYER_BEAM_CHARGE) {
player->beam = PLAYER_BEAM_NORMAL;
} else {
player->beam = PLAYER_BEAM_CHARGE;
}
}
if(KEYS[SDLK_r]) {
reset();
}
if(KEYS[SDLK_ESCAPE]) {
gamestate = 0;
}
}
And of course you can easily do what you're wanting to do
while(KEYS[SDLK_s]) {
// do something
keyboard(); // don't forget to redetect which keys are being pressed!
}
**Updated version on my website: **
For the sake of not posting a lot of source code, you can view a complete SDL Keyboard class in C++ that supports
Single Key Input
Simultaneous Key Combos (Keys all pressed in any order)
Sequential Key Combonations (Keys all pressed in specific order)
http://kennycason.com/posts/2009-09-20-sdl-simple-space-shooter-game-demo-part-i.html (if you have any problems, let me know)
There is an SDL function for this: SDL_GetKeyboardState
Example to check whether left or right CTRL key is pressed:
const Uint8* state = SDL_GetKeyboardState(nullptr);
if (state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL]) {
std::cerr << "ctrl pressed" << std::endl;
}
I had this problem in LuaJIT with FFI, this is how I solved it:
Global:
KEYS = {}
Event code:
ev = ffi.new("SDL_Event[1]")
function event()
while sdl.SDL_PollEvent(ev) ~= 0 do
local e = ev[0]
local etype = e.type
if etype == sdl.SDL_QUIT then
return false -- quit
-- os.exit() -- prevents interactive mode
elseif etype == sdl.SDL_KEYDOWN then
if e.key.keysym.sym == sdl.SDLK_ESCAPE then
return false -- quit
-- os.exit()
end
print("Pressed: ", e.key.keysym.scancode, "\n")
KEYS[tonumber(e.key.keysym.sym)] = true
-- print("Pressed: ", (e.key.keysym.sym == sdl.SDLK_w), "\n");
elseif etype == sdl.SDL_KEYUP then
KEYS[tonumber(e.key.keysym.sym)] = false
elseif etype == sdl.SDL_VIDEORESIZE then
-- print("video resize W:".. e.resize.w .. " H:" .. e.resize.h)
width = e.resize.w
height = e.resize.h
onResize()
end
end
return true -- everything ok
end
Update function:
if KEYS[sdl.SDLK_w] == true then
rot = rot + 1
end
Most time i wasted on this:
KEYS[tonumber(e.key.keysym.sym)] = false
Because FFI is returning a CData object, which was used as the array-key, but it needs the integer.
You should have 2 tables of booleans for keys. One table, in which you set keys true or false based on the SDL keydown/keyup events, and another one, that you initialize with false. When checking keyPressed, you just compare the second table key with the first table key, and if different, if second table key is false, then it was pressed, else it was released. After that, you do secondTable[key] := not secondTable[key]. Works!